diff --git a/packages/block-library/src/widget-area/edit/index.js b/packages/block-library/src/widget-area/edit/index.js index 4db09556424756..272956acd1809e 100644 --- a/packages/block-library/src/widget-area/edit/index.js +++ b/packages/block-library/src/widget-area/edit/index.js @@ -1,7 +1,7 @@ /** * WordPress dependencies */ -import { useSelect } from '@wordpress/data'; +import { useSelect, useDispatch } from '@wordpress/data'; import { EntityProvider } from '@wordpress/core-data'; import { Panel, PanelBody } from '@wordpress/components'; @@ -15,14 +15,22 @@ export default function WidgetAreaEdit( { className, attributes: { id, name }, } ) { - const index = useSelect( - ( select ) => select( 'core/block-editor' ).getBlockIndex( clientId ), + const isOpen = useSelect( + ( select ) => + select( 'core/edit-widgets' ).getIsWidgetAreaOpen( clientId ), [ clientId ] ); + const { setIsWidgetAreaOpen } = useDispatch( 'core/edit-widgets' ); return ( - + { + setIsWidgetAreaOpen( clientId, opened ); + } } + > + select( 'core/edit-widgets' ).getIsWidgetAreaOpen( rootClientId ), + [ rootClientId ] + ); + const { setIsWidgetAreaOpen } = useDispatch( 'core/edit-widgets' ); + const { selectBlock } = useDispatch( 'core/block-editor' ); + + function handleInserterOpen( isOpen ) { + if ( isOpen && ! isLastSelectedWidgetAreaOpen ) { + // Select the last selected block if hasn't already. + selectBlock( rootClientId ); + // Open the last selected widget area when opening the inserter. + setIsWidgetAreaOpen( rootClientId, isOpen ); + } + } return ( <> @@ -43,6 +60,7 @@ function Header( { isCustomizer } ) { ...toolbarItemProps, } } rootClientId={ rootClientId } + onToggle={ handleInserterOpen } /> ) } diff --git a/packages/edit-widgets/src/hooks/use-last-selected-root-id.js b/packages/edit-widgets/src/hooks/use-last-selected-root-id.js index 0db9a7da57a568..692e9cb1b21412 100644 --- a/packages/edit-widgets/src/hooks/use-last-selected-root-id.js +++ b/packages/edit-widgets/src/hooks/use-last-selected-root-id.js @@ -2,7 +2,6 @@ * WordPress dependencies */ import { useSelect } from '@wordpress/data'; -import { useRef } from '@wordpress/element'; /** * Internal dependencies @@ -18,28 +17,21 @@ const useLastSelectedRootId = () => { POST_TYPE, buildWidgetAreasPostId() ); - if ( widgetAreasPost ) { - return widgetAreasPost?.blocks[ 0 ]?.clientId; - } + return widgetAreasPost?.blocks[ 0 ]?.clientId; }, [] ); - const lastSelectedRootIdRef = useRef(); - if ( ! lastSelectedRootIdRef.current && firstRootId ) { - lastSelectedRootIdRef.current = firstRootId; - } - const selectedRootId = useSelect( ( select ) => { const { getBlockRootClientId, getBlockSelectionEnd } = select( 'core/block-editor' ); - return getBlockRootClientId( getBlockSelectionEnd() ); + const blockSelectionEnd = getBlockSelectionEnd(); + const blockRootClientId = getBlockRootClientId( blockSelectionEnd ); + // getBlockRootClientId returns an empty string for top-level blocks, in which case just return the block id. + return blockRootClientId === '' ? blockSelectionEnd : blockRootClientId; }, [] ); - if ( selectedRootId ) { - lastSelectedRootIdRef.current = selectedRootId; - } - - return lastSelectedRootIdRef.current; + // Fallbacks to the first widget area. + return selectedRootId || firstRootId; }; export default useLastSelectedRootId; diff --git a/packages/edit-widgets/src/store/actions.js b/packages/edit-widgets/src/store/actions.js index fab994e763c1ce..2452367b1381b9 100644 --- a/packages/edit-widgets/src/store/actions.js +++ b/packages/edit-widgets/src/store/actions.js @@ -147,3 +147,31 @@ export function setWidgetIdForClientId( clientId, widgetId ) { widgetId, }; } + +/** + * Sets the open state of all the widget areas. + * + * @param {Object} widgetAreasOpenState The open states of all the widget areas. + * @return {Object} Action. + */ +export function setWidgetAreasOpenState( widgetAreasOpenState ) { + return { + type: 'SET_WIDGET_AREAS_OPEN_STATE', + widgetAreasOpenState, + }; +} + +/** + * Sets the open state of the widget area. + * + * @param {string} clientId The clientId of the widget area. + * @param {boolean} isOpen Whether the widget area should be opened. + * @return {Object} Action. + */ +export function setIsWidgetAreaOpen( clientId, isOpen ) { + return { + type: 'SET_IS_WIDGET_AREA_OPEN', + clientId, + isOpen, + }; +} diff --git a/packages/edit-widgets/src/store/reducer.js b/packages/edit-widgets/src/store/reducer.js index f24805d59d41dd..0bc9e16f20df20 100644 --- a/packages/edit-widgets/src/store/reducer.js +++ b/packages/edit-widgets/src/store/reducer.js @@ -28,6 +28,33 @@ export function mapping( state, action ) { return state || {}; } +/** + * Controls the open state of the widget areas. + * + * @param {Object} state Redux state + * @param {Object} action Redux action + * @return {Array} Updated state + */ +export function widgetAreasOpenState( state = {}, action ) { + const { type } = action; + switch ( type ) { + case 'SET_WIDGET_AREAS_OPEN_STATE': { + return action.widgetAreasOpenState; + } + case 'SET_IS_WIDGET_AREA_OPEN': { + const { clientId, isOpen } = action; + return { + ...state, + [ clientId ]: isOpen, + }; + } + default: { + return state; + } + } +} + export default combineReducers( { mapping, + widgetAreasOpenState, } ); diff --git a/packages/edit-widgets/src/store/resolvers.js b/packages/edit-widgets/src/store/resolvers.js index 49ab28864dd6e8..e8af992ab9be1d 100644 --- a/packages/edit-widgets/src/store/resolvers.js +++ b/packages/edit-widgets/src/store/resolvers.js @@ -7,6 +7,7 @@ import { createBlock } from '@wordpress/blocks'; * Internal dependencies */ import { resolveWidgetAreas, select, dispatch } from './controls'; +import { setWidgetAreasOpenState } from './actions'; import { KIND, POST_TYPE, @@ -61,6 +62,13 @@ export function* getWidgetAreas() { ); } + const widgetAreasOpenState = {}; + widgetAreaBlocks.forEach( ( widgetAreaBlock, index ) => { + // Defaults to open the first widget area. + widgetAreasOpenState[ widgetAreaBlock.clientId ] = index === 0; + } ); + yield setWidgetAreasOpenState( widgetAreasOpenState ); + yield persistStubPost( buildWidgetAreasPostId(), widgetAreaBlocks ); yield { diff --git a/packages/edit-widgets/src/store/selectors.js b/packages/edit-widgets/src/store/selectors.js index 3941524ca54626..fc98c3e3e6b368 100644 --- a/packages/edit-widgets/src/store/selectors.js +++ b/packages/edit-widgets/src/store/selectors.js @@ -160,3 +160,15 @@ export const hasResolvedWidgetAreas = createRegistrySelector( return true; } ); + +/** + * Gets whether the widget area is opened. + * + * @param {Array} state The open state of the widget areas. + * @param {string} clientId The clientId of the widget area. + * @return {boolean} True if the widget area is open. + */ +export const getIsWidgetAreaOpen = ( state, clientId ) => { + const { widgetAreasOpenState } = state; + return !! widgetAreasOpenState[ clientId ]; +};