Setup basic column blocks for Cart i2 (https://github.com/woocommerce/woocommerce-blocks/pull/4780)
* setup basic column blocks * fix classnames * fix broken block.json in cart items block * move hacks back * dubplciate columns
This commit is contained in:
parent
f9b9679d62
commit
56551347a6
|
@ -0,0 +1,15 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { useBlockProps } from '@wordpress/block-editor';
|
||||||
|
|
||||||
|
export const Columns = ( {
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
}: {
|
||||||
|
children?: React.ReactNode;
|
||||||
|
} ): JSX.Element => {
|
||||||
|
const blockProps = useBlockProps( props );
|
||||||
|
|
||||||
|
return <div { ...blockProps }>{ children }</div>;
|
||||||
|
};
|
|
@ -0,0 +1 @@
|
||||||
|
export * from './columns-block';
|
|
@ -1,16 +1,12 @@
|
||||||
|
/* tslint:disable */
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import { CartCheckoutFeedbackPrompt } from '@woocommerce/editor-components/feedback-prompt';
|
import { CartCheckoutFeedbackPrompt } from '@woocommerce/editor-components/feedback-prompt';
|
||||||
import { InspectorControls } from '@wordpress/block-editor';
|
import { InnerBlocks, InspectorControls } from '@wordpress/block-editor';
|
||||||
import {
|
import { PanelBody, ToggleControl, Notice } from '@wordpress/components';
|
||||||
Disabled,
|
|
||||||
PanelBody,
|
|
||||||
ToggleControl,
|
|
||||||
Notice,
|
|
||||||
} from '@wordpress/components';
|
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { CartCheckoutCompatibilityNotice } from '@woocommerce/editor-components/compatibility-notices';
|
import { CartCheckoutCompatibilityNotice } from '@woocommerce/editor-components/compatibility-notices';
|
||||||
import ViewSwitcher from '@woocommerce/editor-components/view-switcher';
|
import ViewSwitcher from '@woocommerce/editor-components/view-switcher';
|
||||||
|
@ -25,13 +21,13 @@ import {
|
||||||
import { createInterpolateElement, useRef } from '@wordpress/element';
|
import { createInterpolateElement, useRef } from '@wordpress/element';
|
||||||
import { getAdminLink, getSetting } from '@woocommerce/settings';
|
import { getAdminLink, getSetting } from '@woocommerce/settings';
|
||||||
import { previewCart } from '@woocommerce/resource-previews';
|
import { previewCart } from '@woocommerce/resource-previews';
|
||||||
|
import { SidebarLayout } from '@woocommerce/base-components/sidebar-layout';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import Block from './block.js';
|
|
||||||
import EmptyCartEdit from './empty-cart-edit';
|
|
||||||
import './editor.scss';
|
import './editor.scss';
|
||||||
|
import { Columns } from './columns';
|
||||||
|
|
||||||
const BlockSettings = ( { attributes, setAttributes } ) => {
|
const BlockSettings = ( { attributes, setAttributes } ) => {
|
||||||
const {
|
const {
|
||||||
|
@ -162,6 +158,10 @@ const BlockSettings = ( { attributes, setAttributes } ) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ALLOWED_BLOCKS: string[] = [
|
||||||
|
'woocommerce/cart-items-block',
|
||||||
|
'woocommerce/cart-totals-block',
|
||||||
|
];
|
||||||
/**
|
/**
|
||||||
* Component to handle edit mode of "Cart Block".
|
* Component to handle edit mode of "Cart Block".
|
||||||
*
|
*
|
||||||
|
@ -176,6 +176,13 @@ const BlockSettings = ( { attributes, setAttributes } ) => {
|
||||||
* @param {function(any):any} props.setAttributes Setter for attributes.
|
* @param {function(any):any} props.setAttributes Setter for attributes.
|
||||||
*/
|
*/
|
||||||
const CartEditor = ( { className, attributes, setAttributes } ) => {
|
const CartEditor = ( { className, attributes, setAttributes } ) => {
|
||||||
|
const cartClassName = classnames( 'wc-block-cart', {
|
||||||
|
'has-dark-controls': attributes.hasDarkControls,
|
||||||
|
} );
|
||||||
|
const defaultInnerBlocksTemplate = [
|
||||||
|
[ 'woocommerce/cart-items-block', {}, [] ],
|
||||||
|
[ 'woocommerce/cart-totals-block', {}, [] ],
|
||||||
|
];
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={ classnames( className, 'wp-block-woocommerce-cart', {
|
className={ classnames( className, 'wp-block-woocommerce-cart', {
|
||||||
|
@ -221,16 +228,26 @@ const CartEditor = ( { className, attributes, setAttributes } ) => {
|
||||||
attributes={ attributes }
|
attributes={ attributes }
|
||||||
setAttributes={ setAttributes }
|
setAttributes={ setAttributes }
|
||||||
/>
|
/>
|
||||||
<Disabled>
|
<CartProvider>
|
||||||
<CartProvider>
|
<Columns>
|
||||||
<Block attributes={ attributes } />
|
<SidebarLayout
|
||||||
</CartProvider>
|
className={ cartClassName }
|
||||||
</Disabled>
|
>
|
||||||
|
<InnerBlocks
|
||||||
|
allowedBlocks={
|
||||||
|
ALLOWED_BLOCKS
|
||||||
|
}
|
||||||
|
template={
|
||||||
|
defaultInnerBlocksTemplate
|
||||||
|
}
|
||||||
|
templateLock="insert"
|
||||||
|
/>
|
||||||
|
</SidebarLayout>
|
||||||
|
</Columns>
|
||||||
|
</CartProvider>
|
||||||
</EditorProvider>
|
</EditorProvider>
|
||||||
<EmptyCartEdit hidden={ true } />
|
|
||||||
</>
|
</>
|
||||||
) }
|
) }
|
||||||
{ currentView === 'empty' && <EmptyCartEdit /> }
|
|
||||||
</BlockErrorBoundary>
|
</BlockErrorBoundary>
|
||||||
) }
|
) }
|
||||||
/>
|
/>
|
|
@ -0,0 +1,19 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { getBlockTypes } from '@wordpress/blocks';
|
||||||
|
|
||||||
|
// List of core block types to allow in inner block areas.
|
||||||
|
const coreBlockTypes = [ 'core/paragraph', 'core/image', 'core/separator' ];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a list of allowed blocks types under a specific parent block type.
|
||||||
|
*/
|
||||||
|
export const getAllowedBlocks = ( block: string ): string[] => [
|
||||||
|
...getBlockTypes()
|
||||||
|
.filter( ( blockType ) =>
|
||||||
|
( blockType?.parent || [] ).includes( block )
|
||||||
|
)
|
||||||
|
.map( ( { name } ) => name ),
|
||||||
|
...coreBlockTypes,
|
||||||
|
];
|
|
@ -6,3 +6,50 @@
|
||||||
max-height: 1000px;
|
max-height: 1000px;
|
||||||
overflow: hidden;
|
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 {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body.wc-lock-selected-block--remove {
|
||||||
|
.block-editor-block-settings-menu__popover {
|
||||||
|
.components-menu-group:last-child {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.components-menu-group:nth-last-child(2) {
|
||||||
|
margin-bottom: -12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,151 @@
|
||||||
|
/**
|
||||||
|
* HACKS
|
||||||
|
*
|
||||||
|
* This file contains functionality to "lock" blocks i.e. to prevent blocks being moved or deleted. This needs to be
|
||||||
|
* kept in place until native support for locking is available in WordPress (estimated WordPress 5.9).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @todo Remove custom block locking (requires native WordPress support)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import {
|
||||||
|
useBlockProps,
|
||||||
|
store as blockEditorStore,
|
||||||
|
} from '@wordpress/block-editor';
|
||||||
|
import { isTextField } from '@wordpress/dom';
|
||||||
|
import { useSelect, subscribe, select as _select } from '@wordpress/data';
|
||||||
|
import { useEffect, useRef } from '@wordpress/element';
|
||||||
|
import { MutableRefObject } from 'react';
|
||||||
|
import { BACKSPACE, DELETE } from '@wordpress/keycodes';
|
||||||
|
import { hasFilter } from '@wordpress/hooks';
|
||||||
|
/**
|
||||||
|
* Toggle class on body.
|
||||||
|
*
|
||||||
|
* @param {string} className CSS Class name.
|
||||||
|
* @param {boolean} add True to add, false to remove.
|
||||||
|
*/
|
||||||
|
const toggleBodyClass = ( className: string, add = true ) => {
|
||||||
|
if ( add ) {
|
||||||
|
window.document.body.classList.add( className );
|
||||||
|
} else {
|
||||||
|
window.document.body.classList.remove( className );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* addClassToBody
|
||||||
|
*
|
||||||
|
* This components watches the current selected block and adds a class name to the body if that block is locked. If the
|
||||||
|
* current block is not locked, it removes the class name. The appended body class is used to hide UI elements to prevent
|
||||||
|
* the block from being deleted.
|
||||||
|
*
|
||||||
|
* We use a component so we can react to changes in the store.
|
||||||
|
*/
|
||||||
|
export const addClassToBody = (): void => {
|
||||||
|
if ( ! hasFilter( 'blocks.registerBlockType', 'core/lock/addAttribute' ) ) {
|
||||||
|
subscribe( () => {
|
||||||
|
const blockEditorSelect = _select( blockEditorStore );
|
||||||
|
|
||||||
|
if ( ! blockEditorSelect ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedBlock = blockEditorSelect.getSelectedBlock();
|
||||||
|
|
||||||
|
if ( ! selectedBlock ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleBodyClass(
|
||||||
|
'wc-lock-selected-block--remove',
|
||||||
|
!! selectedBlock?.attributes?.lock?.remove
|
||||||
|
);
|
||||||
|
|
||||||
|
toggleBodyClass(
|
||||||
|
'wc-lock-selected-block--move',
|
||||||
|
!! selectedBlock?.attributes?.lock?.move
|
||||||
|
);
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a hook we use in conjunction with useBlockProps. Its goal is to check if a block is locked (move or remove)
|
||||||
|
* and will stop the keydown event from propagating to stop it from being deleted via the keyboard.
|
||||||
|
*
|
||||||
|
* @todo Disable custom locking support if native support is detected.
|
||||||
|
*/
|
||||||
|
const useLockBlock = ( {
|
||||||
|
clientId,
|
||||||
|
ref,
|
||||||
|
attributes,
|
||||||
|
}: {
|
||||||
|
clientId: string;
|
||||||
|
ref: MutableRefObject< Element | undefined >;
|
||||||
|
attributes: Record< string, unknown >;
|
||||||
|
} ): void => {
|
||||||
|
const lockInCore = hasFilter(
|
||||||
|
'blocks.registerBlockType',
|
||||||
|
'core/lock/addAttribute'
|
||||||
|
);
|
||||||
|
const { isSelected } = useSelect(
|
||||||
|
( select ) => {
|
||||||
|
return {
|
||||||
|
isSelected: select( blockEditorStore ).isBlockSelected(
|
||||||
|
clientId
|
||||||
|
),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
[ clientId ]
|
||||||
|
);
|
||||||
|
|
||||||
|
const node = ref.current;
|
||||||
|
|
||||||
|
return useEffect( () => {
|
||||||
|
if ( ! isSelected || ! node || lockInCore ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
function onKeyDown( event: KeyboardEvent ) {
|
||||||
|
const { keyCode, target } = event;
|
||||||
|
if ( keyCode !== BACKSPACE && keyCode !== DELETE ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( target !== node || isTextField( target ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Prevent the keyboard event from propogating if it supports locking.
|
||||||
|
if ( attributes?.lock?.remove ) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
node.addEventListener( 'keydown', onKeyDown, true );
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
node.removeEventListener( 'keydown', onKeyDown, true );
|
||||||
|
};
|
||||||
|
}, [ node, isSelected, lockInCore, attributes ] );
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This hook is a light wrapper to useBlockProps, it wraps that hook plus useLockBlock to pass data between them.
|
||||||
|
*/
|
||||||
|
export const useBlockPropsWithLocking = (
|
||||||
|
props: Record< string, unknown > = {}
|
||||||
|
): Record< string, unknown > => {
|
||||||
|
const ref = useRef< Element >();
|
||||||
|
const { attributes } = props;
|
||||||
|
const blockProps = useBlockProps( { ref, ...props } );
|
||||||
|
useLockBlock( {
|
||||||
|
ref,
|
||||||
|
attributes,
|
||||||
|
clientId: blockProps[ 'data-block' ],
|
||||||
|
} );
|
||||||
|
return blockProps;
|
||||||
|
};
|
|
@ -12,7 +12,7 @@ import { registerFeaturePluginBlockType } from '@woocommerce/block-settings';
|
||||||
import edit from './edit';
|
import edit from './edit';
|
||||||
import './style.scss';
|
import './style.scss';
|
||||||
import blockAttributes from './attributes';
|
import blockAttributes from './attributes';
|
||||||
|
import './inner-blocks';
|
||||||
/**
|
/**
|
||||||
* Register and run the Cart block.
|
* Register and run the Cart block.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"name": "woocommerce/cart-items-block",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"title": "Cart Items block",
|
||||||
|
"description": "Column containing cart items.",
|
||||||
|
"category": "woocommerce",
|
||||||
|
"supports": {
|
||||||
|
"align": false,
|
||||||
|
"html": false,
|
||||||
|
"multiple": false,
|
||||||
|
"reusable": false,
|
||||||
|
"inserter": false
|
||||||
|
},
|
||||||
|
"attributes": {
|
||||||
|
"lock": {
|
||||||
|
"default": {
|
||||||
|
"remove": true,
|
||||||
|
"move": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parent": [ "woocommerce/cart-i2" ],
|
||||||
|
"textdomain": "woo-gutenberg-products-block",
|
||||||
|
"apiVersion": 2
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { useBlockProps, InnerBlocks } from '@wordpress/block-editor';
|
||||||
|
import { Main } from '@woocommerce/base-components/sidebar-layout';
|
||||||
|
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.CART_ITEMS );
|
||||||
|
|
||||||
|
useForcedLayout( {
|
||||||
|
clientId,
|
||||||
|
template: allowedBlocks,
|
||||||
|
} );
|
||||||
|
return (
|
||||||
|
<Main className="wc-block-cart__main">
|
||||||
|
<div { ...blockProps }>
|
||||||
|
<InnerBlocks
|
||||||
|
allowedBlocks={ allowedBlocks }
|
||||||
|
templateLock={ false }
|
||||||
|
renderAppender={ InnerBlocks.ButtonBlockAppender }
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Main>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Save = (): JSX.Element => {
|
||||||
|
return (
|
||||||
|
<div { ...useBlockProps.save() }>
|
||||||
|
<InnerBlocks.Content />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,14 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { Main } from '@woocommerce/base-components/sidebar-layout';
|
||||||
|
|
||||||
|
const FrontendBlock = ( {
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: JSX.Element;
|
||||||
|
} ): JSX.Element => {
|
||||||
|
return <Main className="wc-block-cart__main">{ children }</Main>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FrontendBlock;
|
|
@ -0,0 +1,20 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { Icon, column } from '@wordpress/icons';
|
||||||
|
import { registerFeaturePluginBlockType } from '@woocommerce/block-settings';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import { Edit, Save } from './edit';
|
||||||
|
import metadata from './block.json';
|
||||||
|
|
||||||
|
registerFeaturePluginBlockType( metadata, {
|
||||||
|
icon: {
|
||||||
|
src: <Icon icon={ column } />,
|
||||||
|
foreground: '#874FB9',
|
||||||
|
},
|
||||||
|
edit: Edit,
|
||||||
|
save: Save,
|
||||||
|
} );
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"name": "woocommerce/cart-totals-block",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"title": "Cart Totals",
|
||||||
|
"description": "Column containing the cart totals.",
|
||||||
|
"category": "woocommerce",
|
||||||
|
"supports": {
|
||||||
|
"align": false,
|
||||||
|
"html": false,
|
||||||
|
"multiple": false,
|
||||||
|
"reusable": false,
|
||||||
|
"inserter": false
|
||||||
|
},
|
||||||
|
"attributes": {
|
||||||
|
"checkbox": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"type": "string",
|
||||||
|
"required": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parent": [ "woocommerce/cart-i2" ],
|
||||||
|
"textdomain": "woo-gutenberg-products-block",
|
||||||
|
"apiVersion": 2
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { useBlockProps, InnerBlocks } from '@wordpress/block-editor';
|
||||||
|
import { Sidebar } from '@woocommerce/base-components/sidebar-layout';
|
||||||
|
import { innerBlockAreas } from '@woocommerce/blocks-checkout';
|
||||||
|
import Title from '@woocommerce/base-components/title';
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import './style.scss';
|
||||||
|
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.CART_TOTALS );
|
||||||
|
|
||||||
|
useForcedLayout( {
|
||||||
|
clientId,
|
||||||
|
template: allowedBlocks,
|
||||||
|
} );
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Sidebar className="wc-block-cart__sidebar">
|
||||||
|
<div { ...blockProps }>
|
||||||
|
<Title headingLevel="2" className="wc-block-cart__totals-title">
|
||||||
|
{ __( 'Cart totals', 'woo-gutenberg-products-block' ) }
|
||||||
|
</Title>
|
||||||
|
<InnerBlocks
|
||||||
|
allowedBlocks={ allowedBlocks }
|
||||||
|
templateLock={ false }
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Sidebar>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Save = (): JSX.Element => {
|
||||||
|
return (
|
||||||
|
<div { ...useBlockProps.save() }>
|
||||||
|
<InnerBlocks.Content />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,19 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { Sidebar } from '@woocommerce/base-components/sidebar-layout';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import './style.scss';
|
||||||
|
|
||||||
|
const FrontendBlock = ( {
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: JSX.Element;
|
||||||
|
} ): JSX.Element => {
|
||||||
|
return <Sidebar className="wc-block-cart__sidebar">{ children }</Sidebar>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FrontendBlock;
|
|
@ -0,0 +1,20 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { Icon, column } from '@wordpress/icons';
|
||||||
|
import { registerFeaturePluginBlockType } from '@woocommerce/block-settings';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import { Edit, Save } from './edit';
|
||||||
|
import metadata from './block.json';
|
||||||
|
|
||||||
|
registerFeaturePluginBlockType( metadata, {
|
||||||
|
icon: {
|
||||||
|
src: <Icon icon={ column } />,
|
||||||
|
foreground: '#874FB9',
|
||||||
|
},
|
||||||
|
edit: Edit,
|
||||||
|
save: Save,
|
||||||
|
} );
|
|
@ -0,0 +1,8 @@
|
||||||
|
.is-mobile,
|
||||||
|
.is-small,
|
||||||
|
.is-medium {
|
||||||
|
.wc-block-cart__sidebar {
|
||||||
|
margin-bottom: $gap-large;
|
||||||
|
order: 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import './cart-items-block';
|
||||||
|
import './cart-totals-block';
|
|
@ -0,0 +1,63 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { useLayoutEffect, useRef } from '@wordpress/element';
|
||||||
|
import { useSelect, useDispatch } from '@wordpress/data';
|
||||||
|
import {
|
||||||
|
createBlock,
|
||||||
|
getBlockType,
|
||||||
|
Block,
|
||||||
|
AttributeSource,
|
||||||
|
} from '@wordpress/blocks';
|
||||||
|
|
||||||
|
const isBlockLocked = ( {
|
||||||
|
attributes,
|
||||||
|
}: {
|
||||||
|
attributes: Record< string, AttributeSource.Attribute >;
|
||||||
|
} ) => Boolean( attributes.lock?.remove || attributes.lock?.default?.remove );
|
||||||
|
|
||||||
|
export const useForcedLayout = ( {
|
||||||
|
clientId,
|
||||||
|
template,
|
||||||
|
}: {
|
||||||
|
clientId: string;
|
||||||
|
template: Array< string >;
|
||||||
|
} ): void => {
|
||||||
|
const currentTemplate = useRef( template );
|
||||||
|
const { insertBlock } = useDispatch( 'core/block-editor' );
|
||||||
|
const { innerBlocks, templateTypes } = useSelect(
|
||||||
|
( select ) => {
|
||||||
|
return {
|
||||||
|
innerBlocks: select( 'core/block-editor' ).getBlocks(
|
||||||
|
clientId
|
||||||
|
),
|
||||||
|
templateTypes: currentTemplate.current.map( ( blockName ) =>
|
||||||
|
getBlockType( blockName )
|
||||||
|
),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
[ clientId, currentTemplate ]
|
||||||
|
);
|
||||||
|
/**
|
||||||
|
* If the current inner blocks differ from the registered blocks, push the differences.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
useLayoutEffect( () => {
|
||||||
|
if ( ! clientId ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Missing check to see if registered block is 'forced'
|
||||||
|
templateTypes.forEach( ( block: Block | undefined ) => {
|
||||||
|
if (
|
||||||
|
block &&
|
||||||
|
isBlockLocked( block ) &&
|
||||||
|
! innerBlocks.find(
|
||||||
|
( { name }: { name: string } ) => name === block.name
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
const newBlock = createBlock( block.name );
|
||||||
|
insertBlock( newBlock, innerBlocks.length, clientId, false );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}, [ clientId, innerBlocks, insertBlock, templateTypes ] );
|
||||||
|
};
|
|
@ -13,6 +13,9 @@ export enum innerBlockAreas {
|
||||||
BILLING_ADDRESS = 'woocommerce/checkout-billing-address-block',
|
BILLING_ADDRESS = 'woocommerce/checkout-billing-address-block',
|
||||||
SHIPPING_METHODS = 'woocommerce/checkout-shipping-methods-block',
|
SHIPPING_METHODS = 'woocommerce/checkout-shipping-methods-block',
|
||||||
PAYMENT_METHODS = 'woocommerce/checkout-payment-methods-block',
|
PAYMENT_METHODS = 'woocommerce/checkout-payment-methods-block',
|
||||||
|
CART = 'woocommerce/cart-i2',
|
||||||
|
CART_ITEMS = 'woocommerce/cart-items-block',
|
||||||
|
CART_TOTALS = 'woocommerce/cart-totals-block',
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CheckoutBlockOptionsMetadata extends Partial< BlockConfiguration > {
|
interface CheckoutBlockOptionsMetadata extends Partial< BlockConfiguration > {
|
||||||
|
|
Loading…
Reference in New Issue