This commit is contained in:
Mike Jolley 2020-05-29 12:28:04 +01:00 committed by GitHub
parent d1685bda7b
commit 18480b0d68
13 changed files with 190 additions and 36 deletions

View File

@ -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 );
} );
};

View File

@ -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 ),
} );

View File

@ -0,0 +1,2 @@
export * from './get-block-map.js';
export * from './create-blocks-from-template.js';

View File

@ -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.

View File

@ -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';

View File

@ -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.
*/

View File

@ -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 ) ),
];

View File

@ -1,3 +1,10 @@
.wc-block-single-product__selection {
width: 100%;
}
.wc-block-single-product__reset-layout {
padding: 0;
svg {
margin-right: 4px;
}
}

View File

@ -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>

View File

@ -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;

View File

@ -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/`

View File

@ -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",

View File

@ -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/*" ],