Update product editor package (#36830)

* Add missing dev packages to product-editor package

* Create components folder for organization

* Move product field, section and tab slots over to product-editor package

* Move use of product slot fills to product-editor package

* Sync dependencies

* Add changelogs

* Update README's and add constant for default values

* Update README's in product-editor package
This commit is contained in:
louwie17 2023-02-24 09:37:53 -04:00 committed by GitHub
parent 2ef4f8a9da
commit aec4dfd3bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 1992 additions and 1410 deletions

View File

@ -0,0 +1,4 @@
Significance: minor
Type: update
Add deprecated message to product slot fill components

View File

@ -26,17 +26,17 @@ A Slotfill component that will allow you to add a new field to a specific sectio
This is the fill component. You must provide the `id` prop to identify your product field fill with a unique string. This component will accept a series of props:
| Prop | Type | Description |
| -------------| -------- | ------------------------------------------------------------------------------------------------------------------------ |
| `id` | String | A unique string to identify your fill. Used for configuiration management. |
| `section ` | String | The string used to identify the particular section where you want to render your field. |
| `pluginId` | String | A unique plugin ID to identify the plugin/extension that this fill is associated with. |
| `order` | Number | (optional) This number will dictate the order that the fields rendered by a Slot will be appear. |
| Prop | Type | Description |
| ---------- | ------ | ------------------------------------------------------------------------------------------------ |
| `id` | String | A unique string to identify your fill. Used for configuration management. |
| `sections` | Array | Contains an array of name and order values for which slots it should be rendered in. |
| `pluginId` | String | A unique plugin ID to identify the plugin/extension that this fill is associated with. |
| `order` | Number | (optional) This number will dictate the order that the fields rendered by a Slot will be appear. |
### WooProductFieldItem.Slot (slot)
This is the slot component, and will not be used as frequently. It must also receive the required `location` prop that will be identical to the fill `location`.
This is the slot component. This will render all the registered fills that match the `section` prop.
| Name | Type | Description |
| ----------- | ------ | ---------------------------------------------------------------------------------------------------- |
| `section` | String | Unique to the section that the Slot appears, and must be the same as the one provided to any fills. |
| Name | Type | Description |
| --------- | ------ | --------------------------------------------------------------------------------------------------- |
| `section` | String | Unique to the section that the Slot appears, and must be the same as the one provided to any fills. |

View File

@ -4,6 +4,7 @@
import React, { useEffect } from 'react';
import { Slot, Fill } from '@wordpress/components';
import { createElement, Children, Fragment } from '@wordpress/element';
import deprecated from '@wordpress/deprecated';
/**
* Internal dependencies
@ -29,6 +30,8 @@ type WooProductFieldFillProps = {
children?: React.ReactNode;
};
const DEFAULT_FIELD_ORDER = 20;
const WooProductFieldFill: React.FC< WooProductFieldFillProps > = ( {
fieldName,
sectionName,
@ -39,6 +42,12 @@ const WooProductFieldFill: React.FC< WooProductFieldFillProps > = ( {
const fieldId = `product_field/${ sectionName }/${ fieldName }`;
deprecated( `__experimentalWooProductFieldItem`, {
version: '13.0.0',
plugin: '@woocommerce/components',
hint: 'Moved to @woocommerce/product-editor package: import { __experimentalWooProductFieldItem } from @woocommerce/product-editor',
} );
useEffect( () => {
registerFill( fieldId );
}, [] );
@ -75,16 +84,18 @@ export const WooProductFieldItem: React.FC< WooProductFieldItemProps > & {
} = ( { children, sections, id } ) => {
return (
<>
{ sections.map( ( { name: sectionName, order = 20 } ) => (
<WooProductFieldFill
fieldName={ id }
sectionName={ sectionName }
order={ order }
key={ sectionName }
>
{ children }
</WooProductFieldFill>
) ) }
{ sections.map(
( { name: sectionName, order = DEFAULT_FIELD_ORDER } ) => (
<WooProductFieldFill
fieldName={ id }
sectionName={ sectionName }
order={ order }
key={ sectionName }
>
{ children }
</WooProductFieldFill>
)
) }
</>
);
};

View File

@ -30,17 +30,17 @@ A Slotfill component that will allow you to add a new section to the product edi
This is the fill component. You must provide the `id` prop to identify your section fill with a unique string. This component will accept a series of props:
| Prop | Type | Description |
| -------------| -------- | ------------------------------------------------------------------------------------------------------------------------ |
| `id` | String | A unique string to identify your fill. Used for configuiration management. |
| `location` | String | The string used to identify the particular location that you want to render your section. |
| `pluginId` | String | A unique plugin ID to identify the plugin/extension that this fill is associated with. |
| `order` | Number | (optional) This number will dictate the order that the sections rendered by a Slot will be appear. |
| Prop | Type | Description |
| ---------- | ------ | -------------------------------------------------------------------------------------------------- |
| `id` | String | A unique string to identify your fill. Used for configuiration management. |
| `tabs` | Array | Contains an array of name and order of which slots it should be rendered in. |
| `pluginId` | String | A unique plugin ID to identify the plugin/extension that this fill is associated with. |
| `order` | Number | (optional) This number will dictate the order that the sections rendered by a Slot will be appear. |
### WooProductSectionItem.Slot (slot)
This is the slot component, and will not be used as frequently. It must also receive the required `location` prop that will be identical to the fill `location`.
This is the slot component. This will render all the registered fills that match the `tab` prop.
| Name | Type | Description |
| ----------- | ------ | ---------------------------------------------------------------------------------------------------- |
| `location` | String | Unique to the location that the Slot appears, and must be the same as the one provided to any fills. |
| Name | Type | Description |
| ----- | ------ | ---------------------------------------------------------------------------------------------------- |
| `tab` | String | Unique to the location that the Slot appears, and must be the same as the one provided to any fills. |

View File

@ -4,6 +4,7 @@
import React from 'react';
import { Slot, Fill } from '@wordpress/components';
import { createElement, Fragment } from '@wordpress/element';
import deprecated from '@wordpress/deprecated';
/**
* Internal dependencies
@ -21,12 +22,20 @@ type WooProductSectionSlotProps = {
tab: string;
};
const DEFAULT_SECTION_ORDER = 20;
export const WooProductSectionItem: React.FC< WooProductSectionItemProps > & {
Slot: React.FC< Slot.Props & WooProductSectionSlotProps >;
} = ( { children, tabs } ) => {
deprecated( `__experimentalWooProductSectionItem`, {
version: '13.0.0',
plugin: '@woocommerce/components',
hint: 'Moved to @woocommerce/product-editor package: import { __experimentalWooProductSectionItem } from @woocommerce/product-editor',
} );
return (
<>
{ tabs.map( ( { name: tabName, order: tabOrder } ) => (
{ tabs.map( ( { name: tabName, order: sectionOrder } ) => (
<Fill
name={ `woocommerce_product_section_${ tabName }` }
key={ tabName }
@ -34,7 +43,7 @@ export const WooProductSectionItem: React.FC< WooProductSectionItemProps > & {
{ ( fillProps: Fill.Props ) => {
return createOrderedChildren<
Fill.Props & { tabName: string }
>( children, tabOrder || 20, {
>( children, sectionOrder || DEFAULT_SECTION_ORDER, {
tabName,
...fillProps,
} );

View File

@ -18,18 +18,18 @@ A Slotfill component that will allow you to add a new tab to the product editor.
This is the fill component. You must provide the `id` prop to identify your section fill with a unique string. This component will accept a series of props:
| Prop | Type | Description |
| ---------- | ------ | -------------------------------------------------------------------------------------------------------------- |
| `id` | String | A unique string to identify your fill. Used for configuiration management. |
| `location` | String | The string used to identify the particular location that you want to render your section. |
| `pluginId` | String | A unique plugin ID to identify the plugin/extension that this fill is associated with. |
| `tabProps` | Object | An object containing tab props: name, title, className, disabled (see TabPanel.Tab from @wordpress/components) |
| `order` | Number | (optional) This number will dictate the order that the sections rendered by a Slot will be appear. |
| Prop | Type | Description |
| ----------- | ------ | -------------------------------------------------------------------------------------------------------------- |
| `id` | String | A unique string to identify your fill. Used for configuiration management. |
| `templates` | Array | Array of name and order of which template slots it should be rendered in |
| `pluginId` | String | A unique plugin ID to identify the plugin/extension that this fill is associated with. |
| `tabProps` | Object | An object containing tab props: name, title, className, disabled (see TabPanel.Tab from @wordpress/components) |
| `order` | Number | (optional) This number will dictate the order that the sections rendered by a Slot will be appear. |
### WooProductTabItem.Slot (slot)
This is the slot component, and will not be used as frequently. It must also receive the required `location` prop that will be identical to the fill `location`.
This is the slot component. This will render all the registered fills that match the `template` prop.
| Name | Type | Description |
| ---------- | ------ | ---------------------------------------------------------------------------------------------------- |
| `location` | String | Unique to the location that the Slot appears, and must be the same as the one provided to any fills. |
| `template` | String | Unique to the location that the Slot appears, and must be the same as the one provided to any fills. |

View File

@ -4,6 +4,7 @@
import React, { ReactElement, ReactNode } from 'react';
import { Slot, Fill, TabPanel } from '@wordpress/components';
import { createElement, Fragment } from '@wordpress/element';
import deprecated from '@wordpress/deprecated';
/**
* Internal dependencies
@ -30,11 +31,19 @@ type WooProductFieldSlotProps = {
) => ReactElement | null;
};
const DEFAULT_TAB_ORDER = 20;
export const WooProductTabItem: React.FC< WooProductTabItemProps > & {
Slot: React.VFC<
Omit< Slot.Props, 'children' > & WooProductFieldSlotProps
>;
} = ( { children, tabProps, templates } ) => {
deprecated( `__experimentalWooProductTabItem`, {
version: '13.0.0',
plugin: '@woocommerce/components',
hint: 'Moved to @woocommerce/product-editor package: import { __experimentalWooProductTabItem } from @woocommerce/product-editor',
} );
if ( ! templates ) {
// eslint-disable-next-line no-console
console.warn( 'WooProductTabItem fill is missing templates property.' );
@ -50,12 +59,12 @@ export const WooProductTabItem: React.FC< WooProductTabItemProps > & {
{ ( fillProps: Fill.Props ) => {
return createOrderedChildren< Fill.Props >(
children,
templateData.order || 20,
templateData.order || DEFAULT_TAB_ORDER,
{},
{
tabProps,
templateName: templateData.name,
order: templateData.order || 20,
order: templateData.order || DEFAULT_TAB_ORDER,
...fillProps,
}
);
@ -84,7 +93,7 @@ WooProductTabItem.Slot = ( { fillProps, template, children } ) => (
: props.tabProps;
tabs.push( {
...tabProps,
order: props.order ?? 20,
order: props.order ?? DEFAULT_TAB_ORDER,
} );
}
return {

View File

@ -0,0 +1,4 @@
Significance: minor
Type: add
Copy over the product slot fill components from @woocommerce/components

View File

@ -42,12 +42,15 @@
"@woocommerce/eslint-plugin": "workspace:*",
"@woocommerce/internal-style-build": "workspace:*",
"@wordpress/browserslist-config": "^4.1.1",
"concurrently": "^7.0.0",
"css-loader": "^3.6.0",
"eslint": "^8.32.0",
"jest": "^27.5.1",
"jest-cli": "^27.5.1",
"postcss-loader": "^3.0.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"rimraf": "^3.0.2",
"sass-loader": "^10.2.1",
"ts-jest": "^27.1.3",
"typescript": "^4.8.3",

View File

@ -0,0 +1,7 @@
export {
ProductSectionLayout as __experimentalProductSectionLayout,
ProductFieldSection as __experimentalProductFieldSection,
} from './product-section-layout';
export { WooProductFieldItem as __experimentalWooProductFieldItem } from './woo-product-field-item';
export { WooProductSectionItem as __experimentalWooProductSectionItem } from './woo-product-section-item';
export { WooProductTabItem as __experimentalWooProductTabItem } from './woo-product-tab-item';

View File

@ -0,0 +1,42 @@
# WooProductFieldItem Slot & Fill
A Slotfill component that will allow you to add a new field to a specific section in the product editor.
## Usage
```jsx
<WooProductFieldItem id={ key } section="details" order={ 2 } pluginId="test-plugin" >
{ () => {
return (
<TextControl
label="Name"
name={ `product-mvp-name` }
placeholder="e.g. 12 oz Coffee Mug"
value="Test Name"
onChange={ () => console.debug( 'Changed!' ) }
/>
);
} }
</WooProductFieldItem>
<WooProductFieldItem.Slot section="details" />
```
### WooProductFieldItem (fill)
This is the fill component. You must provide the `id` prop to identify your product field fill with a unique string. This component will accept a series of props:
| Prop | Type | Description |
| ---------- | ------ | ------------------------------------------------------------------------------------------------ |
| `id` | String | A unique string to identify your fill. Used for configuration management. |
| `sections` | Array | Contains an array of name and order values for which slots it should be rendered in. |
| `pluginId` | String | A unique plugin ID to identify the plugin/extension that this fill is associated with. |
| `order` | Number | (optional) This number will dictate the order that the fields rendered by a Slot will be appear. |
### WooProductFieldItem.Slot (slot)
This is the slot component. This will render all the registered fills that match the `section` prop.
| Name | Type | Description |
| --------- | ------ | --------------------------------------------------------------------------------------------------- |
| `section` | String | Unique to the section that the Slot appears, and must be the same as the one provided to any fills. |

View File

@ -0,0 +1 @@
export * from './woo-product-field-item';

View File

@ -0,0 +1,130 @@
/**
* External dependencies
*/
import { ReactNode } from 'react';
import { Slot, Fill } from '@wordpress/components';
import {
createElement,
Children,
Fragment,
useEffect,
} from '@wordpress/element';
import {
useSlotContext,
SlotContextHelpersType,
} from '@woocommerce/components';
/**
* Internal dependencies
*/
import { createOrderedChildren, sortFillsByOrder } from '../../utils';
import { ProductFillLocationType } from '../woo-product-tab-item';
type WooProductFieldItemProps = {
id: string;
sections: ProductFillLocationType[];
pluginId: string;
};
type WooProductFieldSlotProps = {
section: string;
};
type WooProductFieldFillProps = {
fieldName: string;
sectionName: string;
order: number;
children?: ReactNode;
};
const DEFAULT_FIELD_ORDER = 20;
const WooProductFieldFill: React.FC< WooProductFieldFillProps > = ( {
fieldName,
sectionName,
order,
children,
} ) => {
const { registerFill, getFillHelpers } = useSlotContext();
const fieldId = `product_field/${ sectionName }/${ fieldName }`;
useEffect( () => {
registerFill( fieldId );
}, [] );
return (
<Fill
name={ `woocommerce_product_field_${ sectionName }` }
key={ fieldId }
>
{ ( fillProps: Fill.Props ) =>
createOrderedChildren<
Fill.Props &
SlotContextHelpersType & {
sectionName: string;
},
{ _id: string }
>(
children,
order,
{
sectionName,
...fillProps,
...getFillHelpers(),
},
{ _id: fieldId }
)
}
</Fill>
);
};
export const WooProductFieldItem: React.FC< WooProductFieldItemProps > & {
Slot: React.FC< Slot.Props & WooProductFieldSlotProps >;
} = ( { children, sections, id } ) => {
return (
<>
{ sections.map(
( { name: sectionName, order = DEFAULT_FIELD_ORDER } ) => (
<WooProductFieldFill
fieldName={ id }
sectionName={ sectionName }
order={ order }
key={ sectionName }
>
{ children }
</WooProductFieldFill>
)
) }
</>
);
};
WooProductFieldItem.Slot = ( { fillProps, section } ) => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const { filterRegisteredFills } = useSlotContext();
return (
<Slot
name={ `woocommerce_product_field_${ section }` }
fillProps={ fillProps }
>
{ ( fills ) => {
if ( ! sortFillsByOrder ) {
return null;
}
return Children.map(
sortFillsByOrder( filterRegisteredFills( fills ) )?.props
.children,
( child ) => (
<div className="woocommerce-product-form__field">
{ child }
</div>
)
);
} }
</Slot>
);
};

View File

@ -0,0 +1,46 @@
# WooProductSectionItem Slot & Fill
A Slotfill component that will allow you to add a new section to the product editor.
## Usage
```jsx
<WooProductSectionItem id={ key } location="tab/general" order={ 2 } pluginId="test-plugin" >
{ () => {
return (
<ProductSectionLayout
title={ __( 'Product test section', 'woocommerce' ) }
description={ __(
'In this area you can describe the section.',
'woocommerce'
) }
>
<Card>
<CardBody>{ /* Section content */ }</CardBody>
</Card>
</ProductSectionLayout>
);
} }
</WooProductSectionItem>
<WooProductSectionItem.Slot location="tab/general" />
```
### WooProductSectionItem (fill)
This is the fill component. You must provide the `id` prop to identify your section fill with a unique string. This component will accept a series of props:
| Prop | Type | Description |
| ---------- | ------ | -------------------------------------------------------------------------------------------------- |
| `id` | String | A unique string to identify your fill. Used for configuration management. |
| `tabs` | Array | Contains an array of name and order of which slots it should be rendered in. |
| `pluginId` | String | A unique plugin ID to identify the plugin/extension that this fill is associated with. |
| `order` | Number | (optional) This number will dictate the order that the sections rendered by a Slot will be appear. |
### WooProductSectionItem.Slot (slot)
This is the slot component. This will render all the registered fills that match the `tab` prop.
| Name | Type | Description |
| ----- | ------ | ---------------------------------------------------------------------------------------------------- |
| `tab` | String | Unique to the location that the Slot appears, and must be the same as the one provided to any fills. |

View File

@ -0,0 +1 @@
export * from './woo-product-section-item';

View File

@ -0,0 +1,63 @@
/**
* External dependencies
*/
import React from 'react';
import { Slot, Fill } from '@wordpress/components';
import { createElement, Fragment } from '@wordpress/element';
/**
* Internal dependencies
*/
import { createOrderedChildren, sortFillsByOrder } from '../../utils';
import { ProductFillLocationType } from '../woo-product-tab-item';
type WooProductSectionItemProps = {
id: string;
tabs: ProductFillLocationType[];
pluginId: string;
};
type WooProductSectionSlotProps = {
tab: string;
};
const DEFAULT_SECTION_ORDER = 20;
export const WooProductSectionItem: React.FC< WooProductSectionItemProps > & {
Slot: React.FC< Slot.Props & WooProductSectionSlotProps >;
} = ( { children, tabs } ) => {
return (
<>
{ tabs.map( ( { name: tabName, order: sectionOrder } ) => (
<Fill
name={ `woocommerce_product_section_${ tabName }` }
key={ tabName }
>
{ ( fillProps: Fill.Props ) => {
return createOrderedChildren<
Fill.Props & { tabName: string }
>( children, sectionOrder || DEFAULT_SECTION_ORDER, {
tabName,
...fillProps,
} );
} }
</Fill>
) ) }
</>
);
};
WooProductSectionItem.Slot = ( { fillProps, tab } ) => (
<Slot
name={ `woocommerce_product_section_${ tab }` }
fillProps={ fillProps }
>
{ ( fills ) => {
if ( ! sortFillsByOrder ) {
return null;
}
return sortFillsByOrder( fills );
} }
</Slot>
);

View File

@ -0,0 +1,35 @@
# WooProductTabItem Slot & Fill
A Slotfill component that will allow you to add a new tab to the product editor.
## Usage
```jsx
<WooProductTabItem id={ key } location="tab/general" order={ 2 } pluginId="test-plugin" tabProps={ { title: 'New tab', name: 'new-tab' } } >
<Card>
<CardBody>{ /* Tab content */ }</CardBody>
</Card>
</WooProductTabItem>
<WooProductTabItem.Slot location="tab/general" />
```
### WooProductTabItem (fill)
This is the fill component. You must provide the `id` prop to identify your section fill with a unique string. This component will accept a series of props:
| Prop | Type | Description |
| ----------- | ------ | -------------------------------------------------------------------------------------------------------------- |
| `id` | String | A unique string to identify your fill. Used for configuration management. |
| `templates` | Array | Array of name and order of which template slots it should be rendered in |
| `pluginId` | String | A unique plugin ID to identify the plugin/extension that this fill is associated with. |
| `tabProps` | Object | An object containing tab props: name, title, className, disabled (see TabPanel.Tab from @wordpress/components) |
| `order` | Number | (optional) This number will dictate the order that the sections rendered by a Slot will be appear. |
### WooProductTabItem.Slot (slot)
This is the slot component. This will render all the registered fills that match the `template` prop.
| Name | Type | Description |
| ---------- | ------ | ---------------------------------------------------------------------------------------------------- |
| `template` | String | Unique to the location that the Slot appears, and must be the same as the one provided to any fills. |

View File

@ -0,0 +1 @@
export * from './woo-product-tab-item';

View File

@ -0,0 +1,109 @@
/**
* External dependencies
*/
import React, { ReactElement, ReactNode } from 'react';
import { Slot, Fill, TabPanel } from '@wordpress/components';
import { createElement, Fragment } from '@wordpress/element';
/**
* Internal dependencies
*/
import { createOrderedChildren } from '../../utils';
export type ProductFillLocationType = { name: string; order?: number };
type WooProductTabItemProps = {
id: string;
pluginId: string;
tabProps:
| TabPanel.Tab
// eslint-disable-next-line @typescript-eslint/no-explicit-any
| ( ( fillProps: Record< string, any > | undefined ) => TabPanel.Tab );
templates?: Array< ProductFillLocationType >;
};
type WooProductFieldSlotProps = {
template: string;
children: (
tabs: TabPanel.Tab[],
tabChildren: Record< string, ReactNode >
) => ReactElement | null;
};
const DEFAULT_TAB_ORDER = 20;
export const WooProductTabItem: React.FC< WooProductTabItemProps > & {
Slot: React.VFC<
Omit< Slot.Props, 'children' > & WooProductFieldSlotProps
>;
} = ( { children, tabProps, templates } ) => {
if ( ! templates ) {
// eslint-disable-next-line no-console
console.warn( 'WooProductTabItem fill is missing templates property.' );
return null;
}
return (
<>
{ templates.map( ( templateData ) => (
<Fill
name={ `woocommerce_product_tab_${ templateData.name }` }
key={ templateData.name }
>
{ ( fillProps: Fill.Props ) => {
return createOrderedChildren< Fill.Props >(
children,
templateData.order || DEFAULT_TAB_ORDER,
{},
{
tabProps,
templateName: templateData.name,
order: templateData.order || DEFAULT_TAB_ORDER,
...fillProps,
}
);
} }
</Fill>
) ) }
</>
);
};
WooProductTabItem.Slot = ( { fillProps, template, children } ) => (
<Slot
name={ `woocommerce_product_tab_${ template }` }
fillProps={ fillProps }
>
{ ( fills ) => {
const tabData = fills.reduce(
( { childrenMap, tabs }, fill ) => {
const props: WooProductTabItemProps & { order: number } =
fill[ 0 ].props;
if ( props && props.tabProps ) {
childrenMap[ props.tabProps.name ] = fill[ 0 ];
const tabProps =
typeof props.tabProps === 'function'
? props.tabProps( fillProps )
: props.tabProps;
tabs.push( {
...tabProps,
order: props.order ?? DEFAULT_TAB_ORDER,
} );
}
return {
childrenMap,
tabs,
};
},
{ childrenMap: {}, tabs: [] } as {
childrenMap: Record< string, ReactElement >;
tabs: Array< TabPanel.Tab & { order: number } >;
}
);
const orderedTabs = tabData.tabs.sort( ( a, b ) => {
return a.order - b.order;
} );
return children( orderedTabs, tabData.childrenMap );
} }
</Slot>
);

View File

@ -1,7 +1,4 @@
export {
ProductSectionLayout as __experimentalProductSectionLayout,
ProductFieldSection as __experimentalProductFieldSection,
} from './product-section-layout';
export * from './components';
/**
* Utils

View File

@ -1 +1 @@
@import 'product-section-layout/style.scss';
@import 'components/product-section-layout/style.scss';

View File

@ -0,0 +1,72 @@
/**
* External dependencies
*/
import { isValidElement, Fragment } from 'react';
import { Slot, Fill } from '@wordpress/components';
import { cloneElement, createElement } from '@wordpress/element';
type ChildrenProps = {
order: number;
};
/**
* Returns an object with the children and props that will be used by `cloneElement`. They will change depending on the
* type of children passed in.
*
* @param {Node} children - Node children.
* @param {number} order - Node order.
* @param {Array} props - Fill props.
* @param {Object} injectProps - Props to inject.
* @return {Object} Object with the keys: children and props.
*/
function getChildrenAndProps< T = Fill.Props, S = Record< string, unknown > >(
children: React.ReactNode,
order: number,
props: T,
injectProps?: S
) {
if ( typeof children === 'function' ) {
return {
children: children( { ...props, order, ...injectProps } ),
props: { order, ...injectProps },
};
} else if ( isValidElement( children ) ) {
// This checks whether 'children' is a react element or a standard HTML element.
if ( typeof children?.type === 'function' ) {
return {
children,
props: {
...props,
order,
...injectProps,
},
};
}
return {
children: children as React.ReactElement< ChildrenProps >,
props: { order, ...injectProps },
};
}
throw Error( 'Invalid children type' );
}
/**
* Ordered fill item.
*
* @param {Node} children - Node children.
* @param {number} order - Node order.
* @param {Array} props - Fill props.
* @param {Object} injectProps - Props to inject.
* @return {Node} Node.
*/
function createOrderedChildren< T = Fill.Props, S = Record< string, unknown > >(
children: React.ReactNode,
order: number,
props: T,
injectProps?: S
) {
const { children: childrenToRender, props: propsToRender } =
getChildrenAndProps( children, order, props, injectProps );
return cloneElement( childrenToRender, propsToRender );
}
export { createOrderedChildren };

View File

@ -17,6 +17,9 @@ import {
} from './get-product-variation-title';
import { preventLeavingProductForm } from './prevent-leaving-product-form';
export * from './create-ordered-children';
export * from './sort-fills-by-order';
export {
AUTO_DRAFT_NAME,
formatCurrencyDisplayValue,

View File

@ -0,0 +1,21 @@
/**
* External dependencies
*/
import { Fragment } from 'react';
import { Slot } from '@wordpress/components';
import { createElement } from '@wordpress/element';
/**
* Sort fills by order for slot children.
*
* @param {Array} fills - slot's `Fill`s.
* @return {Node} Node.
*/
export 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;
} );
return <Fragment>{ sortedFills }</Fragment>;
};

View File

@ -2,12 +2,12 @@
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { Link } from '@woocommerce/components';
import {
__experimentalWooProductSectionItem as WooProductSectionItem,
__experimentalWooProductFieldItem as WooProductFieldItem,
Link,
} from '@woocommerce/components';
import { __experimentalProductSectionLayout as ProductSectionLayout } from '@woocommerce/product-editor';
__experimentalProductSectionLayout as ProductSectionLayout,
} from '@woocommerce/product-editor';
import { recordEvent } from '@woocommerce/tracks';
/**

View File

@ -3,10 +3,10 @@
*/
import { __ } from '@wordpress/i18n';
import {
__experimentalProductFieldSection as ProductFieldSection,
__experimentalWooProductSectionItem as WooProductSectionItem,
__experimentalWooProductFieldItem as WooProductFieldItem,
} from '@woocommerce/components';
import { __experimentalProductFieldSection as ProductFieldSection } from '@woocommerce/product-editor';
} from '@woocommerce/product-editor';
/**
* Internal dependencies

View File

@ -2,12 +2,12 @@
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { Link } from '@woocommerce/components';
import {
__experimentalWooProductSectionItem as WooProductSectionItem,
__experimentalWooProductFieldItem as WooProductFieldItem,
Link,
} from '@woocommerce/components';
import { __experimentalProductFieldSection as ProductFieldSection } from '@woocommerce/product-editor';
__experimentalProductFieldSection as ProductFieldSection,
} from '@woocommerce/product-editor';
import { recordEvent } from '@woocommerce/tracks';
/**

View File

@ -3,13 +3,15 @@
*/
import { __ } from '@wordpress/i18n';
import {
__experimentalWooProductSectionItem as WooProductSectionItem,
__experimentalWooProductFieldItem as WooProductFieldItem,
Link,
useFormContext,
CollapsibleContent,
} from '@woocommerce/components';
import { __experimentalProductSectionLayout as ProductSectionLayout } from '@woocommerce/product-editor';
import {
__experimentalWooProductSectionItem as WooProductSectionItem,
__experimentalWooProductFieldItem as WooProductFieldItem,
__experimentalProductSectionLayout as ProductSectionLayout,
} from '@woocommerce/product-editor';
import { Card, CardBody } from '@wordpress/components';
import { recordEvent } from '@woocommerce/tracks';
import { getAdminLink } from '@woocommerce/settings';

View File

@ -3,13 +3,15 @@
*/
import { __ } from '@wordpress/i18n';
import {
__experimentalWooProductSectionItem as WooProductSectionItem,
__experimentalWooProductFieldItem as WooProductFieldItem,
Link,
useFormContext,
CollapsibleContent,
} from '@woocommerce/components';
import { __experimentalProductSectionLayout as ProductSectionLayout } from '@woocommerce/product-editor';
import {
__experimentalWooProductSectionItem as WooProductSectionItem,
__experimentalWooProductFieldItem as WooProductFieldItem,
__experimentalProductSectionLayout as ProductSectionLayout,
} from '@woocommerce/product-editor';
import { recordEvent } from '@woocommerce/tracks';
import { Product } from '@woocommerce/data';
import { useContext } from '@wordpress/element';

View File

@ -1,11 +1,8 @@
/**
* External dependencies
*/
import {
__experimentalWooProductFieldItem as WooProductFieldItem,
renderField,
useFormContext,
} from '@woocommerce/components';
import { renderField, useFormContext } from '@woocommerce/components';
import { __experimentalWooProductFieldItem as WooProductFieldItem } from '@woocommerce/product-editor';
import { Product, ProductFormField } from '@woocommerce/data';
export const Fields: React.FC< { fields: ProductFormField[] } > = ( {

View File

@ -2,8 +2,10 @@
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { __experimentalWooProductSectionItem as WooProductSectionItem } from '@woocommerce/components';
import { __experimentalProductFieldSection as ProductFieldSection } from '@woocommerce/product-editor';
import {
__experimentalProductFieldSection as ProductFieldSection,
__experimentalWooProductSectionItem as WooProductSectionItem,
} from '@woocommerce/product-editor';
import { ProductFormSection } from '@woocommerce/data';
export const Sections: React.FC< { sections: ProductFormSection[] } > = ( {

View File

@ -6,8 +6,8 @@ import { registerPlugin } from '@wordpress/plugins';
import {
__experimentalWooProductTabItem as WooProductTabItem,
__experimentalWooProductSectionItem as WooProductSectionItem,
useFormContext,
} from '@woocommerce/components';
} from '@woocommerce/product-editor';
import { useFormContext } from '@woocommerce/components';
import { Product } from '@woocommerce/data';
import { useMemo } from '@wordpress/element';

View File

@ -6,7 +6,7 @@ import { registerPlugin } from '@wordpress/plugins';
import {
__experimentalWooProductTabItem as WooProductTabItem,
__experimentalWooProductSectionItem as WooProductSectionItem,
} from '@woocommerce/components';
} from '@woocommerce/product-editor';
import { PartialProduct } from '@woocommerce/data';
/**

View File

@ -5,8 +5,8 @@ import { __ } from '@wordpress/i18n';
import {
__experimentalWooProductSectionItem as WooProductSectionItem,
__experimentalWooProductFieldItem as WooProductFieldItem,
} from '@woocommerce/components';
import { __experimentalProductSectionLayout as ProductSectionLayout } from '@woocommerce/product-editor';
__experimentalProductSectionLayout as ProductSectionLayout,
} from '@woocommerce/product-editor';
import { PartialProduct, OPTIONS_STORE_NAME } from '@woocommerce/data';
import { useSelect } from '@wordpress/data';
import { useState } from '@wordpress/element';

View File

@ -5,7 +5,7 @@ import { __ } from '@wordpress/i18n';
import { useEffect } from '@wordpress/element';
import { TabPanel, Tooltip } from '@wordpress/components';
import { navigateTo, getNewPath, getQuery } from '@woocommerce/navigation';
import { __experimentalWooProductTabItem as WooProductTabItem } from '@woocommerce/components';
import { __experimentalWooProductTabItem as WooProductTabItem } from '@woocommerce/product-editor';
import { PartialProduct } from '@woocommerce/data';
import classnames from 'classnames';

View File

@ -0,0 +1,4 @@
Significance: minor
Type: update
Update imports of product slot fills to new @woocommerce/product-editor library

File diff suppressed because it is too large Load Diff