Add layour editor to the single product block (https://github.com/woocommerce/woocommerce-blocks/pull/2586)
This commit is contained in:
parent
d1685bda7b
commit
18480b0d68
|
@ -0,0 +1,18 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { createBlock } from '@wordpress/blocks';
|
||||
|
||||
/**
|
||||
* Creates blocks for a given inner blocks Template.
|
||||
*
|
||||
* @param {Array} template Inner Blocks Template.
|
||||
*/
|
||||
export const createBlocksFromTemplate = ( template ) => {
|
||||
return template.map( ( [ name, atts = {}, innerBlocks = [] ] ) => {
|
||||
const children = innerBlocks
|
||||
? createBlocksFromTemplate( innerBlocks )
|
||||
: [];
|
||||
return createBlock( name, atts, children );
|
||||
} );
|
||||
};
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { getRegisteredInnerBlocks } from '@woocommerce/blocks-registry';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import {
|
||||
ProductTitle,
|
||||
ProductPrice,
|
||||
ProductButton,
|
||||
ProductImage,
|
||||
ProductRating,
|
||||
ProductSummary,
|
||||
ProductSaleBadge,
|
||||
} from '../components/product';
|
||||
|
||||
/**
|
||||
* Map blocks names to components.
|
||||
*
|
||||
* @param {string} blockName Name of the parent block. Used to get extension children.
|
||||
*/
|
||||
export const getBlockMap = ( blockName ) => ( {
|
||||
'woocommerce/product-price': ProductPrice,
|
||||
'woocommerce/product-image': ProductImage,
|
||||
'woocommerce/product-title': ProductTitle,
|
||||
'woocommerce/product-rating': ProductRating,
|
||||
'woocommerce/product-button': ProductButton,
|
||||
'woocommerce/product-summary': ProductSummary,
|
||||
'woocommerce/product-sale-badge': ProductSaleBadge,
|
||||
...getRegisteredInnerBlocks( blockName ),
|
||||
} );
|
|
@ -0,0 +1,2 @@
|
|||
export * from './get-block-map.js';
|
||||
export * from './create-blocks-from-template.js';
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* Internal dependencies
|
||||
* External dependencies
|
||||
*/
|
||||
import { getBlockMap } from '../../../blocks/products/base-utils';
|
||||
import { getBlockMap } from '@woocommerce/atomic-utils';
|
||||
|
||||
/**
|
||||
* Maps a layout config into atomic components.
|
||||
|
|
|
@ -26,6 +26,7 @@ import { Icon, grid } from '@woocommerce/icons';
|
|||
import GridLayoutControl from '@woocommerce/block-components/grid-layout-control';
|
||||
import { HAS_PRODUCTS } from '@woocommerce/block-settings';
|
||||
import { InnerBlockConfigurationProvider } from '@woocommerce/shared-context';
|
||||
import { getBlockMap } from '@woocommerce/atomic-utils';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
|
@ -37,7 +38,6 @@ import {
|
|||
} from '../utils';
|
||||
import {
|
||||
DEFAULT_PRODUCT_LIST_LAYOUT,
|
||||
getBlockMap,
|
||||
getProductLayoutConfig,
|
||||
} from '../base-utils';
|
||||
import { getSharedContentControls, getSharedListControls } from '../edit';
|
||||
|
|
|
@ -1,33 +1,3 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { getRegisteredInnerBlocks } from '@woocommerce/blocks-registry';
|
||||
import {
|
||||
ProductTitle,
|
||||
ProductPrice,
|
||||
ProductButton,
|
||||
ProductImage,
|
||||
ProductRating,
|
||||
ProductSummary,
|
||||
ProductSaleBadge,
|
||||
} from '@woocommerce/atomic-components/product';
|
||||
|
||||
/**
|
||||
* Map blocks names to components.
|
||||
*
|
||||
* @param {string} blockName Name of the parent block. Used to get extension children.
|
||||
*/
|
||||
export const getBlockMap = ( blockName ) => ( {
|
||||
'woocommerce/product-price': ProductPrice,
|
||||
'woocommerce/product-image': ProductImage,
|
||||
'woocommerce/product-title': ProductTitle,
|
||||
'woocommerce/product-rating': ProductRating,
|
||||
'woocommerce/product-button': ProductButton,
|
||||
'woocommerce/product-summary': ProductSummary,
|
||||
'woocommerce/product-sale-badge': ProductSaleBadge,
|
||||
...getRegisteredInnerBlocks( blockName ),
|
||||
} );
|
||||
|
||||
/**
|
||||
* The default layout built from the default template.
|
||||
*/
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { Icon, reader } from '@woocommerce/icons';
|
||||
import { getBlockMap } from '@woocommerce/atomic-utils';
|
||||
|
||||
export const BLOCK_NAME = 'woocommerce/single-product';
|
||||
export const BLOCK_TITLE = __(
|
||||
|
@ -14,3 +15,35 @@ export const BLOCK_DESCRIPTION = __(
|
|||
'Display a single product.',
|
||||
'woo-gutenberg-products-block'
|
||||
);
|
||||
|
||||
export const DEFAULT_INNER_BLOCKS = [
|
||||
[
|
||||
'core/columns',
|
||||
{},
|
||||
[
|
||||
[
|
||||
'core/column',
|
||||
{},
|
||||
[ [ 'woocommerce/product-image', { showSaleBadge: false } ] ],
|
||||
],
|
||||
[
|
||||
'core/column',
|
||||
{},
|
||||
[
|
||||
[ 'woocommerce/product-sale-badge' ],
|
||||
[ 'woocommerce/product-title' ],
|
||||
[ 'woocommerce/product-rating' ],
|
||||
[ 'woocommerce/product-price' ],
|
||||
[ 'woocommerce/product-summary' ],
|
||||
[ 'woocommerce/product-button' ],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
export const ALLOWED_INNER_BLOCKS = [
|
||||
'core/columns',
|
||||
'core/column',
|
||||
...Object.keys( getBlockMap( BLOCK_NAME ) ),
|
||||
];
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
.wc-block-single-product__selection {
|
||||
width: 100%;
|
||||
}
|
||||
.wc-block-single-product__reset-layout {
|
||||
padding: 0;
|
||||
|
||||
svg {
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,9 @@ const Editor = ( {
|
|||
setAttributes,
|
||||
error,
|
||||
getProduct,
|
||||
product,
|
||||
isLoading,
|
||||
clientId,
|
||||
} ) => {
|
||||
const { productId, isPreview } = attributes;
|
||||
const [ isEditing, setIsEditing ] = useState( ! productId );
|
||||
|
@ -97,7 +99,11 @@ const Editor = ( {
|
|||
/>
|
||||
</PanelBody>
|
||||
</InspectorControls>
|
||||
<LayoutEditor />
|
||||
<LayoutEditor
|
||||
clientId={ clientId }
|
||||
product={ product }
|
||||
isLoading={ isLoading }
|
||||
/>
|
||||
</>
|
||||
) }
|
||||
</BlockErrorBoundary>
|
||||
|
|
|
@ -1,8 +1,86 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { useCallback } from '@wordpress/element';
|
||||
import { useDispatch } from '@wordpress/data';
|
||||
import { InnerBlocks, InspectorControls } from '@wordpress/block-editor';
|
||||
import {
|
||||
InnerBlockConfigurationProvider,
|
||||
ProductDataContextProvider,
|
||||
} from '@woocommerce/shared-context';
|
||||
import { createBlocksFromTemplate } from '@woocommerce/atomic-utils';
|
||||
import classnames from 'classnames';
|
||||
import { PanelBody, Button } from '@wordpress/components';
|
||||
import { Icon, restore } from '@woocommerce/icons';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import {
|
||||
BLOCK_NAME,
|
||||
DEFAULT_INNER_BLOCKS,
|
||||
ALLOWED_INNER_BLOCKS,
|
||||
} from '../constants';
|
||||
|
||||
/**
|
||||
* Component to handle edit mode of the "Single Product Block".
|
||||
*/
|
||||
const LayoutEditor = () => {
|
||||
return null;
|
||||
const LayoutEditor = ( { product, clientId, isLoading } ) => {
|
||||
const baseClassName = 'wc-block-single-product';
|
||||
const { replaceInnerBlocks } = useDispatch( 'core/block-editor' );
|
||||
|
||||
const resetInnerBlocks = useCallback( () => {
|
||||
replaceInnerBlocks(
|
||||
clientId,
|
||||
createBlocksFromTemplate( DEFAULT_INNER_BLOCKS ),
|
||||
false
|
||||
);
|
||||
}, [ clientId, replaceInnerBlocks ] );
|
||||
|
||||
return (
|
||||
<InnerBlockConfigurationProvider
|
||||
parentName={ BLOCK_NAME }
|
||||
layoutStyleClassPrefix={ baseClassName }
|
||||
>
|
||||
<ProductDataContextProvider product={ product }>
|
||||
<InspectorControls>
|
||||
<PanelBody
|
||||
title={ __( 'Layout', 'woo-gutenberg-products-block' ) }
|
||||
initialOpen={ true }
|
||||
>
|
||||
<Button
|
||||
label={ __(
|
||||
'Reset layout to default',
|
||||
'woo-gutenberg-products-block'
|
||||
) }
|
||||
onClick={ resetInnerBlocks }
|
||||
isTertiary
|
||||
className="wc-block-single-product__reset-layout"
|
||||
>
|
||||
<Icon srcElement={ restore } />{ ' ' }
|
||||
{ __(
|
||||
'Reset layout',
|
||||
'woo-gutenberg-products-block'
|
||||
) }
|
||||
</Button>
|
||||
</PanelBody>
|
||||
</InspectorControls>
|
||||
<div
|
||||
className={ classnames( baseClassName, {
|
||||
'is-loading': isLoading,
|
||||
} ) }
|
||||
>
|
||||
<InnerBlocks
|
||||
template={ DEFAULT_INNER_BLOCKS }
|
||||
allowedBlocks={ ALLOWED_INNER_BLOCKS }
|
||||
templateLock={ false }
|
||||
renderAppender={ false }
|
||||
/>
|
||||
</div>
|
||||
</ProductDataContextProvider>
|
||||
</InnerBlockConfigurationProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default LayoutEditor;
|
||||
|
|
|
@ -54,6 +54,10 @@ const getAlias = ( options = {} ) => {
|
|||
__dirname,
|
||||
`../assets/js/${ pathPart }atomic/components/`
|
||||
),
|
||||
'@woocommerce/atomic-utils': path.resolve(
|
||||
__dirname,
|
||||
`../assets/js/${ pathPart }atomic/utils`
|
||||
),
|
||||
'@woocommerce/base-components': path.resolve(
|
||||
__dirname,
|
||||
`../assets/js/${ pathPart }base/components/`
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
],
|
||||
"moduleDirectories": [ "node_modules" ],
|
||||
"moduleNameMapper": {
|
||||
"@woocommerce/atomic-components": "assets/js/atomic/components",
|
||||
"@woocommerce/atomic-utils": "assets/js/atomic/utils",
|
||||
"@woocommerce/icons": "assets/js/icons",
|
||||
"@woocommerce/settings": "assets/js/settings/shared",
|
||||
"@woocommerce/block-settings": "assets/js/settings/blocks",
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
"@woocommerce/atomic-components/*": [
|
||||
"assets/js/base/atomic/components/*"
|
||||
],
|
||||
"@woocommerce/atomic-utils": [ "assets/js/atomic/utils" ],
|
||||
"@woocommerce/base-components/*": [ "assets/js/base/components/*" ],
|
||||
"@woocommerce/base-context": [ "assets/js/base/context" ],
|
||||
"@woocommerce/base-hocs/*": [ "assets/js/base/hocs/*" ],
|
||||
|
|
Loading…
Reference in New Issue