Cart i2: view switcher shared to children (https://github.com/woocommerce/woocommerce-blocks/pull/4817)
* 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:
parent
8e38c6b857
commit
1aaa00ed2a
|
@ -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 );
|
||||||
};
|
};
|
||||||
|
|
|
@ -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" />
|
||||||
|
|
|
@ -29,6 +29,7 @@ const settings = {
|
||||||
align: false,
|
align: false,
|
||||||
html: false,
|
html: false,
|
||||||
multiple: false,
|
multiple: false,
|
||||||
|
__experimentalExposeControlsToChildren: true,
|
||||||
},
|
},
|
||||||
example: {
|
example: {
|
||||||
attributes: {
|
attributes: {
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
Loading…
Reference in New Issue