diff --git a/plugins/woocommerce-admin/client/header/utils.js b/plugins/woocommerce-admin/client/header/utils.tsx
similarity index 61%
rename from plugins/woocommerce-admin/client/header/utils.js
rename to plugins/woocommerce-admin/client/header/utils.tsx
index 10d2bae283c..96a368d1e4b 100644
--- a/plugins/woocommerce-admin/client/header/utils.js
+++ b/plugins/woocommerce-admin/client/header/utils.tsx
@@ -1,6 +1,7 @@
/**
* External dependencies
*/
+import { isValidElement } from 'react';
import { Slot, Fill } from '@wordpress/components';
import { cloneElement } from '@wordpress/element';
@@ -12,10 +13,34 @@ import { cloneElement } from '@wordpress/element';
* @param {Array} props - Fill props.
* @return {Node} Node.
*/
-const createOrderedChildren = ( children, order, props ) => {
- return typeof children === 'function'
- ? cloneElement( children( props ), { order } )
- : cloneElement( children, { ...props, order } );
+const createOrderedChildren = (
+ children: React.ReactNode,
+ order: number,
+ props: Fill.Props
+) => {
+ if ( typeof children === 'function' ) {
+ return cloneElement( children( props ), { order } );
+ } else if ( isValidElement( children ) ) {
+ return cloneElement( children, { ...props, order } );
+ }
+ throw Error( 'Invalid children type' );
+};
+
+/**
+ * Sort fills by order for slot children.
+ *
+ * @param {Array} fills - slot's `Fill`s.
+ * @return {Node} Node.
+ */
+const sortFillsByOrder: Slot.Props[ 'children' ] = ( fills ) => {
+ // Copy fills array here because its type is readonly array that doesn't have .sort method in Typescript definition.
+ const sortedFills = [ ...fills ].sort( ( a, b ) => {
+ return a[ 0 ].props.order - b[ 0 ].props.order;
+ } );
+ if ( isValidElement( sortedFills ) ) {
+ return sortedFills;
+ }
+ return null;
};
/**
@@ -36,10 +61,12 @@ const createOrderedChildren = ( children, order, props ) => {
* @param {Array} param0.children - Node children.
* @param {Array} param0.order - Node order.
*/
-export const WooHeaderItem = ( { children, order = 1 } ) => {
+export const WooHeaderItem: React.FC< { order?: number } > & {
+ Slot: React.FC< Slot.Props >;
+} = ( { children, order = 1 } ) => {
return (
- { ( fillProps ) => {
+ { ( fillProps: Fill.Props ) => {
return createOrderedChildren( children, order, fillProps );
} }
@@ -48,11 +75,7 @@ export const WooHeaderItem = ( { children, order = 1 } ) => {
WooHeaderItem.Slot = ( { fillProps } ) => (
- { ( fills ) => {
- return fills.sort( ( a, b ) => {
- return a[ 0 ].props.order - b[ 0 ].props.order;
- } );
- } }
+ { sortFillsByOrder }
);
@@ -75,23 +98,21 @@ WooHeaderItem.Slot = ( { fillProps } ) => (
* @param {Array} param0.children - Node children.
* @param {Array} param0.order - Node order.
*/
-export const WooHeaderNavigationItem = ( { children, order = 1 } ) => {
+export const WooHeaderNavigationItem: React.FC< { order?: number } > & {
+ Slot: React.FC< Slot.Props >;
+} = ( { children, order = 1 } ) => {
return (
- { ( fillProps ) => {
+ { ( fillProps: Fill.Props ) => {
return createOrderedChildren( children, order, fillProps );
} }
);
};
-WooHeaderNavigationItem.Slot = ( { fillProps } ) => (
+WooHeaderNavigationItem.Slot = ( { fillProps }: Slot.Props ) => (
- { ( fills ) => {
- return fills.sort( ( a, b ) => {
- return a[ 0 ].props.order - b[ 0 ].props.order;
- } );
- } }
+ { sortFillsByOrder }
);
@@ -112,15 +133,20 @@ WooHeaderNavigationItem.Slot = ( { fillProps } ) => (
* @param {Object} param0
* @param {Array} param0.children - Node children.
*/
-export const WooHeaderPageTitle = ( { children } ) => {
+export const WooHeaderPageTitle: React.FC & {
+ Slot: React.FC< Slot.Props >;
+} = ( { children } ) => {
return { children };
};
WooHeaderPageTitle.Slot = ( { fillProps } ) => (
{ ( fills ) => {
- const last = fills.pop();
- return [ last ];
+ const last = [ [ ...fills ].pop() ];
+ if ( isValidElement( last ) ) {
+ return last;
+ }
+ return null;
} }
);