* Update area/types

* Add empty and filled block wrappers

* Add missing useBlockProps

* Add templates and inner block structure
This commit is contained in:
Mike Jolley 2021-09-21 16:41:09 +01:00 committed by GitHub
parent 614c7205ef
commit 2af90f301c
17 changed files with 316 additions and 152 deletions

View File

@ -3,7 +3,8 @@
*/
import { getSetting } from '@woocommerce/settings';
const blockAttributes = {
export const blockName = 'woocommerce/cart-i2';
export const blockAttributes = {
isPreview: {
type: 'boolean',
default: false,
@ -26,5 +27,3 @@ const blockAttributes = {
default: true,
},
};
export default blockAttributes;

View File

@ -5,11 +5,13 @@
import classnames from 'classnames';
import { __ } from '@wordpress/i18n';
import { CartCheckoutFeedbackPrompt } from '@woocommerce/editor-components/feedback-prompt';
import { InnerBlocks, InspectorControls } from '@wordpress/block-editor';
import {
InnerBlocks,
useBlockProps,
InspectorControls,
} from '@wordpress/block-editor';
import { PanelBody, ToggleControl, Notice } from '@wordpress/components';
import PropTypes from 'prop-types';
import { CartCheckoutCompatibilityNotice } from '@woocommerce/editor-components/compatibility-notices';
import ViewSwitcher from '@woocommerce/editor-components/view-switcher';
import { CART_PAGE_ID } from '@woocommerce/block-settings';
import BlockErrorBoundary from '@woocommerce/base-components/block-error-boundary';
import {
@ -20,15 +22,30 @@ import {
import { createInterpolateElement } from '@wordpress/element';
import { getAdminLink, getSetting } from '@woocommerce/settings';
import { previewCart } from '@woocommerce/resource-previews';
import { SidebarLayout } from '@woocommerce/base-components/sidebar-layout';
/**
* Internal dependencies
*/
import './editor.scss';
import { Columns } from './columns';
import { addClassToBody } from './hacks';
import type { Attributes } from './types';
const BlockSettings = ( { attributes, setAttributes } ) => {
// This is adds a class to body to signal if the selected block is locked
addClassToBody();
// Array of allowed block names.
const ALLOWED_BLOCKS: string[] = [
'woocommerce/filled-cart-block',
'woocommerce/empty-cart-block',
];
const BlockSettings = ( {
attributes,
setAttributes,
}: {
attributes: Attributes;
setAttributes: ( attributes: Record< string, unknown > ) => undefined;
} ): JSX.Element => {
const { isShippingCalculatorEnabled, showRateAfterTaxName } = attributes;
const { currentPostId } = useEditorContext();
return (
@ -113,42 +130,43 @@ const BlockSettings = ( { attributes, setAttributes } ) => {
);
};
const ALLOWED_BLOCKS: string[] = [
'woocommerce/cart-items-block',
'woocommerce/cart-totals-block',
];
/**
* Component to handle edit mode of "Cart Block".
*
* Note: We need to always render `<InnerBlocks>` in the editor. Otherwise,
* if the user saves the page without having triggered the 'Empty Cart'
* view, inner blocks would not be saved and they wouldn't be visible
* in the frontend.
*
* @param {Object} props Incoming props for the component.
* @param {string} props.className CSS class used.
* @param {Object} props.attributes Attributes available.
* @param {function(any):any} props.setAttributes Setter for attributes.
*/
const CartEditor = ( { className, attributes, setAttributes } ) => {
const cartClassName = classnames( 'wc-block-cart', {
export const Edit = ( {
className,
attributes,
setAttributes,
}: {
className: string;
attributes: Attributes;
setAttributes: ( attributes: Record< string, unknown > ) => undefined;
} ): JSX.Element => {
const cartClassName = classnames( {
'has-dark-controls': attributes.hasDarkControls,
} );
const defaultInnerBlocksTemplate = [
[
'woocommerce/cart-items-block',
{},
[ [ 'woocommerce/cart-line-items-block', {}, [] ] ],
],
[
'woocommerce/cart-totals-block',
'woocommerce/filled-cart-block',
{},
[
[ 'woocommerce/cart-order-summary-block', {}, [] ],
[ 'woocommerce/cart-express-payment-block', {}, [] ],
[ 'woocommerce/proceed-to-checkout-block', {}, [] ],
[
'woocommerce/cart-items-block',
{},
[ [ 'woocommerce/cart-line-items-block', {}, [] ] ],
],
[
'woocommerce/cart-totals-block',
{},
[
[ 'woocommerce/cart-order-summary-block', {}, [] ],
[ 'woocommerce/cart-express-payment-block', {}, [] ],
[ 'woocommerce/proceed-to-checkout-block', {}, [] ],
],
],
],
],
[ 'woocommerce/empty-cart-block', {}, [] ],
];
return (
<div
@ -156,75 +174,50 @@ const CartEditor = ( { className, attributes, setAttributes } ) => {
'is-editor-preview': attributes.isPreview,
} ) }
>
<ViewSwitcher
label={ __( 'Edit', 'woo-gutenberg-products-block' ) }
views={ [
{
value: 'full',
name: __( 'Full Cart', 'woo-gutenberg-products-block' ),
},
{
value: 'empty',
name: __(
'Empty Cart',
'woo-gutenberg-products-block'
),
},
] }
defaultView={ 'full' }
render={ ( currentView ) => (
<BlockErrorBoundary
header={ __(
'Cart Block Error',
'woo-gutenberg-products-block'
) }
text={ __(
'There was an error whilst rendering the cart block. If this problem continues, try re-creating the block.',
'woo-gutenberg-products-block'
) }
showErrorMessage={ true }
errorMessagePrefix={ __(
'Error message:',
'woo-gutenberg-products-block'
) }
>
{ currentView === 'full' && (
<>
<EditorProvider previewData={ { previewCart } }>
<BlockSettings
attributes={ attributes }
setAttributes={ setAttributes }
/>
<CartProvider>
<Columns>
<SidebarLayout
className={ cartClassName }
>
<InnerBlocks
allowedBlocks={
ALLOWED_BLOCKS
}
template={
defaultInnerBlocksTemplate
}
templateLock="insert"
/>
</SidebarLayout>
</Columns>
</CartProvider>
</EditorProvider>
</>
) }
</BlockErrorBoundary>
<BlockErrorBoundary
header={ __(
'Cart Block Error',
'woo-gutenberg-products-block'
) }
/>
text={ __(
'There was an error whilst rendering the cart block. If this problem continues, try re-creating the block.',
'woo-gutenberg-products-block'
) }
showErrorMessage={ true }
errorMessagePrefix={ __(
'Error message:',
'woo-gutenberg-products-block'
) }
>
<EditorProvider previewData={ { previewCart } }>
<BlockSettings
attributes={ attributes }
setAttributes={ setAttributes }
/>
<CartProvider>
<div className={ cartClassName }>
<InnerBlocks
allowedBlocks={ ALLOWED_BLOCKS }
template={ defaultInnerBlocksTemplate }
templateLock="insert"
/>
</div>
</CartProvider>
</EditorProvider>
</BlockErrorBoundary>
<CartCheckoutCompatibilityNotice blockName="cart" />
</div>
);
};
CartEditor.propTypes = {
className: PropTypes.string,
export const Save = (): JSX.Element => {
return (
<div
{ ...useBlockProps.save( {
className: 'wc-block-cart is-loading',
} ) }
>
<InnerBlocks.Content />
</div>
);
};
export default CartEditor;

View File

@ -2,39 +2,6 @@
margin: 0;
}
.wp-block-woocommerce-cart.is-editor-preview {
max-height: 1000px;
overflow: hidden;
}
.wp-block-woocommerce-cart-i2 {
.wc-block-components-sidebar-layout {
display: block;
}
.block-editor-block-list__layout {
display: flex;
flex-flow: row wrap;
align-items: flex-start;
.wc-block-cart__additional_fields {
padding: 0;
}
}
.wc-block-components-main,
.wc-block-components-sidebar,
.block-editor-block-list__layout {
> :first-child {
margin-top: 0;
}
}
.wp-block-woocommerce-cart-totals-block,
.wp-block-woocommerce-cart-items-block {
.block-editor-block-list__layout {
display: block;
}
}
}
body.wc-lock-selected-block--move {
.block-editor-block-mover__move-button-container,
.block-editor-block-mover {

View File

@ -21,7 +21,7 @@ import {
* Internal dependencies
*/
import Block from './block.js';
import blockAttributes from './attributes';
import { blockAttributes } from './attributes';
const reloadPage = () => void window.location.reload( true );
/**

View File

@ -2,17 +2,17 @@
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { InnerBlocks } from '@wordpress/block-editor';
import { Icon, cart } from '@woocommerce/icons';
import classnames from 'classnames';
import { registerFeaturePluginBlockType } from '@woocommerce/block-settings';
/**
* Internal dependencies
*/
import edit from './edit';
import { Edit, Save } from './edit';
import './style.scss';
import blockAttributes from './attributes';
import { blockName, blockAttributes } from './attributes';
import './inner-blocks';
/**
* Register and run the Cart block.
*/
@ -36,16 +36,8 @@ const settings = {
},
},
attributes: blockAttributes,
edit,
// Save the props to post content.
save( { attributes } ) {
return (
<div className={ classnames( 'is-loading', attributes.className ) }>
<InnerBlocks.Content />
</div>
);
},
edit: Edit,
save: Save,
};
registerFeaturePluginBlockType( 'woocommerce/cart-i2', settings );
registerFeaturePluginBlockType( blockName, settings );

View File

@ -20,7 +20,7 @@
}
}
},
"parent": [ "woocommerce/cart-i2" ],
"parent": [ "woocommerce/filled-cart-block" ],
"textdomain": "woo-gutenberg-products-block",
"apiVersion": 2
}

View File

@ -27,7 +27,7 @@
}
}
},
"parent": [ "woocommerce/cart-i2" ],
"parent": [ "woocommerce/filled-cart-block" ],
"textdomain": "woo-gutenberg-products-block",
"apiVersion": 2
}

View File

@ -0,0 +1,26 @@
{
"name": "woocommerce/empty-cart-block",
"version": "1.0.0",
"title": "Empty Cart",
"description": "Contains blocks that are displayed when the cart is empty.",
"category": "woocommerce",
"supports": {
"align": false,
"html": false,
"multiple": false,
"reusable": false,
"inserter": false
},
"attributes": {
"lock": {
"type": "object",
"default": {
"remove": true,
"move": true
}
}
},
"parent": [ "woocommerce/cart-i2" ],
"textdomain": "woo-gutenberg-products-block",
"apiVersion": 2
}

View File

@ -0,0 +1,38 @@
/**
* External dependencies
*/
import { useBlockProps, InnerBlocks } from '@wordpress/block-editor';
import { innerBlockAreas } from '@woocommerce/blocks-checkout';
/**
* Internal dependencies
*/
import { useForcedLayout } from '../../use-forced-layout';
import { getAllowedBlocks } from '../../editor-utils';
export const Edit = ( { clientId }: { clientId: string } ): JSX.Element => {
const blockProps = useBlockProps();
const allowedBlocks = getAllowedBlocks( innerBlockAreas.EMPTY_CART );
useForcedLayout( {
clientId,
template: allowedBlocks,
} );
return (
<div { ...blockProps }>
This is the empty cart block.
<InnerBlocks
allowedBlocks={ allowedBlocks }
templateLock={ false }
/>
</div>
);
};
export const Save = (): JSX.Element => {
return (
<div { ...useBlockProps.save() }>
<InnerBlocks.Content />
</div>
);
};

View File

@ -0,0 +1,20 @@
/**
* External dependencies
*/
import { Icon, removeCart } from '@woocommerce/icons';
import { registerFeaturePluginBlockType } from '@woocommerce/block-settings';
/**
* Internal dependencies
*/
import { Edit, Save } from './edit';
import metadata from './block.json';
registerFeaturePluginBlockType( metadata, {
icon: {
src: <Icon srcElement={ removeCart } />,
foreground: '#874FB9',
},
edit: Edit,
save: Save,
} );

View File

@ -0,0 +1,26 @@
{
"name": "woocommerce/filled-cart-block",
"version": "1.0.0",
"title": "Filled Cart",
"description": "Contains blocks that are displayed when the cart contains products.",
"category": "woocommerce",
"supports": {
"align": false,
"html": false,
"multiple": false,
"reusable": false,
"inserter": false
},
"attributes": {
"lock": {
"type": "object",
"default": {
"remove": true,
"move": true
}
}
},
"parent": [ "woocommerce/cart-i2" ],
"textdomain": "woo-gutenberg-products-block",
"apiVersion": 2
}

View File

@ -0,0 +1,44 @@
/**
* External dependencies
*/
import { useBlockProps, InnerBlocks } from '@wordpress/block-editor';
import { innerBlockAreas } from '@woocommerce/blocks-checkout';
import { SidebarLayout } from '@woocommerce/base-components/sidebar-layout';
/**
* Internal dependencies
*/
import { useForcedLayout } from '../../use-forced-layout';
import { getAllowedBlocks } from '../../editor-utils';
import { Columns } from './../../columns';
import './editor.scss';
export const Edit = ( { clientId }: { clientId: string } ): JSX.Element => {
const blockProps = useBlockProps();
const allowedBlocks = getAllowedBlocks( innerBlockAreas.FILLED_CART );
useForcedLayout( {
clientId,
template: allowedBlocks,
} );
return (
<div { ...blockProps }>
<Columns>
<SidebarLayout className={ 'wc-block-cart' }>
<InnerBlocks
allowedBlocks={ allowedBlocks }
templateLock={ false }
/>
</SidebarLayout>
</Columns>
</div>
);
};
export const Save = (): JSX.Element => {
return (
<div { ...useBlockProps.save() }>
<InnerBlocks.Content />
</div>
);
};

View File

@ -0,0 +1,23 @@
.wp-block-woocommerce-filled-cart-block {
.wc-block-components-sidebar-layout {
display: block;
}
.block-editor-block-list__layout {
display: flex;
flex-flow: row wrap;
align-items: flex-start;
}
.wc-block-components-main,
.wc-block-components-sidebar,
.block-editor-block-list__layout {
> :first-child {
margin-top: 0;
}
}
.wp-block-woocommerce-cart-totals-block,
.wp-block-woocommerce-cart-items-block {
.block-editor-block-list__layout {
display: block;
}
}
}

View File

@ -0,0 +1,20 @@
/**
* External dependencies
*/
import { Icon, cart } from '@woocommerce/icons';
import { registerFeaturePluginBlockType } from '@woocommerce/block-settings';
/**
* Internal dependencies
*/
import { Edit, Save } from './edit';
import metadata from './block.json';
registerFeaturePluginBlockType( metadata, {
icon: {
src: <Icon srcElement={ cart } />,
foreground: '#874FB9',
},
edit: Edit,
save: Save,
} );

View File

@ -1,9 +1,11 @@
/**
* Internal dependencies
*/
import './filled-cart-block';
import './cart-items-block';
import './cart-totals-block';
import './cart-line-items-block';
import './cart-totals-block';
import './cart-order-summary-block';
import './cart-express-payment-block';
import './proceed-to-checkout-block';
import './empty-cart-block';

View File

@ -0,0 +1,13 @@
export type InnerBlockTemplate = [
string,
Record< string, unknown >,
InnerBlockTemplate[] | undefined
];
export interface Attributes {
isPreview: boolean;
isShippingCalculatorEnabled: boolean;
hasDarkControls: boolean;
showRateAfterTaxName: boolean;
checkoutPageId: number;
}

View File

@ -13,7 +13,8 @@ export enum innerBlockAreas {
BILLING_ADDRESS = 'woocommerce/checkout-billing-address-block',
SHIPPING_METHODS = 'woocommerce/checkout-shipping-methods-block',
PAYMENT_METHODS = 'woocommerce/checkout-payment-methods-block',
CART = 'woocommerce/cart-i2',
EMPTY_CART = 'woocommerce/empty-cart-block',
FILLED_CART = 'woocommerce/filled-cart-block',
CART_ITEMS = 'woocommerce/cart-items-block',
CART_TOTALS = 'woocommerce/cart-totals-block',
}