* Replace context with __experimentalShareWithChildBlocks

* Switch to parent block when changing views

* Swap order of views

* Drop default, use first view

* Improve block selection after changing views
This commit is contained in:
Mike Jolley 2021-09-24 16:13:39 +01:00 committed by GitHub
parent 8e38c6b857
commit 1aaa00ed2a
7 changed files with 1000 additions and 96 deletions

View File

@ -6,22 +6,14 @@ import { createContext, useContext } from '@wordpress/element';
/** /**
* Context consumed by inner blocks. * Context consumed by inner blocks.
*/ */
export type CartBlockControlsContextProps = { export type CartBlockContextProps = {
viewSwitcher: { currentView: string;
component: () => JSX.Element | null;
currentView: string;
};
}; };
export const CartBlockControlsContext = createContext< export const CartBlockContext = createContext< CartBlockContextProps >( {
CartBlockControlsContextProps currentView: '',
>( {
viewSwitcher: {
component: () => null,
currentView: 'filledCart',
},
} ); } );
export const useCartBlockControlsContext = (): CartBlockControlsContextProps => { export const useCartBlockContext = (): CartBlockContextProps => {
return useContext( CartBlockControlsContext ); return useContext( CartBlockContext );
}; };

View File

@ -6,9 +6,10 @@ 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 { import {
InnerBlocks,
useBlockProps, useBlockProps,
InnerBlocks,
InspectorControls, InspectorControls,
BlockControls,
} from '@wordpress/block-editor'; } from '@wordpress/block-editor';
import { PanelBody, ToggleControl, Notice } from '@wordpress/components'; import { PanelBody, ToggleControl, Notice } from '@wordpress/components';
import { CartCheckoutCompatibilityNotice } from '@woocommerce/editor-components/compatibility-notices'; import { CartCheckoutCompatibilityNotice } from '@woocommerce/editor-components/compatibility-notices';
@ -31,7 +32,7 @@ import './editor.scss';
import { addClassToBody, useBlockPropsWithLocking } from './hacks'; import { addClassToBody, useBlockPropsWithLocking } from './hacks';
import { useViewSwitcher } from './use-view-switcher'; import { useViewSwitcher } from './use-view-switcher';
import type { Attributes } from './types'; import type { Attributes } from './types';
import { CartBlockControlsContext } from './context'; import { CartBlockContext } from './context';
// This is adds a class to body to signal if the selected block is locked // This is adds a class to body to signal if the selected block is locked
addClassToBody(); addClassToBody();
@ -140,24 +141,28 @@ export const Edit = ( {
className, className,
attributes, attributes,
setAttributes, setAttributes,
clientId,
}: { }: {
className: string; className: string;
attributes: Attributes; attributes: Attributes;
setAttributes: ( attributes: Record< string, unknown > ) => undefined; setAttributes: ( attributes: Record< string, unknown > ) => undefined;
clientId: string;
} ): JSX.Element => { } ): JSX.Element => {
const { currentView, component: ViewSwitcherComponent } = useViewSwitcher( [ const { currentView, component: ViewSwitcherComponent } = useViewSwitcher(
{ clientId,
view: 'emptyCart', [
label: __( 'Empty Cart', 'woo-gutenberg-products-block' ), {
icon: <Icon srcElement={ removeCart } />, view: 'woocommerce/filled-cart-block',
}, label: __( 'Filled Cart', 'woo-gutenberg-products-block' ),
{ icon: <Icon srcElement={ filledCart } />,
view: 'filledCart', },
label: __( 'Filled Cart', 'woo-gutenberg-products-block' ), {
icon: <Icon srcElement={ filledCart } />, view: 'woocommerce/empty-cart-block',
default: true, label: __( 'Empty Cart', 'woo-gutenberg-products-block' ),
}, icon: <Icon srcElement={ removeCart } />,
] ); },
]
);
const cartClassName = classnames( { const cartClassName = classnames( {
'has-dark-controls': attributes.hasDarkControls, 'has-dark-controls': attributes.hasDarkControls,
} ); } );
@ -212,13 +217,12 @@ export const Edit = ( {
attributes={ attributes } attributes={ attributes }
setAttributes={ setAttributes } setAttributes={ setAttributes }
/> />
<ViewSwitcherComponent /> <BlockControls __experimentalShareWithChildBlocks>
<CartBlockControlsContext.Provider <ViewSwitcherComponent />
</BlockControls>
<CartBlockContext.Provider
value={ { value={ {
viewSwitcher: { currentView,
component: ViewSwitcherComponent,
currentView,
},
} } } }
> >
<CartProvider> <CartProvider>
@ -230,7 +234,7 @@ export const Edit = ( {
/> />
</div> </div>
</CartProvider> </CartProvider>
</CartBlockControlsContext.Provider> </CartBlockContext.Provider>
</EditorProvider> </EditorProvider>
</BlockErrorBoundary> </BlockErrorBoundary>
<CartCheckoutCompatibilityNotice blockName="cart" /> <CartCheckoutCompatibilityNotice blockName="cart" />

View File

@ -29,6 +29,7 @@ const settings = {
align: false, align: false,
html: false, html: false,
multiple: false, multiple: false,
__experimentalExposeControlsToChildren: true,
}, },
example: { example: {
attributes: { attributes: {

View File

@ -9,10 +9,11 @@ import { innerBlockAreas } from '@woocommerce/blocks-checkout';
*/ */
import { useForcedLayout } from '../../use-forced-layout'; import { useForcedLayout } from '../../use-forced-layout';
import { getAllowedBlocks } from '../../editor-utils'; import { getAllowedBlocks } from '../../editor-utils';
import { useCartBlockControlsContext } from '../../context'; import { useCartBlockContext } from '../../context';
export const Edit = ( { clientId }: { clientId: string } ): JSX.Element => { export const Edit = ( { clientId }: { clientId: string } ): JSX.Element => {
const blockProps = useBlockProps(); const blockProps = useBlockProps();
const { currentView } = useCartBlockContext();
const allowedBlocks = getAllowedBlocks( innerBlockAreas.EMPTY_CART ); const allowedBlocks = getAllowedBlocks( innerBlockAreas.EMPTY_CART );
useForcedLayout( { useForcedLayout( {
@ -20,18 +21,16 @@ export const Edit = ( { clientId }: { clientId: string } ): JSX.Element => {
template: allowedBlocks, template: allowedBlocks,
} ); } );
const {
viewSwitcher: { currentView, component: ViewSwitcherComponent },
} = useCartBlockControlsContext();
return ( return (
<div { ...blockProps } hidden={ currentView !== 'emptyCart' }> <div
{ ...blockProps }
hidden={ currentView !== 'woocommerce/empty-cart-block' }
>
This is the empty cart block. This is the empty cart block.
<InnerBlocks <InnerBlocks
allowedBlocks={ allowedBlocks } allowedBlocks={ allowedBlocks }
templateLock={ false } templateLock={ false }
/> />
<ViewSwitcherComponent />
</div> </div>
); );
}; };

View File

@ -12,23 +12,22 @@ import { useForcedLayout } from '../../use-forced-layout';
import { getAllowedBlocks } from '../../editor-utils'; import { getAllowedBlocks } from '../../editor-utils';
import { Columns } from './../../columns'; import { Columns } from './../../columns';
import './editor.scss'; import './editor.scss';
import { useCartBlockControlsContext } from '../../context'; import { useCartBlockContext } from '../../context';
export const Edit = ( { clientId }: { clientId: string } ): JSX.Element => { export const Edit = ( { clientId }: { clientId: string } ): JSX.Element => {
const blockProps = useBlockProps(); const blockProps = useBlockProps();
const { currentView } = useCartBlockContext();
const allowedBlocks = getAllowedBlocks( innerBlockAreas.FILLED_CART ); const allowedBlocks = getAllowedBlocks( innerBlockAreas.FILLED_CART );
useForcedLayout( { useForcedLayout( {
clientId, clientId,
template: allowedBlocks, template: allowedBlocks,
} ); } );
const {
viewSwitcher: { currentView, component: ViewSwitcherComponent },
} = useCartBlockControlsContext();
return ( return (
<div { ...blockProps } hidden={ currentView !== 'filledCart' }> <div
{ ...blockProps }
hidden={ currentView !== 'woocommerce/filled-cart-block' }
>
<Columns> <Columns>
<SidebarLayout className={ 'wc-block-cart' }> <SidebarLayout className={ 'wc-block-cart' }>
<InnerBlocks <InnerBlocks
@ -37,7 +36,6 @@ export const Edit = ( { clientId }: { clientId: string } ): JSX.Element => {
/> />
</SidebarLayout> </SidebarLayout>
</Columns> </Columns>
<ViewSwitcherComponent />
</div> </div>
); );
}; };

View File

@ -3,50 +3,52 @@
*/ */
import { __ } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
import { useState } from '@wordpress/element'; import { useState } from '@wordpress/element';
import { useDispatch, select } from '@wordpress/data';
import { Toolbar, ToolbarDropdownMenu } from '@wordpress/components'; import { Toolbar, ToolbarDropdownMenu } from '@wordpress/components';
import { BlockControls } from '@wordpress/block-editor';
import { Icon, eye } from '@woocommerce/icons'; import { Icon, eye } from '@woocommerce/icons';
import { store as blockEditorStore } from '@wordpress/block-editor';
interface View { interface View {
view: string; view: string;
label: string; label: string;
icon: string | JSX.Element; icon: string | JSX.Element;
default?: boolean;
} }
export const useViewSwitcher = ( export const useViewSwitcher = (
clientId: string,
views: View[] views: View[]
): { ): {
currentView: string; currentView: string;
component: () => JSX.Element; component: () => JSX.Element;
} => { } => {
const initialView = const initialView = views[ 0 ];
views?.find( ( view ) => view.default === true ) || views[ 0 ];
const [ currentView, setCurrentView ] = useState( initialView ); const [ currentView, setCurrentView ] = useState( initialView );
const { selectBlock } = useDispatch( 'core/block-editor' );
const { getBlock } = select( blockEditorStore );
const ViewSwitcherComponent = () => ( const ViewSwitcherComponent = () => (
<BlockControls> <Toolbar>
<Toolbar> <ToolbarDropdownMenu
<ToolbarDropdownMenu label={ __( 'Switch view', 'woo-gutenberg-products-block' ) }
label={ __( text={ currentView.label }
'Switch view', icon={
'woo-gutenberg-products-block' <Icon srcElement={ eye } style={ { marginRight: '8px' } } />
) } }
text={ currentView.label } controls={ views.map( ( view ) => ( {
icon={ ...view,
<Icon title: view.label,
srcElement={ eye } onClick: () => {
style={ { marginRight: '8px' } } setCurrentView( view );
/> selectBlock(
} getBlock( clientId ).innerBlocks.find(
controls={ views.map( ( view ) => ( { ( block: { name: string } ) =>
...view, block.name === view.view
title: view.label, )?.clientId || clientId
onClick: () => setCurrentView( view ), );
} ) ) } },
/> } ) ) }
</Toolbar> />
</BlockControls> </Toolbar>
); );
return { return {

File diff suppressed because it is too large Load Diff