From 5f3c1b2cd65ee35d6966ae9fe6f43dedc19f6c31 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Mon, 15 May 2023 11:02:52 +1000 Subject: [PATCH 01/44] Add ability to prevent editing blocks using useBlockEditingMode() --- .../components/block-editing-mode/index.js | 35 ++++++++++++++++++ .../src/components/block-list/block.js | 14 ++++---- .../src/components/block-list/content.scss | 10 +++--- .../block-list/use-in-between-inserter.js | 11 ++++-- .../src/components/block-toolbar/index.js | 10 +++--- .../block-tools/block-contextual-toolbar.js | 7 ++-- packages/block-editor/src/hooks/align.js | 8 ++++- packages/block-editor/src/hooks/duotone.js | 11 ++++-- packages/block-editor/src/private-apis.js | 2 ++ .../block-editor/src/store/private-actions.js | 15 ++++++++ .../src/store/private-selectors.js | 16 +++++++++ packages/block-editor/src/store/reducer.js | 16 +++++++++ packages/block-library/src/post-title/edit.js | 36 +++++++++++-------- 13 files changed, 152 insertions(+), 39 deletions(-) create mode 100644 packages/block-editor/src/components/block-editing-mode/index.js diff --git a/packages/block-editor/src/components/block-editing-mode/index.js b/packages/block-editor/src/components/block-editing-mode/index.js new file mode 100644 index 00000000000000..ed572f56f73b32 --- /dev/null +++ b/packages/block-editor/src/components/block-editing-mode/index.js @@ -0,0 +1,35 @@ +/** + * WordPress dependencies + */ +import { useSelect, useDispatch } from '@wordpress/data'; +import { useEffect } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import { store as blockEditorStore } from '../../store'; +import { unlock } from '../../lock-unlock'; + +export function useBlockEditingMode( clientId, mode ) { + const blockEditingMode = useSelect( + ( select ) => + unlock( select( blockEditorStore ) ).getBlockEditingMode( + clientId + ), + [ clientId ] + ); + const { setBlockEditingMode, unsetBlockEditingMode } = unlock( + useDispatch( blockEditorStore ) + ); + useEffect( () => { + if ( mode ) { + setBlockEditingMode( clientId, mode ); + } + return () => { + if ( mode ) { + unsetBlockEditingMode( clientId ); + } + }; + }, [ clientId, mode, setBlockEditingMode, unsetBlockEditingMode ] ); + return blockEditingMode; +} diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index 3980dd7b2aead3..964aacae99ac26 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -43,6 +43,8 @@ import BlockHtml from './block-html'; import { useBlockProps } from './use-block-props'; import { store as blockEditorStore } from '../../store'; import { useLayout } from './layout'; +import { useBlockEditingMode } from '../block-editing-mode'; + export const BlockListBlockContext = createContext(); /** @@ -101,14 +103,12 @@ function BlockListBlock( { themeSupportsLayout, hasContentLockedParent, isContentBlock, - isContentLocking, isTemporarilyEditingAsBlocks, } = useSelect( ( select ) => { const { getSettings, __unstableGetContentLockingParent, - getTemplateLock, __unstableGetTemporarilyEditingAsBlocks, } = select( blockEditorStore ); const _hasContentLockedParent = @@ -120,9 +120,6 @@ function BlockListBlock( { name ), hasContentLockedParent: _hasContentLockedParent, - isContentLocking: - getTemplateLock( clientId ) === 'contentOnly' && - ! _hasContentLockedParent, isTemporarilyEditingAsBlocks: __unstableGetTemporarilyEditingAsBlocks() === clientId, }; @@ -134,6 +131,8 @@ function BlockListBlock( { const parentLayout = useLayout() || {}; + const blockEditingMode = useBlockEditingMode( clientId ); + // We wrap the BlockEdit component in a div that hides it when editing in // HTML mode. This allows us to render all of the ancillary pieces // (InspectorControls, etc.) which are inside `BlockEdit` but not @@ -234,10 +233,11 @@ function BlockListBlock( { clientId, className: classnames( { - 'is-content-locked': isContentLocking, + 'is-editing-disabled': + blockEditingMode === 'disabled' || + ( hasContentLockedParent && ! isContentBlock ), 'is-content-locked-temporarily-editing-as-blocks': isTemporarilyEditingAsBlocks, - 'is-content-block': hasContentLockedParent && isContentBlock, }, dataAlign && themeSupportsLayout && `align${ dataAlign }`, className diff --git a/packages/block-editor/src/components/block-list/content.scss b/packages/block-editor/src/components/block-list/content.scss index 80056f35cf0d6e..dab07ced873e9f 100644 --- a/packages/block-editor/src/components/block-list/content.scss +++ b/packages/block-editor/src/components/block-list/content.scss @@ -161,13 +161,13 @@ padding: 0; } -.is-content-locked { - .block-editor-block-list__block { +.block-editor-block-list__layout, +.block-editor-block-list__block { + pointer-events: initial; + + &.is-editing-disabled { pointer-events: none; } - .is-content-block { - pointer-events: initial; - } } .block-editor-block-list__layout .block-editor-block-list__block { diff --git a/packages/block-editor/src/components/block-list/use-in-between-inserter.js b/packages/block-editor/src/components/block-list/use-in-between-inserter.js index 6e9365ad102242..854d1dc7ca86a1 100644 --- a/packages/block-editor/src/components/block-list/use-in-between-inserter.js +++ b/packages/block-editor/src/components/block-list/use-in-between-inserter.js @@ -11,6 +11,7 @@ import { isRTL } from '@wordpress/i18n'; */ import { store as blockEditorStore } from '../../store'; import { InsertionPointOpenRef } from '../block-tools/insertion-point'; +import { unlock } from '../../lock-unlock'; export function useInBetweenInserter() { const openRef = useContext( InsertionPointOpenRef ); @@ -29,7 +30,8 @@ export function useInBetweenInserter() { getSelectedBlockClientIds, getTemplateLock, __unstableIsWithinBlockOverlay, - } = useSelect( blockEditorStore ); + getBlockEditingMode, + } = unlock( useSelect( blockEditorStore ) ); const { showInsertionPoint, hideInsertionPoint } = useDispatch( blockEditorStore ); @@ -74,8 +76,11 @@ export function useInBetweenInserter() { rootClientId = blockElement.getAttribute( 'data-block' ); } - // Don't set the insertion point if the template is locked. - if ( getTemplateLock( rootClientId ) ) { + // Don't set the insertion point if the root is locked. + if ( + getTemplateLock( rootClientId ) || + getBlockEditingMode( rootClientId ) === 'disabled' + ) { return; } diff --git a/packages/block-editor/src/components/block-toolbar/index.js b/packages/block-editor/src/components/block-toolbar/index.js index d9799849b13990..af5fe6f509b582 100644 --- a/packages/block-editor/src/components/block-toolbar/index.js +++ b/packages/block-editor/src/components/block-toolbar/index.js @@ -32,6 +32,7 @@ import BlockEditVisuallyButton from '../block-edit-visually-button'; import { useShowMoversGestures } from './utils'; import { store as blockEditorStore } from '../../store'; import __unstableBlockNameContext from './block-name-context'; +import { unlock } from '../../lock-unlock'; const BlockToolbar = ( { hideDragHandle } ) => { const { @@ -52,7 +53,8 @@ const BlockToolbar = ( { hideDragHandle } ) => { getBlockRootClientId, getSettings, __unstableGetContentLockingParent, - } = select( blockEditorStore ); + getBlockEditingMode, + } = unlock( select( blockEditorStore ) ); const selectedBlockClientIds = getSelectedBlockClientIds(); const selectedBlockClientId = selectedBlockClientIds[ 0 ]; const blockRootClientId = getBlockRootClientId( selectedBlockClientId ); @@ -73,9 +75,9 @@ const BlockToolbar = ( { hideDragHandle } ) => { isVisual: selectedBlockClientIds.every( ( id ) => getBlockMode( id ) === 'visual' ), - isContentLocked: !! __unstableGetContentLockingParent( - selectedBlockClientId - ), + isContentLocked: + !! __unstableGetContentLockingParent( selectedBlockClientId ) || + getBlockEditingMode( selectedBlockClientId ) !== 'default', }; }, [] ); diff --git a/packages/block-editor/src/components/block-tools/block-contextual-toolbar.js b/packages/block-editor/src/components/block-tools/block-contextual-toolbar.js index 385b120c352d22..d709869de52b2e 100644 --- a/packages/block-editor/src/components/block-tools/block-contextual-toolbar.js +++ b/packages/block-editor/src/components/block-tools/block-contextual-toolbar.js @@ -25,6 +25,7 @@ import NavigableToolbar from '../navigable-toolbar'; import BlockToolbar from '../block-toolbar'; import { store as blockEditorStore } from '../../store'; import BlockIcon from '../block-icon'; +import { unlock } from '../../lock-unlock'; function BlockContextualToolbar( { focusOnMount, isFixed, ...props } ) { // When the toolbar is fixed it can be collapsed @@ -39,7 +40,8 @@ function BlockContextualToolbar( { focusOnMount, isFixed, ...props } ) { getBlockParents, getSelectedBlockClientIds, __unstableGetContentLockingParent, - } = select( blockEditorStore ); + getBlockEditingMode, + } = unlock( select( blockEditorStore ) ); const { getBlockType } = select( blocksStore ); const selectedBlockClientIds = getSelectedBlockClientIds(); const _selectedBlockClientId = selectedBlockClientIds[ 0 ]; @@ -64,7 +66,8 @@ function BlockContextualToolbar( { focusOnMount, isFixed, ...props } ) { selectedBlockClientIds.length <= 1 && ! __unstableGetContentLockingParent( _selectedBlockClientId - ), + ) && + getBlockEditingMode( _selectedBlockClientId ) === 'default', }; }, [] ); diff --git a/packages/block-editor/src/hooks/align.js b/packages/block-editor/src/hooks/align.js index 23e6809685377a..1a8896513ab2d0 100644 --- a/packages/block-editor/src/hooks/align.js +++ b/packages/block-editor/src/hooks/align.js @@ -21,6 +21,7 @@ import { useSelect } from '@wordpress/data'; import { BlockControls, BlockAlignmentControl } from '../components'; import useAvailableAlignments from '../components/block-alignment-control/use-available-alignments'; import { store as blockEditorStore } from '../store'; +import { useBlockEditingMode } from '../components/block-editing-mode'; /** * An array which includes all possible valid alignments, @@ -141,7 +142,12 @@ export const withToolbarControls = createHigherOrderComponent( }, [ props.clientId ] ); - if ( ! validAlignments.length || isContentLocked ) { + const blockEditingMode = useBlockEditingMode( props.clientId ); + if ( + ! validAlignments.length || + isContentLocked || + blockEditingMode !== 'default' + ) { return blockEdit; } diff --git a/packages/block-editor/src/hooks/duotone.js b/packages/block-editor/src/hooks/duotone.js index c28310cc7b86b0..f018444de0c67f 100644 --- a/packages/block-editor/src/hooks/duotone.js +++ b/packages/block-editor/src/hooks/duotone.js @@ -38,6 +38,7 @@ import { scopeSelector } from '../components/global-styles/utils'; import { useBlockSettings } from './utils'; import { store as blockEditorStore } from '../store'; import { default as StylesFiltersPanel } from '../components/global-styles/filters-panel'; +import { useBlockEditingMode } from '../components/block-editing-mode'; const EMPTY_ARRAY = []; @@ -235,15 +236,19 @@ const withDuotoneControls = createHigherOrderComponent( [ props.clientId ] ); + const blockEditingMode = useBlockEditingMode( props.clientId ); + // CAUTION: code added before this line will be executed // for all blocks, not just those that support duotone. Code added // above this line should be carefully evaluated for its impact on // performance. return ( <> - { hasDuotoneSupport && ! isContentLocked && ( - - ) } + { hasDuotoneSupport && + ! isContentLocked && + blockEditingMode === 'default' && ( + + ) } ); diff --git a/packages/block-editor/src/private-apis.js b/packages/block-editor/src/private-apis.js index a7357311eedbe8..f96130b670e240 100644 --- a/packages/block-editor/src/private-apis.js +++ b/packages/block-editor/src/private-apis.js @@ -11,6 +11,7 @@ import { PrivateListView } from './components/list-view'; import BlockInfo from './components/block-info-slot-fill'; import { useShouldContextualToolbarShow } from './utils/use-should-contextual-toolbar-show'; import { cleanEmptyObject } from './hooks/utils'; +import { useBlockEditingMode } from './components/block-editing-mode'; /** * Private @wordpress/block-editor APIs. @@ -26,4 +27,5 @@ lock( privateApis, { BlockInfo, useShouldContextualToolbarShow, cleanEmptyObject, + useBlockEditingMode, } ); diff --git a/packages/block-editor/src/store/private-actions.js b/packages/block-editor/src/store/private-actions.js index 2d33ea82cb9b63..496562687118b1 100644 --- a/packages/block-editor/src/store/private-actions.js +++ b/packages/block-editor/src/store/private-actions.js @@ -66,3 +66,18 @@ export function showBlockInterface() { type: 'SHOW_BLOCK_INTERFACE', }; } + +export function setBlockEditingMode( clientId, mode ) { + return { + type: 'SET_BLOCK_EDITING_MODE', + clientId, + mode, + }; +} + +export function unsetBlockEditingMode( clientId ) { + return { + type: 'UNSET_BLOCK_EDITING_MODE', + clientId, + }; +} diff --git a/packages/block-editor/src/store/private-selectors.js b/packages/block-editor/src/store/private-selectors.js index 60712e6b8eb6e0..8f9af5df0b692e 100644 --- a/packages/block-editor/src/store/private-selectors.js +++ b/packages/block-editor/src/store/private-selectors.js @@ -18,3 +18,19 @@ export function isBlockInterfaceHidden( state ) { export function getLastInsertedBlocksClientIds( state ) { return state?.lastBlockInserted?.clientIds; } + +export function getBlockEditingMode( state, clientId ) { + if ( ! clientId ) { + return state.settings.rootBlockEditingMode; + } + while ( + ! state.blockEditingModes.has( clientId ) && + state.blocks.parents.has( clientId ) + ) { + clientId = state.blocks.parents.get( clientId ); + } + return ( + state.blockEditingModes.get( clientId ) ?? + state.settings.rootBlockEditingMode + ); +} diff --git a/packages/block-editor/src/store/reducer.js b/packages/block-editor/src/store/reducer.js index 4239cb1aba8489..f0c44244371c04 100644 --- a/packages/block-editor/src/store/reducer.js +++ b/packages/block-editor/src/store/reducer.js @@ -1834,6 +1834,21 @@ export function temporarilyEditingAsBlocks( state = '', action ) { return state; } +export function blockEditingModes( state = new Map(), action ) { + switch ( action.type ) { + case 'SET_BLOCK_EDITING_MODE': + return new Map( state ).set( action.clientId, action.mode ); + case 'UNSET_BLOCK_EDITING_MODE': { + const newState = new Map( state ); + newState.delete( action.clientId ); + return newState; + } + case 'RESET_BLOCKS': + return new Map(); + } + return state; +} + const combinedReducers = combineReducers( { blocks, isTyping, @@ -1856,6 +1871,7 @@ const combinedReducers = combineReducers( { lastBlockInserted, temporarilyEditingAsBlocks, blockVisibility, + blockEditingModes, } ); function withAutomaticChangeReset( reducer ) { diff --git a/packages/block-library/src/post-title/edit.js b/packages/block-library/src/post-title/edit.js index 8cd71881e06dec..a30b01dee74569 100644 --- a/packages/block-library/src/post-title/edit.js +++ b/packages/block-library/src/post-title/edit.js @@ -12,6 +12,7 @@ import { InspectorControls, useBlockProps, PlainText, + privateApis as blockEditorPrivateApis, } from '@wordpress/block-editor'; import { ToggleControl, TextControl, PanelBody } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; @@ -23,12 +24,16 @@ import { useEntityProp } from '@wordpress/core-data'; */ import HeadingLevelDropdown from '../heading/heading-level-dropdown'; import { useCanEditEntity } from '../utils/hooks'; +import { unlock } from '../private-apis'; + +const { useBlockEditingMode } = unlock( blockEditorPrivateApis ); export default function PostTitleEdit( { attributes: { level, textAlign, isLink, rel, linkTarget }, setAttributes, context: { postType, postId, queryId }, insertBlocksAfter, + clientId, } ) { const TagName = 0 === level ? 'p' : 'h' + level; const isDescendentOfQueryLoop = Number.isFinite( queryId ); @@ -58,6 +63,7 @@ export default function PostTitleEdit( { [ `has-text-align-${ textAlign }` ]: textAlign, } ), } ); + const blockEditingMode = useBlockEditingMode( clientId ); let titleElement = ( { __( 'Post Title' ) } @@ -114,20 +120,22 @@ export default function PostTitleEdit( { return ( <> - - - setAttributes( { level: newLevel } ) - } - /> - { - setAttributes( { textAlign: nextAlign } ); - } } - /> - + { blockEditingMode === 'default' && ( + + + setAttributes( { level: newLevel } ) + } + /> + { + setAttributes( { textAlign: nextAlign } ); + } } + /> + + ) } Date: Mon, 22 May 2023 10:32:13 +1000 Subject: [PATCH 02/44] Make useBlockEditingMode use context --- .../src/components/block-editing-mode/index.js | 8 +++++--- packages/block-editor/src/components/block-list/block.js | 9 +++++---- packages/block-editor/src/hooks/align.js | 2 +- packages/block-editor/src/hooks/duotone.js | 2 +- packages/block-library/src/post-title/edit.js | 3 +-- 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/packages/block-editor/src/components/block-editing-mode/index.js b/packages/block-editor/src/components/block-editing-mode/index.js index ed572f56f73b32..056721209ddfc8 100644 --- a/packages/block-editor/src/components/block-editing-mode/index.js +++ b/packages/block-editor/src/components/block-editing-mode/index.js @@ -2,15 +2,17 @@ * WordPress dependencies */ import { useSelect, useDispatch } from '@wordpress/data'; -import { useEffect } from '@wordpress/element'; +import { useContext, useEffect } from '@wordpress/element'; /** * Internal dependencies */ import { store as blockEditorStore } from '../../store'; import { unlock } from '../../lock-unlock'; +import { BlockListBlockContext } from '../block-list/block'; -export function useBlockEditingMode( clientId, mode ) { +export function useBlockEditingMode( mode ) { + const { clientId } = useContext( BlockListBlockContext ); const blockEditingMode = useSelect( ( select ) => unlock( select( blockEditorStore ) ).getBlockEditingMode( @@ -30,6 +32,6 @@ export function useBlockEditingMode( clientId, mode ) { unsetBlockEditingMode( clientId ); } }; - }, [ clientId, mode, setBlockEditingMode, unsetBlockEditingMode ] ); + }, [ clientId, mode ] ); return blockEditingMode; } diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index 964aacae99ac26..d331fe7e541f30 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -43,7 +43,7 @@ import BlockHtml from './block-html'; import { useBlockProps } from './use-block-props'; import { store as blockEditorStore } from '../../store'; import { useLayout } from './layout'; -import { useBlockEditingMode } from '../block-editing-mode'; +import { unlock } from '../../lock-unlock'; export const BlockListBlockContext = createContext(); @@ -104,13 +104,15 @@ function BlockListBlock( { hasContentLockedParent, isContentBlock, isTemporarilyEditingAsBlocks, + blockEditingMode, } = useSelect( ( select ) => { const { getSettings, __unstableGetContentLockingParent, __unstableGetTemporarilyEditingAsBlocks, - } = select( blockEditorStore ); + getBlockEditingMode, + } = unlock( select( blockEditorStore ) ); const _hasContentLockedParent = !! __unstableGetContentLockingParent( clientId ); return { @@ -122,6 +124,7 @@ function BlockListBlock( { hasContentLockedParent: _hasContentLockedParent, isTemporarilyEditingAsBlocks: __unstableGetTemporarilyEditingAsBlocks() === clientId, + blockEditingMode: getBlockEditingMode( clientId ), }; }, [ name, clientId ] @@ -131,8 +134,6 @@ function BlockListBlock( { const parentLayout = useLayout() || {}; - const blockEditingMode = useBlockEditingMode( clientId ); - // We wrap the BlockEdit component in a div that hides it when editing in // HTML mode. This allows us to render all of the ancillary pieces // (InspectorControls, etc.) which are inside `BlockEdit` but not diff --git a/packages/block-editor/src/hooks/align.js b/packages/block-editor/src/hooks/align.js index 1a8896513ab2d0..58c076fd8e21c8 100644 --- a/packages/block-editor/src/hooks/align.js +++ b/packages/block-editor/src/hooks/align.js @@ -142,7 +142,7 @@ export const withToolbarControls = createHigherOrderComponent( }, [ props.clientId ] ); - const blockEditingMode = useBlockEditingMode( props.clientId ); + const blockEditingMode = useBlockEditingMode(); if ( ! validAlignments.length || isContentLocked || diff --git a/packages/block-editor/src/hooks/duotone.js b/packages/block-editor/src/hooks/duotone.js index f018444de0c67f..42a9374ac098bd 100644 --- a/packages/block-editor/src/hooks/duotone.js +++ b/packages/block-editor/src/hooks/duotone.js @@ -236,7 +236,7 @@ const withDuotoneControls = createHigherOrderComponent( [ props.clientId ] ); - const blockEditingMode = useBlockEditingMode( props.clientId ); + const blockEditingMode = useBlockEditingMode(); // CAUTION: code added before this line will be executed // for all blocks, not just those that support duotone. Code added diff --git a/packages/block-library/src/post-title/edit.js b/packages/block-library/src/post-title/edit.js index a30b01dee74569..3b54c58f838ea0 100644 --- a/packages/block-library/src/post-title/edit.js +++ b/packages/block-library/src/post-title/edit.js @@ -33,7 +33,6 @@ export default function PostTitleEdit( { setAttributes, context: { postType, postId, queryId }, insertBlocksAfter, - clientId, } ) { const TagName = 0 === level ? 'p' : 'h' + level; const isDescendentOfQueryLoop = Number.isFinite( queryId ); @@ -63,7 +62,7 @@ export default function PostTitleEdit( { [ `has-text-align-${ textAlign }` ]: textAlign, } ), } ); - const blockEditingMode = useBlockEditingMode( clientId ); + const blockEditingMode = useBlockEditingMode(); let titleElement = ( { __( 'Post Title' ) } From 6ab13d7787725be1a1334693962e802e9ebb7c96 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Mon, 22 May 2023 11:20:56 +1000 Subject: [PATCH 03/44] Remove rootBlockEditingMode setting --- .../src/components/block-editing-mode/index.js | 2 +- packages/block-editor/src/store/private-actions.js | 4 ++-- packages/block-editor/src/store/private-selectors.js | 10 ++-------- packages/block-editor/src/store/reducer.js | 7 +++++-- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/packages/block-editor/src/components/block-editing-mode/index.js b/packages/block-editor/src/components/block-editing-mode/index.js index 056721209ddfc8..82a77811429450 100644 --- a/packages/block-editor/src/components/block-editing-mode/index.js +++ b/packages/block-editor/src/components/block-editing-mode/index.js @@ -12,7 +12,7 @@ import { unlock } from '../../lock-unlock'; import { BlockListBlockContext } from '../block-list/block'; export function useBlockEditingMode( mode ) { - const { clientId } = useContext( BlockListBlockContext ); + const { clientId = '' } = useContext( BlockListBlockContext ) ?? {}; const blockEditingMode = useSelect( ( select ) => unlock( select( blockEditorStore ) ).getBlockEditingMode( diff --git a/packages/block-editor/src/store/private-actions.js b/packages/block-editor/src/store/private-actions.js index 496562687118b1..aa2030c1dcc525 100644 --- a/packages/block-editor/src/store/private-actions.js +++ b/packages/block-editor/src/store/private-actions.js @@ -67,7 +67,7 @@ export function showBlockInterface() { }; } -export function setBlockEditingMode( clientId, mode ) { +export function setBlockEditingMode( clientId = '', mode ) { return { type: 'SET_BLOCK_EDITING_MODE', clientId, @@ -75,7 +75,7 @@ export function setBlockEditingMode( clientId, mode ) { }; } -export function unsetBlockEditingMode( clientId ) { +export function unsetBlockEditingMode( clientId = '' ) { return { type: 'UNSET_BLOCK_EDITING_MODE', clientId, diff --git a/packages/block-editor/src/store/private-selectors.js b/packages/block-editor/src/store/private-selectors.js index 8f9af5df0b692e..b7b63a9ea875be 100644 --- a/packages/block-editor/src/store/private-selectors.js +++ b/packages/block-editor/src/store/private-selectors.js @@ -19,18 +19,12 @@ export function getLastInsertedBlocksClientIds( state ) { return state?.lastBlockInserted?.clientIds; } -export function getBlockEditingMode( state, clientId ) { - if ( ! clientId ) { - return state.settings.rootBlockEditingMode; - } +export function getBlockEditingMode( state, clientId = '' ) { while ( ! state.blockEditingModes.has( clientId ) && state.blocks.parents.has( clientId ) ) { clientId = state.blocks.parents.get( clientId ); } - return ( - state.blockEditingModes.get( clientId ) ?? - state.settings.rootBlockEditingMode - ); + return state.blockEditingModes.get( clientId ) ?? 'default'; } diff --git a/packages/block-editor/src/store/reducer.js b/packages/block-editor/src/store/reducer.js index f0c44244371c04..8bef78a07fa7ae 100644 --- a/packages/block-editor/src/store/reducer.js +++ b/packages/block-editor/src/store/reducer.js @@ -1843,8 +1843,11 @@ export function blockEditingModes( state = new Map(), action ) { newState.delete( action.clientId ); return newState; } - case 'RESET_BLOCKS': - return new Map(); + case 'RESET_BLOCKS': { + return state.has( '' ) + ? new Map().set( '', state.get( '' ) ) + : state; + } } return state; } From 6426fca4057250adecd31c8c9d554c07329107da Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Mon, 22 May 2023 13:57:35 +1000 Subject: [PATCH 04/44] Fix private createRegistrySelector selectors --- packages/data/src/redux-store/index.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/data/src/redux-store/index.js b/packages/data/src/redux-store/index.js index c4dc12643673b6..50a0ade0d551c9 100644 --- a/packages/data/src/redux-store/index.js +++ b/packages/data/src/redux-store/index.js @@ -221,12 +221,14 @@ export default function createReduxStore( key, options ) { get: ( target, prop ) => { return ( mapSelectors( - mapValues( - privateSelectors, - ( selector ) => - ( state, ...args ) => - selector( state.root, ...args ) - ), + mapValues( privateSelectors, ( selector ) => { + if ( selector.isRegistrySelector ) { + selector.registry = registry; + } + + return ( state, ...args ) => + selector( state.root, ...args ); + } ), store )[ prop ] || selectors[ prop ] ); From bd2f478717f517e72a4dcc505cbef9b0d2f0cdac Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Mon, 22 May 2023 13:58:45 +1000 Subject: [PATCH 05/44] Consolidate templateLock=contentOnly logic into getBlockEditingMode --- .../src/components/block-list/block.js | 19 +----- .../block-list/use-in-between-inserter.js | 3 +- .../src/components/block-toolbar/index.js | 17 ++--- .../block-tools/block-contextual-toolbar.js | 4 -- .../components/use-block-drop-zone/index.js | 11 ++-- packages/block-editor/src/hooks/align.js | 16 +---- packages/block-editor/src/hooks/duotone.js | 19 +----- packages/block-editor/src/hooks/layout.js | 28 +++----- .../src/store/private-selectors.js | 66 ++++++++++++++++--- packages/block-library/src/image/edit.js | 31 +++++---- packages/block-library/src/image/image.js | 10 +-- packages/block-library/src/media-text/edit.js | 22 ++++--- .../src/media-text/media-container.js | 6 +- 13 files changed, 124 insertions(+), 128 deletions(-) diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index d331fe7e541f30..185c8791a27e47 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -18,7 +18,6 @@ import { isUnmodifiedDefaultBlock, serializeRawBlock, switchToBlockType, - store as blocksStore, getDefaultBlockName, isUnmodifiedBlock, } from '@wordpress/blocks'; @@ -101,33 +100,23 @@ function BlockListBlock( { } ) { const { themeSupportsLayout, - hasContentLockedParent, - isContentBlock, isTemporarilyEditingAsBlocks, blockEditingMode, } = useSelect( ( select ) => { const { getSettings, - __unstableGetContentLockingParent, __unstableGetTemporarilyEditingAsBlocks, getBlockEditingMode, } = unlock( select( blockEditorStore ) ); - const _hasContentLockedParent = - !! __unstableGetContentLockingParent( clientId ); return { themeSupportsLayout: getSettings().supportsLayout, - isContentBlock: - select( blocksStore ).__experimentalHasContentRoleAttribute( - name - ), - hasContentLockedParent: _hasContentLockedParent, isTemporarilyEditingAsBlocks: __unstableGetTemporarilyEditingAsBlocks() === clientId, blockEditingMode: getBlockEditingMode( clientId ), }; }, - [ name, clientId ] + [ clientId ] ); const { removeBlock } = useDispatch( blockEditorStore ); const onRemove = useCallback( () => removeBlock( clientId ), [ clientId ] ); @@ -160,7 +149,7 @@ function BlockListBlock( { const blockType = getBlockType( name ); - if ( hasContentLockedParent && ! isContentBlock ) { + if ( blockEditingMode === 'disabled' ) { wrapperProps = { ...wrapperProps, tabIndex: -1, @@ -234,9 +223,7 @@ function BlockListBlock( { clientId, className: classnames( { - 'is-editing-disabled': - blockEditingMode === 'disabled' || - ( hasContentLockedParent && ! isContentBlock ), + 'is-editing-disabled': blockEditingMode === 'disabled', 'is-content-locked-temporarily-editing-as-blocks': isTemporarilyEditingAsBlocks, }, diff --git a/packages/block-editor/src/components/block-list/use-in-between-inserter.js b/packages/block-editor/src/components/block-list/use-in-between-inserter.js index 854d1dc7ca86a1..2c1d8736ceefdb 100644 --- a/packages/block-editor/src/components/block-list/use-in-between-inserter.js +++ b/packages/block-editor/src/components/block-list/use-in-between-inserter.js @@ -76,7 +76,8 @@ export function useInBetweenInserter() { rootClientId = blockElement.getAttribute( 'data-block' ); } - // Don't set the insertion point if the root is locked. + // Don't show the in-between inserter if the container block is + // locked or disabled. if ( getTemplateLock( rootClientId ) || getBlockEditingMode( rootClientId ) === 'disabled' diff --git a/packages/block-editor/src/components/block-toolbar/index.js b/packages/block-editor/src/components/block-toolbar/index.js index af5fe6f509b582..4dc53aae0afffc 100644 --- a/packages/block-editor/src/components/block-toolbar/index.js +++ b/packages/block-editor/src/components/block-toolbar/index.js @@ -43,7 +43,7 @@ const BlockToolbar = ( { hideDragHandle } ) => { isDistractionFree, isValid, isVisual, - isContentLocked, + blockEditingMode, } = useSelect( ( select ) => { const { getBlockName, @@ -52,7 +52,6 @@ const BlockToolbar = ( { hideDragHandle } ) => { isBlockValid, getBlockRootClientId, getSettings, - __unstableGetContentLockingParent, getBlockEditingMode, } = unlock( select( blockEditorStore ) ); const selectedBlockClientIds = getSelectedBlockClientIds(); @@ -75,9 +74,7 @@ const BlockToolbar = ( { hideDragHandle } ) => { isVisual: selectedBlockClientIds.every( ( id ) => getBlockMode( id ) === 'visual' ), - isContentLocked: - !! __unstableGetContentLockingParent( selectedBlockClientId ) || - getBlockEditingMode( selectedBlockClientId ) !== 'default', + blockEditingMode: getBlockEditingMode( selectedBlockClientId ), }; }, [] ); @@ -127,12 +124,12 @@ const BlockToolbar = ( { hideDragHandle } ) => { return (
- { ! isMultiToolbar && isLargeViewport && ! isContentLocked && ( - - ) } + { ! isMultiToolbar && + isLargeViewport && + blockEditingMode === 'default' && }
{ ( shouldShowVisualToolbar || isMultiToolbar ) && - ! isContentLocked && ( + blockEditingMode === 'default' && ( { ! isMultiToolbar && ( @@ -177,7 +174,7 @@ const BlockToolbar = ( { hideDragHandle } ) => { ) } - { ! isContentLocked && ( + { blockEditingMode === 'default' && ( ) }
diff --git a/packages/block-editor/src/components/block-tools/block-contextual-toolbar.js b/packages/block-editor/src/components/block-tools/block-contextual-toolbar.js index d709869de52b2e..d9c06f0324701c 100644 --- a/packages/block-editor/src/components/block-tools/block-contextual-toolbar.js +++ b/packages/block-editor/src/components/block-tools/block-contextual-toolbar.js @@ -39,7 +39,6 @@ function BlockContextualToolbar( { focusOnMount, isFixed, ...props } ) { getBlockName, getBlockParents, getSelectedBlockClientIds, - __unstableGetContentLockingParent, getBlockEditingMode, } = unlock( select( blockEditorStore ) ); const { getBlockType } = select( blocksStore ); @@ -64,9 +63,6 @@ function BlockContextualToolbar( { focusOnMount, isFixed, ...props } ) { true ) && selectedBlockClientIds.length <= 1 && - ! __unstableGetContentLockingParent( - _selectedBlockClientId - ) && getBlockEditingMode( _selectedBlockClientId ) === 'default', }; }, [] ); diff --git a/packages/block-editor/src/components/use-block-drop-zone/index.js b/packages/block-editor/src/components/use-block-drop-zone/index.js index d0700bd8d05abb..75f1de2b03e594 100644 --- a/packages/block-editor/src/components/use-block-drop-zone/index.js +++ b/packages/block-editor/src/components/use-block-drop-zone/index.js @@ -19,6 +19,7 @@ import { isPointContainedByRect, } from '../../utils/math'; import { store as blockEditorStore } from '../../store'; +import { unlock } from '../../lock-unlock'; /** @typedef {import('../../utils/math').WPPoint} WPPoint */ /** @typedef {import('../use-on-block-drop/types').WPDropOperation} WPDropOperation */ @@ -150,15 +151,13 @@ export default function useBlockDropZone( { const isDisabled = useSelect( ( select ) => { const { - getTemplateLock, __unstableIsWithinBlockOverlay, __unstableHasActiveBlockOverlayActive, - } = select( blockEditorStore ); - const templateLock = getTemplateLock( targetRootClientId ); + getBlockEditingMode, + } = unlock( select( blockEditorStore ) ); + const blockEditingMode = getBlockEditingMode( targetRootClientId ); return ( - [ 'all', 'contentOnly' ].some( - ( lock ) => lock === templateLock - ) || + blockEditingMode !== 'default' || __unstableHasActiveBlockOverlayActive( targetRootClientId ) || __unstableIsWithinBlockOverlay( targetRootClientId ) ); diff --git a/packages/block-editor/src/hooks/align.js b/packages/block-editor/src/hooks/align.js index 58c076fd8e21c8..a417d11d900431 100644 --- a/packages/block-editor/src/hooks/align.js +++ b/packages/block-editor/src/hooks/align.js @@ -13,14 +13,12 @@ import { getBlockType, hasBlockSupport, } from '@wordpress/blocks'; -import { useSelect } from '@wordpress/data'; /** * Internal dependencies */ import { BlockControls, BlockAlignmentControl } from '../components'; import useAvailableAlignments from '../components/block-alignment-control/use-available-alignments'; -import { store as blockEditorStore } from '../store'; import { useBlockEditingMode } from '../components/block-editing-mode'; /** @@ -134,20 +132,8 @@ export const withToolbarControls = createHigherOrderComponent( const validAlignments = useAvailableAlignments( blockAllowedAlignments ).map( ( { name } ) => name ); - const isContentLocked = useSelect( - ( select ) => { - return select( - blockEditorStore - ).__unstableGetContentLockingParent( props.clientId ); - }, - [ props.clientId ] - ); const blockEditingMode = useBlockEditingMode(); - if ( - ! validAlignments.length || - isContentLocked || - blockEditingMode !== 'default' - ) { + if ( ! validAlignments.length || blockEditingMode !== 'default' ) { return blockEdit; } diff --git a/packages/block-editor/src/hooks/duotone.js b/packages/block-editor/src/hooks/duotone.js index 42a9374ac098bd..2ecd35c99ee8c4 100644 --- a/packages/block-editor/src/hooks/duotone.js +++ b/packages/block-editor/src/hooks/duotone.js @@ -16,7 +16,6 @@ import { import { createHigherOrderComponent, useInstanceId } from '@wordpress/compose'; import { addFilter } from '@wordpress/hooks'; import { useMemo, useContext, createPortal } from '@wordpress/element'; -import { useSelect } from '@wordpress/data'; /** * Internal dependencies @@ -36,7 +35,6 @@ import { import { getBlockCSSSelector } from '../components/global-styles/get-block-css-selector'; import { scopeSelector } from '../components/global-styles/utils'; import { useBlockSettings } from './utils'; -import { store as blockEditorStore } from '../store'; import { default as StylesFiltersPanel } from '../components/global-styles/filters-panel'; import { useBlockEditingMode } from '../components/block-editing-mode'; @@ -227,15 +225,6 @@ const withDuotoneControls = createHigherOrderComponent( 'filter.duotone' ); - const isContentLocked = useSelect( - ( select ) => { - return select( - blockEditorStore - ).__unstableGetContentLockingParent( props.clientId ); - }, - [ props.clientId ] - ); - const blockEditingMode = useBlockEditingMode(); // CAUTION: code added before this line will be executed @@ -244,11 +233,9 @@ const withDuotoneControls = createHigherOrderComponent( // performance. return ( <> - { hasDuotoneSupport && - ! isContentLocked && - blockEditingMode === 'default' && ( - - ) } + { hasDuotoneSupport && blockEditingMode === 'default' && ( + + ) } ); diff --git a/packages/block-editor/src/hooks/layout.js b/packages/block-editor/src/hooks/layout.js index 9b11e991004b39..815b36e785a81d 100644 --- a/packages/block-editor/src/hooks/layout.js +++ b/packages/block-editor/src/hooks/layout.js @@ -29,6 +29,7 @@ import useSetting from '../components/use-setting'; import { LayoutStyle } from '../components/block-list/layout'; import BlockList from '../components/block-list'; import { getLayoutType, getLayoutTypes } from '../layouts'; +import { useBlockEditingMode } from '../components/block-editing-mode'; const layoutBlockSupportKey = '__experimentalLayout'; @@ -131,25 +132,16 @@ export function useLayoutStyles( blockAttributes = {}, blockName, selector ) { return css; } -function LayoutPanel( { - clientId, - setAttributes, - attributes, - name: blockName, -} ) { +function LayoutPanel( { setAttributes, attributes, name: blockName } ) { const { layout } = attributes; const defaultThemeLayout = useSetting( 'layout' ); - const { themeSupportsLayout, isContentLocked } = useSelect( - ( select ) => { - const { getSettings, __unstableGetContentLockingParent } = - select( blockEditorStore ); - return { - themeSupportsLayout: getSettings().supportsLayout, - isContentLocked: __unstableGetContentLockingParent( clientId ), - }; - }, - [ clientId ] - ); + const { themeSupportsLayout } = useSelect( ( select ) => { + const { getSettings } = select( blockEditorStore ); + return { + themeSupportsLayout: getSettings().supportsLayout, + }; + }, [] ); + const blockEditingMode = useBlockEditingMode(); const layoutBlockSupport = getBlockSupport( blockName, @@ -270,7 +262,7 @@ function LayoutPanel( { ) } - { ! inherit && ! isContentLocked && layoutType && ( + { ! inherit && blockEditingMode === 'default' && layoutType && ( ( state, clientId ) => { + const explicitEditingMode = getExplcitBlockEditingMode( + state, + clientId + ); + const rootClientId = getBlockRootClientId( state, clientId ); + const templateLock = getTemplateLock( state, rootClientId ); + const name = getBlockName( state, clientId ); + const isContent = + select( blocksStore ).__experimentalHasContentRoleAttribute( name ); + if ( + explicitEditingMode === 'disabled' || + ( templateLock === 'contentOnly' && ! isContent ) + ) { + return 'disabled'; + } + if ( + explicitEditingMode === 'contentOnly' || + ( templateLock === 'contentOnly' && isContent ) + ) { + return 'contentOnly'; + } + return 'default'; } - return state.blockEditingModes.get( clientId ) ?? 'default'; -} +); + +const getExplcitBlockEditingMode = createSelector( + ( state, clientId = '' ) => { + while ( + ! state.blockEditingModes.has( clientId ) && + state.blocks.parents.has( clientId ) + ) { + clientId = state.blocks.parents.get( clientId ); + } + return state.blockEditingModes.get( clientId ) ?? 'default'; + }, + ( state ) => [ state.blockEditingModes, state.blocks.parents ] +); diff --git a/packages/block-library/src/image/edit.js b/packages/block-library/src/image/edit.js index c4d8de316ea997..95de37062c09a0 100644 --- a/packages/block-library/src/image/edit.js +++ b/packages/block-library/src/image/edit.js @@ -17,6 +17,7 @@ import { useBlockProps, store as blockEditorStore, __experimentalUseBorderProps as useBorderProps, + privateApis as blockEditorPrivateApis, } from '@wordpress/block-editor'; import { useEffect, useRef, useState } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; @@ -27,6 +28,7 @@ import { store as noticesStore } from '@wordpress/notices'; * Internal dependencies */ import Image from './image'; +import { unlock } from '../private-apis'; /** * Module constants @@ -39,6 +41,8 @@ import { ALLOWED_MEDIA_TYPES, } from './constants'; +const { useBlockEditingMode } = unlock( blockEditorPrivateApis ); + export const pickRelevantMediaFiles = ( image, size ) => { const imageProps = Object.fromEntries( Object.entries( image ?? {} ).filter( ( [ key ] ) => @@ -124,20 +128,15 @@ export function ImageEdit( { }, [ caption ] ); const ref = useRef(); - const { imageDefaultSize, mediaUpload, isContentLocked } = useSelect( - ( select ) => { - const { getSettings, __unstableGetContentLockingParent } = - select( blockEditorStore ); - const settings = getSettings(); - return { - imageDefaultSize: settings.imageDefaultSize, - mediaUpload: settings.mediaUpload, - isContentLocked: - !! __unstableGetContentLockingParent( clientId ), - }; - }, - [] - ); + const { imageDefaultSize, mediaUpload } = useSelect( ( select ) => { + const { getSettings } = select( blockEditorStore ); + const settings = getSettings(); + return { + imageDefaultSize: settings.imageDefaultSize, + mediaUpload: settings.mediaUpload, + }; + }, [] ); + const blockEditingMode = useBlockEditingMode(); const { createErrorNotice } = useDispatch( noticesStore ); function onUploadError( message ) { @@ -366,10 +365,10 @@ export function ImageEdit( { containerRef={ ref } context={ context } clientId={ clientId } - isContentLocked={ isContentLocked } + blockEditingMode={ blockEditingMode } /> ) } - { ! url && ! isContentLocked && ( + { ! url && blockEditingMode === 'default' && ( - { ! isContentLocked && ( + { blockEditingMode === 'default' && ( ) } - { ! isContentLocked && ( + { blockEditingMode === 'default' && ( { setShowCaption( ! showCaption ); diff --git a/packages/block-library/src/media-text/edit.js b/packages/block-library/src/media-text/edit.js index f2848a584d0d8a..dcf8eae4ecf5a9 100644 --- a/packages/block-library/src/media-text/edit.js +++ b/packages/block-library/src/media-text/edit.js @@ -18,6 +18,7 @@ import { __experimentalImageURLInputUI as ImageURLInputUI, __experimentalImageSizeControl as ImageSizeControl, store as blockEditorStore, + privateApis as blockEditorPrivateApis, } from '@wordpress/block-editor'; import { PanelBody, @@ -43,6 +44,9 @@ import { LINK_DESTINATION_ATTACHMENT, TEMPLATE, } from './constants'; +import { unlock } from '../private-apis'; + +const { useBlockEditingMode } = unlock( blockEditorPrivateApis ); // this limits the resize to a safe zone to avoid making broken layouts const applyWidthConstraints = ( width ) => @@ -126,7 +130,7 @@ function attributesFromMedia( { }; } -function MediaTextEdit( { attributes, isSelected, setAttributes, clientId } ) { +function MediaTextEdit( { attributes, isSelected, setAttributes } ) { const { focalPoint, href, @@ -147,13 +151,10 @@ function MediaTextEdit( { attributes, isSelected, setAttributes, clientId } ) { } = attributes; const mediaSizeSlug = attributes.mediaSizeSlug || DEFAULT_MEDIA_SIZE_SLUG; - const { imageSizes, image, isContentLocked } = useSelect( + const { imageSizes, image } = useSelect( ( select ) => { - const { __unstableGetContentLockingParent, getSettings } = - select( blockEditorStore ); + const { getSettings } = select( blockEditorStore ); return { - isContentLocked: - !! __unstableGetContentLockingParent( clientId ), image: mediaId && isSelected ? select( coreStore ).getMedia( mediaId, { @@ -163,8 +164,7 @@ function MediaTextEdit( { attributes, isSelected, setAttributes, clientId } ) { imageSizes: getSettings()?.imageSizes, }; }, - - [ isSelected, mediaId, clientId ] + [ isSelected, mediaId ] ); const refMediaContainer = useRef(); @@ -319,11 +319,13 @@ function MediaTextEdit( { attributes, isSelected, setAttributes, clientId } ) { { template: TEMPLATE, allowedBlocks } ); + const blockEditingMode = useBlockEditingMode(); + return ( <> { mediaTextGeneralSettings } - { ! isContentLocked && ( + { blockEditingMode === 'default' && ( <> { mediaPosition !== 'right' &&
} diff --git a/packages/block-library/src/media-text/media-container.js b/packages/block-library/src/media-text/media-container.js index e5a6270bad8dc9..951c0013b76ebc 100644 --- a/packages/block-library/src/media-text/media-container.js +++ b/packages/block-library/src/media-text/media-container.js @@ -109,7 +109,7 @@ function MediaContainer( props, ref ) { mediaWidth, onSelectMedia, onWidthChange, - isContentLocked, + enableResize, } = props; const isTemporaryMedia = ! mediaId && isBlobURL( mediaUrl ); @@ -128,8 +128,8 @@ function MediaContainer( props, ref ) { commitWidthChange( parseInt( elt.style.width ) ); }; const enablePositions = { - right: ! isContentLocked && mediaPosition === 'left', - left: ! isContentLocked && mediaPosition === 'right', + right: enableResize && mediaPosition === 'left', + left: enableResize && mediaPosition === 'right', }; const backgroundStyles = From f00dc257cebcbcf9d3a310c6a4c758f9661623ab Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Mon, 22 May 2023 14:42:32 +1000 Subject: [PATCH 06/44] Hide disabled blocks from List View --- .../src/components/list-view/block.js | 59 ++++++++----------- .../src/components/list-view/branch.js | 8 +-- .../list-view/use-list-view-client-ids.js | 25 ++++++-- 3 files changed, 46 insertions(+), 46 deletions(-) diff --git a/packages/block-editor/src/components/list-view/block.js b/packages/block-editor/src/components/list-view/block.js index 1afde32cf1ec61..e58c68445ac718 100644 --- a/packages/block-editor/src/components/list-view/block.js +++ b/packages/block-editor/src/components/list-view/block.js @@ -38,6 +38,7 @@ import { getBlockPositionDescription } from './utils'; import { store as blockEditorStore } from '../../store'; import useBlockDisplayInformation from '../use-block-display-information'; import { useBlockLock } from '../block-lock'; +import { unlock } from '../../lock-unlock'; function ListViewBlock( { block: { clientId }, @@ -59,31 +60,13 @@ function ListViewBlock( { const rowRef = useRef( null ); const [ isHovered, setIsHovered ] = useState( false ); - const { isLocked, isContentLocked, canEdit } = useBlockLock( clientId ); - const forceSelectionContentLock = useSelect( - ( select ) => { - if ( isSelected ) { - return false; - } - if ( ! isContentLocked ) { - return false; - } - return select( blockEditorStore ).hasSelectedInnerBlock( - clientId, - true - ); - }, - [ isContentLocked, clientId, isSelected ] - ); + const { isLocked, canEdit } = useBlockLock( clientId ); - const canExpand = isContentLocked ? false : canEdit; const isFirstSelectedBlock = - forceSelectionContentLock || - ( isSelected && selectedClientIds[ 0 ] === clientId ); + isSelected && selectedClientIds[ 0 ] === clientId; const isLastSelectedBlock = - forceSelectionContentLock || - ( isSelected && - selectedClientIds[ selectedClientIds.length - 1 ] === clientId ); + isSelected && + selectedClientIds[ selectedClientIds.length - 1 ] === clientId; const { toggleBlockHighlight } = useDispatch( blockEditorStore ); @@ -97,15 +80,21 @@ function ListViewBlock( { ( select ) => select( blockEditorStore ).getBlockName( clientId ), [ clientId ] ); - - // When a block hides its toolbar it also hides the block settings menu, - // since that menu is part of the toolbar in the editor canvas. - // List View respects this by also hiding the block settings menu. - const showBlockActions = hasBlockSupport( - blockName, - '__experimentalToolbar', - true + const blockEditingMode = useSelect( + ( select ) => + unlock( select( blockEditorStore ) ).getBlockEditingMode( + clientId + ), + [ clientId ] ); + + const showBlockActions = + // When a block hides its toolbar it also hides the block settings menu, + // since that menu is part of the toolbar in the editor canvas. + // List View respects this by also hiding the block settings menu. + hasBlockSupport( blockName, '__experimentalToolbar', true ) && + // Don't show the settings menu if block is disabled or content only. + blockEditingMode === 'default'; const instanceId = useInstanceId( ListViewBlock ); const descriptionId = `list-view-block-select-button__${ instanceId }`; const blockPositionDescription = getBlockPositionDescription( @@ -204,7 +193,7 @@ function ListViewBlock( { } const classes = classnames( { - 'is-selected': isSelected || forceSelectionContentLock, + 'is-selected': isSelected, 'is-first-selected': isFirstSelectedBlock, 'is-last-selected': isLastSelectedBlock, 'is-branch-selected': isBranchSelected, @@ -248,14 +237,14 @@ function ListViewBlock( { path={ path } id={ `list-view-${ listViewInstanceId }-block-${ clientId }` } data-block={ clientId } - data-expanded={ canExpand ? isExpanded : undefined } + data-expanded={ canEdit ? isExpanded : undefined } ref={ rowRef } > { ( { ref, tabIndex, onFocus } ) => (
@@ -272,7 +261,7 @@ function ListViewBlock( { currentlyEditingBlockInCanvas ? 0 : tabIndex } onFocus={ onFocus } - isExpanded={ canExpand ? isExpanded : undefined } + isExpanded={ canEdit ? isExpanded : undefined } selectedClientIds={ selectedClientIds } ariaLabel={ blockAriaLabel } ariaDescribedBy={ descriptionId } @@ -321,7 +310,7 @@ function ListViewBlock( { { showBlockActions && BlockSettingsMenu && ( { ( { ref, tabIndex, onFocus } ) => ( { + return tree.flatMap( ( { clientId, innerBlocks, ...rest } ) => { + if ( getBlockEditingMode( clientId ) === 'disabled' ) { + return removeDisabledBlocks( innerBlocks ); + } + return [ + { + clientId, + innerBlocks: removeDisabledBlocks( innerBlocks ), + ...rest, + }, + ]; + } ); + }; return { selectedClientIds: getSelectedBlockClientIds(), draggedClientIds: getDraggedBlockClientIds(), - clientIdsTree: blocks - ? blocks - : __unstableGetClientIdsTree( rootClientId ), + clientIdsTree: removeDisabledBlocks( + blocks ?? __unstableGetClientIdsTree( rootClientId ) + ), }; }, [ blocks, rootClientId ] From c7e128cc44c843a7e5e54f7aeb901da5b21f6002 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Mon, 22 May 2023 14:42:56 +1000 Subject: [PATCH 07/44] Hide disabled blocks from breadcrumbs --- .../src/components/block-breadcrumb/index.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/block-editor/src/components/block-breadcrumb/index.js b/packages/block-editor/src/components/block-breadcrumb/index.js index 419d4c729b17d2..9e4ab5391d8c44 100644 --- a/packages/block-editor/src/components/block-breadcrumb/index.js +++ b/packages/block-editor/src/components/block-breadcrumb/index.js @@ -11,6 +11,7 @@ import { chevronRightSmall, Icon } from '@wordpress/icons'; */ import BlockTitle from '../block-title'; import { store as blockEditorStore } from '../../store'; +import { unlock } from '../../lock-unlock'; /** * Block breadcrumb component, displaying the hierarchy of the current block selection as a breadcrumb. @@ -22,11 +23,18 @@ import { store as blockEditorStore } from '../../store'; function BlockBreadcrumb( { rootLabelText } ) { const { selectBlock, clearSelectedBlock } = useDispatch( blockEditorStore ); const { clientId, parents, hasSelection } = useSelect( ( select ) => { - const { getSelectionStart, getSelectedBlockClientId, getBlockParents } = - select( blockEditorStore ); + const { + getSelectionStart, + getSelectedBlockClientId, + getBlockParents, + getBlockEditingMode, + } = unlock( select( blockEditorStore ) ); const selectedBlockClientId = getSelectedBlockClientId(); return { - parents: getBlockParents( selectedBlockClientId ), + parents: getBlockParents( selectedBlockClientId ).filter( + ( parentClientId ) => + getBlockEditingMode( parentClientId ) !== 'disabled' + ), clientId: selectedBlockClientId, hasSelection: !! getSelectionStart().clientId, }; From 2a9b9e533bb4422a6cdfbdbf63da4e1384ffadf2 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Mon, 22 May 2023 15:29:04 +1000 Subject: [PATCH 08/44] Add doc comments --- .../components/block-editing-mode/index.js | 31 ++++++++ .../block-editor/src/store/private-actions.js | 20 +++++ .../src/store/private-selectors.js | 77 +++++++++++++------ packages/block-editor/src/store/reducer.js | 8 ++ 4 files changed, 113 insertions(+), 23 deletions(-) diff --git a/packages/block-editor/src/components/block-editing-mode/index.js b/packages/block-editor/src/components/block-editing-mode/index.js index 82a77811429450..94de18dd9d5620 100644 --- a/packages/block-editor/src/components/block-editing-mode/index.js +++ b/packages/block-editor/src/components/block-editing-mode/index.js @@ -11,6 +11,37 @@ import { store as blockEditorStore } from '../../store'; import { unlock } from '../../lock-unlock'; import { BlockListBlockContext } from '../block-list/block'; +/** + * Allows a block to restrict the user interface that is displayed for editing + * that block and its inner blocks. + * + * @example + * ```js + * function MyBlock( { attributes, setAttributes } ) { + * useBlockEditingMode( 'disabled' ); + * return
; + * } + * ``` + * + * `mode` can be one of three options: + * + * - `'disabled'`: Prevents editing the block entirely, i.e. it cannot be + * selected. + * - `'contentOnly'`: Hides all non-content UI, e.g. auxiliary controls in the + * toolbar, the block movers, block settings. + * - `'default'`: Allows editing the block as normal. + * + * The mode is inherited by all of the block's inner blocks, unless they have + * their own mode. + * + * If called outside of a block context, the mode is applied to all blocks. + * + * @param {?string} mode The editing mode to apply. If undefined, the current + * editing mode is not changed. One of `'disabled'`, + * `'contentOnly'`, or `'default'`. + * + * @return {string} The current editing mode. + */ export function useBlockEditingMode( mode ) { const { clientId = '' } = useContext( BlockListBlockContext ) ?? {}; const blockEditingMode = useSelect( diff --git a/packages/block-editor/src/store/private-actions.js b/packages/block-editor/src/store/private-actions.js index aa2030c1dcc525..593086ff120ba6 100644 --- a/packages/block-editor/src/store/private-actions.js +++ b/packages/block-editor/src/store/private-actions.js @@ -67,6 +67,17 @@ export function showBlockInterface() { }; } +/** + * Sets the block editing mode for a given block. + * + * @see useBlockEditingMode + * + * @param {string} clientId The block client ID, or `''` for the root container. + * @param {string} mode The block editing mode. One of `'disabled'`, + * `'contentOnly'`, or `'default'`. + * + * @return {Object} Action object. + */ export function setBlockEditingMode( clientId = '', mode ) { return { type: 'SET_BLOCK_EDITING_MODE', @@ -75,6 +86,15 @@ export function setBlockEditingMode( clientId = '', mode ) { }; } +/** + * Clears the block editing mode for a given block. + * + * @see useBlockEditingMode + * + * @param {string} clientId The block client ID, or `''` for the root container. + * + * @return {Object} Action object. + */ export function unsetBlockEditingMode( clientId = '' ) { return { type: 'UNSET_BLOCK_EDITING_MODE', diff --git a/packages/block-editor/src/store/private-selectors.js b/packages/block-editor/src/store/private-selectors.js index 6cdb77ec83de6d..f33e9e55e30451 100644 --- a/packages/block-editor/src/store/private-selectors.js +++ b/packages/block-editor/src/store/private-selectors.js @@ -39,31 +39,62 @@ export function getLastInsertedBlocksClientIds( state ) { return state?.lastBlockInserted?.clientIds; } +/** + * Returns the block editing mode for a given block. + * + * The mode can be one of three options: + * + * - `'disabled'`: Prevents editing the block entirely, i.e. it cannot be + * selected. + * - `'contentOnly'`: Hides all non-content UI, e.g. auxiliary controls in the + * toolbar, the block movers, block settings. + * - `'default'`: Allows editing the block as normal. + * + * Blocks can set a mode using the `useBlockEditingMode` hook. + * + * The mode is inherited by all of the block's inner blocks, unless they have + * their own mode. + * + * A template lock can also set a mode. If the template lock is `'contentOnly'`, + * the block's mode is overridden to `'contentOnly'` if the block has a content + * role attribute, or `'disabled'` otherwise. + * + * @see useBlockEditingMode + * + * @param {Object} state Global application state. + * @param {string} clientId The block client ID, or `''` for the root container. + * + * @return {string} The block editing mode. One of `'disabled'`, + * `'contentOnly'`, or `'default'`. + */ export const getBlockEditingMode = createRegistrySelector( - ( select ) => ( state, clientId ) => { - const explicitEditingMode = getExplcitBlockEditingMode( - state, - clientId - ); - const rootClientId = getBlockRootClientId( state, clientId ); - const templateLock = getTemplateLock( state, rootClientId ); - const name = getBlockName( state, clientId ); - const isContent = - select( blocksStore ).__experimentalHasContentRoleAttribute( name ); - if ( - explicitEditingMode === 'disabled' || - ( templateLock === 'contentOnly' && ! isContent ) - ) { - return 'disabled'; - } - if ( - explicitEditingMode === 'contentOnly' || - ( templateLock === 'contentOnly' && isContent ) - ) { - return 'contentOnly'; + ( select ) => + ( state, clientId = '' ) => { + const explicitEditingMode = getExplcitBlockEditingMode( + state, + clientId + ); + const rootClientId = getBlockRootClientId( state, clientId ); + const templateLock = getTemplateLock( state, rootClientId ); + const name = getBlockName( state, clientId ); + const isContent = + select( blocksStore ).__experimentalHasContentRoleAttribute( + name + ); + if ( + explicitEditingMode === 'disabled' || + ( templateLock === 'contentOnly' && ! isContent ) + ) { + return 'disabled'; + } + if ( + explicitEditingMode === 'contentOnly' || + ( templateLock === 'contentOnly' && isContent ) + ) { + return 'contentOnly'; + } + return 'default'; } - return 'default'; - } ); const getExplcitBlockEditingMode = createSelector( diff --git a/packages/block-editor/src/store/reducer.js b/packages/block-editor/src/store/reducer.js index 8bef78a07fa7ae..b316bbeb5079e1 100644 --- a/packages/block-editor/src/store/reducer.js +++ b/packages/block-editor/src/store/reducer.js @@ -1834,6 +1834,14 @@ export function temporarilyEditingAsBlocks( state = '', action ) { return state; } +/** + * Reducer returning a map of block client IDs to block editing modes. + * + * @param {Map} state Current state. + * @param {Object} action Dispatched action. + * + * @return {Map} Updated state. + */ export function blockEditingModes( state = new Map(), action ) { switch ( action.type ) { case 'SET_BLOCK_EDITING_MODE': From 692cd768b374ba77516c7ed05afe7a88e54a50cb Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Tue, 23 May 2023 11:32:29 +1000 Subject: [PATCH 09/44] Add unit tests --- .../src/store/test/private-actions.js | 33 +++- .../src/store/test/private-selectors.js | 158 ++++++++++++++++++ .../block-editor/src/store/test/reducer.js | 48 ++++++ 3 files changed, 238 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/store/test/private-actions.js b/packages/block-editor/src/store/test/private-actions.js index c4453547f6ce6a..fdfe993091fef7 100644 --- a/packages/block-editor/src/store/test/private-actions.js +++ b/packages/block-editor/src/store/test/private-actions.js @@ -1,7 +1,12 @@ /** * Internal dependencies */ -import { hideBlockInterface, showBlockInterface } from '../private-actions'; +import { + hideBlockInterface, + showBlockInterface, + setBlockEditingMode, + unsetBlockEditingMode, +} from '../private-actions'; describe( 'private actions', () => { describe( 'hideBlockInterface', () => { @@ -19,4 +24,30 @@ describe( 'private actions', () => { } ); } ); } ); + + describe( 'setBlockEditingMode', () => { + it( 'should return the SET_BLOCK_EDITING_MODE action', () => { + expect( + setBlockEditingMode( + '14501cc2-90a6-4f52-aa36-ab6e896135d1', + 'default' + ) + ).toEqual( { + type: 'SET_BLOCK_EDITING_MODE', + clientId: '14501cc2-90a6-4f52-aa36-ab6e896135d1', + mode: 'default', + } ); + } ); + } ); + + describe( 'unsetBlockEditingMode', () => { + it( 'should return the UNSET_BLOCK_EDITING_MODE action', () => { + expect( + unsetBlockEditingMode( '14501cc2-90a6-4f52-aa36-ab6e896135d1' ) + ).toEqual( { + type: 'UNSET_BLOCK_EDITING_MODE', + clientId: '14501cc2-90a6-4f52-aa36-ab6e896135d1', + } ); + } ); + } ); } ); diff --git a/packages/block-editor/src/store/test/private-selectors.js b/packages/block-editor/src/store/test/private-selectors.js index c5df265f75db35..0dcb89f5363c1c 100644 --- a/packages/block-editor/src/store/test/private-selectors.js +++ b/packages/block-editor/src/store/test/private-selectors.js @@ -4,6 +4,7 @@ import { isBlockInterfaceHidden, getLastInsertedBlocksClientIds, + getBlockEditingMode, } from '../private-selectors'; describe( 'private selectors', () => { @@ -49,4 +50,161 @@ describe( 'private selectors', () => { ] ); } ); } ); + + describe( 'getBlockEditingMode', () => { + const baseState = { + settings: {}, + blocks: { + byClientId: new Map( [ + [ '6cf70164-9097-4460-bcbf-200560546988', {} ], // Header + [ 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337', {} ], // Group + [ 'b26fc763-417d-4f01-b81c-2ec61e14a972', {} ], // | Post Title + [ '9b9c5c3f-2e46-4f02-9e14-9fe9515b958f', {} ], // | Post Content + [ 'b3247f75-fd94-4fef-97f9-5bfd162cc416', {} ], // | | Paragraph + [ 'e178812d-ce5e-48c7-a945-8ae4ffcbbb7c', {} ], // | | Paragraph + ] ), + parents: new Map( [ + [ '6cf70164-9097-4460-bcbf-200560546988', '' ], + [ 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337', '' ], + [ + 'b26fc763-417d-4f01-b81c-2ec61e14a972', + 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337', + ], + [ + '9b9c5c3f-2e46-4f02-9e14-9fe9515b958f', + 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337', + ], + [ + 'b3247f75-fd94-4fef-97f9-5bfd162cc416', + '9b9c5c3f-2e46-4f02-9e14-9fe9515b958f', + ], + [ + 'e178812d-ce5e-48c7-a945-8ae4ffcbbb7c', + '9b9c5c3f-2e46-4f02-9e14-9fe9515b958f', + ], + ] ), + }, + blockListSettings: { + 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337': {}, + '9b9c5c3f-2e46-4f02-9e14-9fe9515b958f': {}, + }, + blockEditingModes: new Map( [] ), + }; + + const __experimentalHasContentRoleAttribute = jest.fn( () => false ); + getBlockEditingMode.registry = { + select: jest.fn( () => ( { + __experimentalHasContentRoleAttribute, + } ) ), + }; + + it( 'should return default by default', () => { + expect( + getBlockEditingMode( + baseState, + 'b3247f75-fd94-4fef-97f9-5bfd162cc416' + ) + ).toBe( 'default' ); + } ); + + [ 'disabled', 'contentOnly' ].forEach( ( mode ) => { + it( `should return ${ mode } if explicitly set`, () => { + const state = { + ...baseState, + blockEditingModes: new Map( [ + [ 'b3247f75-fd94-4fef-97f9-5bfd162cc416', mode ], + ] ), + }; + expect( + getBlockEditingMode( + state, + 'b3247f75-fd94-4fef-97f9-5bfd162cc416' + ) + ).toBe( mode ); + } ); + + it( `should return ${ mode } if explicitly set on a parent`, () => { + const state = { + ...baseState, + blockEditingModes: new Map( [ + [ 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337', mode ], + ] ), + }; + expect( + getBlockEditingMode( + state, + 'b3247f75-fd94-4fef-97f9-5bfd162cc416' + ) + ).toBe( mode ); + } ); + + it( `should return ${ mode } if overriden by a parent`, () => { + const state = { + ...baseState, + blockEditingModes: new Map( [ + [ '', mode ], + [ 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337', 'default' ], + [ '9b9c5c3f-2e46-4f02-9e14-9fe9515b958f', mode ], + ] ), + }; + expect( + getBlockEditingMode( + state, + 'b3247f75-fd94-4fef-97f9-5bfd162cc416' + ) + ).toBe( mode ); + } ); + + it( `should return ${ mode } if explicitly set on root`, () => { + const state = { + ...baseState, + blockEditingModes: new Map( [ [ '', mode ] ] ), + }; + expect( + getBlockEditingMode( + state, + 'b3247f75-fd94-4fef-97f9-5bfd162cc416' + ) + ).toBe( mode ); + } ); + } ); + + it( 'should return disabled if parent is locked and the block has no content role', () => { + const state = { + ...baseState, + blockListSettings: { + ...baseState.blockListSettings, + '9b9c5c3f-2e46-4f02-9e14-9fe9515b958f': { + templateLock: 'contentOnly', + }, + }, + }; + __experimentalHasContentRoleAttribute.mockReturnValueOnce( false ); + expect( + getBlockEditingMode( + state, + 'b3247f75-fd94-4fef-97f9-5bfd162cc416' + ) + ).toBe( 'disabled' ); + } ); + + it( 'should return contentOnly if parent is locked and the block has a content role', () => { + const state = { + ...baseState, + blockListSettings: { + ...baseState.blockListSettings, + '9b9c5c3f-2e46-4f02-9e14-9fe9515b958f': { + templateLock: 'contentOnly', + }, + }, + }; + __experimentalHasContentRoleAttribute.mockReturnValueOnce( true ); + expect( + getBlockEditingMode( + state, + 'b3247f75-fd94-4fef-97f9-5bfd162cc416' + ) + ).toBe( 'contentOnly' ); + } ); + } ); } ); diff --git a/packages/block-editor/src/store/test/reducer.js b/packages/block-editor/src/store/test/reducer.js index 609cbb59c6e54b..67ed0ae69106d6 100644 --- a/packages/block-editor/src/store/test/reducer.js +++ b/packages/block-editor/src/store/test/reducer.js @@ -32,6 +32,7 @@ import { blockListSettings, lastBlockAttributesChange, lastBlockInserted, + blockEditingModes, } from '../reducer'; const noop = () => {}; @@ -3367,4 +3368,51 @@ describe( 'state', () => { expect( state ).toEqual( expectedState ); } ); } ); + + describe( 'blockEditingModes', () => { + it( 'should return an empty map by default', () => { + expect( blockEditingModes( undefined, {} ) ).toEqual( new Map() ); + } ); + + it( 'should set the editing mode for a block', () => { + const state = new Map(); + const newState = blockEditingModes( state, { + type: 'SET_BLOCK_EDITING_MODE', + clientId: '14501cc2-90a6-4f52-aa36-ab6e896135d1', + mode: 'default', + } ); + expect( newState ).toEqual( + new Map( [ + [ '14501cc2-90a6-4f52-aa36-ab6e896135d1', 'default' ], + ] ) + ); + } ); + + it( 'should clear the editing mode for a block', () => { + const state = new Map( [ + [ '14501cc2-90a6-4f52-aa36-ab6e896135d1', 'default' ], + ] ); + const newState = blockEditingModes( state, { + type: 'UNSET_BLOCK_EDITING_MODE', + clientId: '14501cc2-90a6-4f52-aa36-ab6e896135d1', + } ); + expect( newState ).toEqual( new Map() ); + } ); + + it( 'should clear editing modes when blocks are reset', () => { + const state = new Map( [ + [ '', 'disabled' ], + [ '14501cc2-90a6-4f52-aa36-ab6e896135d1', 'default' ], + ] ); + const newState = blockEditingModes( state, { + type: 'RESET_BLOCKS', + } ); + expect( newState ).toEqual( + new Map( [ + // Root mode should be maintained. + [ '', 'disabled' ], + ] ) + ); + } ); + } ); } ); From 8162afef4f40d8d9305433f626c34d13f08a6bef Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Tue, 23 May 2023 11:40:26 +1000 Subject: [PATCH 10/44] Use @typedef to document mode param --- .../src/components/block-editing-mode/index.js | 11 +++++++---- packages/block-editor/src/store/private-actions.js | 10 +++++++--- packages/block-editor/src/store/private-selectors.js | 8 ++++++-- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/packages/block-editor/src/components/block-editing-mode/index.js b/packages/block-editor/src/components/block-editing-mode/index.js index 94de18dd9d5620..a9bb85197619bf 100644 --- a/packages/block-editor/src/components/block-editing-mode/index.js +++ b/packages/block-editor/src/components/block-editing-mode/index.js @@ -11,6 +11,10 @@ import { store as blockEditorStore } from '../../store'; import { unlock } from '../../lock-unlock'; import { BlockListBlockContext } from '../block-list/block'; +/** + * @typedef {'disabled'|'contentOnly'|'default'} BlockEditingMode + */ + /** * Allows a block to restrict the user interface that is displayed for editing * that block and its inner blocks. @@ -36,11 +40,10 @@ import { BlockListBlockContext } from '../block-list/block'; * * If called outside of a block context, the mode is applied to all blocks. * - * @param {?string} mode The editing mode to apply. If undefined, the current - * editing mode is not changed. One of `'disabled'`, - * `'contentOnly'`, or `'default'`. + * @param {?BlockEditingMode} mode The editing mode to apply. If undefined, the + * current editing mode is not changed. * - * @return {string} The current editing mode. + * @return {BlockEditingMode} The current editing mode. */ export function useBlockEditingMode( mode ) { const { clientId = '' } = useContext( BlockListBlockContext ) ?? {}; diff --git a/packages/block-editor/src/store/private-actions.js b/packages/block-editor/src/store/private-actions.js index 593086ff120ba6..0a3484154e5a78 100644 --- a/packages/block-editor/src/store/private-actions.js +++ b/packages/block-editor/src/store/private-actions.js @@ -67,14 +67,18 @@ export function showBlockInterface() { }; } +/** + * @typedef {import('../components/block-editing-mode').BlockEditingMode} BlockEditingMode + */ + /** * Sets the block editing mode for a given block. * * @see useBlockEditingMode * - * @param {string} clientId The block client ID, or `''` for the root container. - * @param {string} mode The block editing mode. One of `'disabled'`, - * `'contentOnly'`, or `'default'`. + * @param {string} clientId The block client ID, or `''` for the root container. + * @param {BlockEditingMode} mode The block editing mode. One of `'disabled'`, + * `'contentOnly'`, or `'default'`. * * @return {Object} Action object. */ diff --git a/packages/block-editor/src/store/private-selectors.js b/packages/block-editor/src/store/private-selectors.js index f33e9e55e30451..ce7802036184e5 100644 --- a/packages/block-editor/src/store/private-selectors.js +++ b/packages/block-editor/src/store/private-selectors.js @@ -39,6 +39,10 @@ export function getLastInsertedBlocksClientIds( state ) { return state?.lastBlockInserted?.clientIds; } +/** + * @typedef {import('../components/block-editing-mode').BlockEditingMode} BlockEditingMode + */ + /** * Returns the block editing mode for a given block. * @@ -64,8 +68,8 @@ export function getLastInsertedBlocksClientIds( state ) { * @param {Object} state Global application state. * @param {string} clientId The block client ID, or `''` for the root container. * - * @return {string} The block editing mode. One of `'disabled'`, - * `'contentOnly'`, or `'default'`. + * @return {BlockEditingMode} The block editing mode. One of `'disabled'`, + * `'contentOnly'`, or `'default'`. */ export const getBlockEditingMode = createRegistrySelector( ( select ) => From 3d437a49228b1934841a98c991c8bec7a4c6c412 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Tue, 23 May 2023 12:42:43 +1000 Subject: [PATCH 11/44] Restore packages/components/package.json from trunk --- packages/components/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/package.json b/packages/components/package.json index b4e9713bbd74c0..0339100948a019 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -86,4 +86,4 @@ "publishConfig": { "access": "public" } -} +} \ No newline at end of file From 25f3e5828db82bdb8ca9443c9562cf9fbec0838c Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Tue, 23 May 2023 12:45:43 +1000 Subject: [PATCH 12/44] Restore packages/block-library/src/post-title/edit.js from trunk --- packages/block-library/src/post-title/edit.js | 35 ++++++++----------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/packages/block-library/src/post-title/edit.js b/packages/block-library/src/post-title/edit.js index 3b54c58f838ea0..8cd71881e06dec 100644 --- a/packages/block-library/src/post-title/edit.js +++ b/packages/block-library/src/post-title/edit.js @@ -12,7 +12,6 @@ import { InspectorControls, useBlockProps, PlainText, - privateApis as blockEditorPrivateApis, } from '@wordpress/block-editor'; import { ToggleControl, TextControl, PanelBody } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; @@ -24,9 +23,6 @@ import { useEntityProp } from '@wordpress/core-data'; */ import HeadingLevelDropdown from '../heading/heading-level-dropdown'; import { useCanEditEntity } from '../utils/hooks'; -import { unlock } from '../private-apis'; - -const { useBlockEditingMode } = unlock( blockEditorPrivateApis ); export default function PostTitleEdit( { attributes: { level, textAlign, isLink, rel, linkTarget }, @@ -62,7 +58,6 @@ export default function PostTitleEdit( { [ `has-text-align-${ textAlign }` ]: textAlign, } ), } ); - const blockEditingMode = useBlockEditingMode(); let titleElement = ( { __( 'Post Title' ) } @@ -119,22 +114,20 @@ export default function PostTitleEdit( { return ( <> - { blockEditingMode === 'default' && ( - - - setAttributes( { level: newLevel } ) - } - /> - { - setAttributes( { textAlign: nextAlign } ); - } } - /> - - ) } + + + setAttributes( { level: newLevel } ) + } + /> + { + setAttributes( { textAlign: nextAlign } ); + } } + /> + Date: Tue, 23 May 2023 14:52:40 +1000 Subject: [PATCH 13/44] Move BlockListBlockContext out of block.js so that it exists on mobile platforms --- .../src/components/block-editing-mode/index.js | 2 +- .../components/block-list/block-list-block-context.js | 6 ++++++ .../block-editor/src/components/block-list/block.js | 10 ++-------- .../src/components/block-list/use-block-props/index.js | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) create mode 100644 packages/block-editor/src/components/block-list/block-list-block-context.js diff --git a/packages/block-editor/src/components/block-editing-mode/index.js b/packages/block-editor/src/components/block-editing-mode/index.js index a9bb85197619bf..0347a9b7378d0e 100644 --- a/packages/block-editor/src/components/block-editing-mode/index.js +++ b/packages/block-editor/src/components/block-editing-mode/index.js @@ -9,7 +9,7 @@ import { useContext, useEffect } from '@wordpress/element'; */ import { store as blockEditorStore } from '../../store'; import { unlock } from '../../lock-unlock'; -import { BlockListBlockContext } from '../block-list/block'; +import { BlockListBlockContext } from '../block-list/block-list-block-context'; /** * @typedef {'disabled'|'contentOnly'|'default'} BlockEditingMode diff --git a/packages/block-editor/src/components/block-list/block-list-block-context.js b/packages/block-editor/src/components/block-list/block-list-block-context.js new file mode 100644 index 00000000000000..6fa09c6969ec59 --- /dev/null +++ b/packages/block-editor/src/components/block-list/block-list-block-context.js @@ -0,0 +1,6 @@ +/** + * WordPress dependencies + */ +import { createContext } from '@wordpress/element'; + +export const BlockListBlockContext = createContext( null ); diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index 9304840eef614b..aa1a40ef480579 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -6,12 +6,7 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { - createContext, - useMemo, - useCallback, - RawHTML, -} from '@wordpress/element'; +import { useMemo, useCallback, RawHTML } from '@wordpress/element'; import { getBlockType, getSaveContent, @@ -43,8 +38,7 @@ import { useBlockProps } from './use-block-props'; import { store as blockEditorStore } from '../../store'; import { useLayout } from './layout'; import { unlock } from '../../lock-unlock'; - -export const BlockListBlockContext = createContext(); +import { BlockListBlockContext } from './block-list-block-context'; /** * Merges wrapper props with special handling for classNames and styles. diff --git a/packages/block-editor/src/components/block-list/use-block-props/index.js b/packages/block-editor/src/components/block-list/use-block-props/index.js index ca6bb4355f52db..acc2bd7f510ede 100644 --- a/packages/block-editor/src/components/block-list/use-block-props/index.js +++ b/packages/block-editor/src/components/block-list/use-block-props/index.js @@ -21,7 +21,7 @@ import warning from '@wordpress/warning'; * Internal dependencies */ import useMovingAnimation from '../../use-moving-animation'; -import { BlockListBlockContext } from '../block'; +import { BlockListBlockContext } from '../block-list-block-context'; import { useFocusFirstElement } from './use-focus-first-element'; import { useIsHovered } from './use-is-hovered'; import { useBlockEditContext } from '../../block-edit/context'; From 6bf1ddd7d6cd8497402d9bab24dba9b2ac6403e4 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Tue, 23 May 2023 16:44:41 +1000 Subject: [PATCH 14/44] Site Editor: Add ability to focus on editing a page's content vs the page's template --- .../data/data-core-edit-site.md | 40 ++++++ packages/block-library/src/post-title/edit.js | 35 +++-- .../src/components/block-editor/index.js | 47 +++++-- .../edit-site/src/components/editor/index.js | 45 +++--- .../src/components/sidebar-edit-mode/index.js | 30 ++-- .../sidebar-edit-mode/page-panels/index.js | 93 +++++++++++++ .../sidebar-edit-mode/page-panels/style.scss | 10 ++ .../settings-header/index.js | 79 +++++++---- .../sidebar-edit-mode/sidebar-card/index.js | 34 +++++ .../sidebar-edit-mode/sidebar-card/style.scss | 34 +++++ .../index.js | 41 +++--- .../last-revision.js} | 0 .../style.scss | 34 +---- .../template-actions.js | 0 .../template-areas.js | 0 .../index.js | 128 ++++++++++++++++++ .../edit-site/src/hooks/block-editing-mode.js | 57 ++++++++ packages/edit-site/src/hooks/index.js | 1 + packages/edit-site/src/store/actions.js | 16 +++ packages/edit-site/src/store/reducer.js | 20 +++ packages/edit-site/src/store/selectors.js | 24 ++++ packages/edit-site/src/store/test/actions.js | 17 +++ packages/edit-site/src/store/test/reducer.js | 57 ++++++++ .../edit-site/src/store/test/selectors.js | 57 ++++++++ packages/edit-site/src/style.scss | 4 +- .../utils/remove-page-from-block-context.js | 7 + .../test/remove-page-from-block-context.js | 20 +++ 27 files changed, 791 insertions(+), 139 deletions(-) create mode 100644 packages/edit-site/src/components/sidebar-edit-mode/page-panels/index.js create mode 100644 packages/edit-site/src/components/sidebar-edit-mode/page-panels/style.scss create mode 100644 packages/edit-site/src/components/sidebar-edit-mode/sidebar-card/index.js create mode 100644 packages/edit-site/src/components/sidebar-edit-mode/sidebar-card/style.scss rename packages/edit-site/src/components/sidebar-edit-mode/{template-card => template-panel}/index.js (60%) rename packages/edit-site/src/components/sidebar-edit-mode/{template-revisions/index.js => template-panel/last-revision.js} (100%) rename packages/edit-site/src/components/sidebar-edit-mode/{template-card => template-panel}/style.scss (50%) rename packages/edit-site/src/components/sidebar-edit-mode/{template-card => template-panel}/template-actions.js (100%) rename packages/edit-site/src/components/sidebar-edit-mode/{template-card => template-panel}/template-areas.js (100%) create mode 100644 packages/edit-site/src/components/use-page-content-lock-notifications/index.js create mode 100644 packages/edit-site/src/hooks/block-editing-mode.js create mode 100644 packages/edit-site/src/utils/remove-page-from-block-context.js create mode 100644 packages/edit-site/src/utils/test/remove-page-from-block-context.js diff --git a/docs/reference-guides/data/data-core-edit-site.md b/docs/reference-guides/data/data-core-edit-site.md index 0dad03bbc8ca2a..aae6188cba2dd7 100644 --- a/docs/reference-guides/data/data-core-edit-site.md +++ b/docs/reference-guides/data/data-core-edit-site.md @@ -131,6 +131,18 @@ _Returns_ - `Object`: Settings. +### hasPageContentLock + +Whether or not the editor is locked so that only page content can be edited. + +_Parameters_ + +- _state_ `Object`: Global application state. + +_Returns_ + +- `boolean`: Whether or not the editor is locked. + ### isFeatureActive > **Deprecated** @@ -174,6 +186,22 @@ _Returns_ > **Deprecated** +### isPage + +Whether or not the editor has a page loaded into it. + +_Related_ + +- setPage + +_Parameters_ + +- _state_ `Object`: Global application state. + +_Returns_ + +- `boolean`: Whether or not the editor has a page loaded into it. + ### isSaveViewOpened Returns the current opened/closed state of the save panel. @@ -355,6 +383,18 @@ _Parameters_ - _featureName_ `string`: Feature name. +### togglePageContentLock + +Action that toggles whether or not the editor is locked so that only page content can be edited. + +_Parameters_ + +- _hasPageContentLock_ `boolean`: True to enable lock, false to disable, or undefined to toggle. + +_Returns_ + +- `Object`: Action object. + ### updateSettings Returns an action object used to update the settings. diff --git a/packages/block-library/src/post-title/edit.js b/packages/block-library/src/post-title/edit.js index 8cd71881e06dec..3b54c58f838ea0 100644 --- a/packages/block-library/src/post-title/edit.js +++ b/packages/block-library/src/post-title/edit.js @@ -12,6 +12,7 @@ import { InspectorControls, useBlockProps, PlainText, + privateApis as blockEditorPrivateApis, } from '@wordpress/block-editor'; import { ToggleControl, TextControl, PanelBody } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; @@ -23,6 +24,9 @@ import { useEntityProp } from '@wordpress/core-data'; */ import HeadingLevelDropdown from '../heading/heading-level-dropdown'; import { useCanEditEntity } from '../utils/hooks'; +import { unlock } from '../private-apis'; + +const { useBlockEditingMode } = unlock( blockEditorPrivateApis ); export default function PostTitleEdit( { attributes: { level, textAlign, isLink, rel, linkTarget }, @@ -58,6 +62,7 @@ export default function PostTitleEdit( { [ `has-text-align-${ textAlign }` ]: textAlign, } ), } ); + const blockEditingMode = useBlockEditingMode(); let titleElement = ( { __( 'Post Title' ) } @@ -114,20 +119,22 @@ export default function PostTitleEdit( { return ( <> - - - setAttributes( { level: newLevel } ) - } - /> - { - setAttributes( { textAlign: nextAlign } ); - } } - /> - + { blockEditingMode === 'default' && ( + + + setAttributes( { level: newLevel } ) + } + /> + { + setAttributes( { textAlign: nextAlign } ); + } } + /> + + ) } { - const { getSettings, getEditedPostType, getCanvasMode } = unlock( - select( editSiteStore ) - ); - - return { - storedSettings: getSettings( setIsInserterOpened ), - templateType: getEditedPostType(), - canvasMode: getCanvasMode(), - }; - }, - [ setIsInserterOpened ] - ); + const { storedSettings, templateType, canvasMode, hasPageContentLock } = + useSelect( + ( select ) => { + const { + getSettings, + getEditedPostType, + getCanvasMode, + hasPageContentLock: _hasPageContentLock, + } = unlock( select( editSiteStore ) ); + + return { + storedSettings: getSettings( setIsInserterOpened ), + templateType: getEditedPostType(), + canvasMode: getCanvasMode(), + hasPageContentLock: _hasPageContentLock(), + }; + }, + [ setIsInserterOpened ] + ); const settingsBlockPatterns = storedSettings.__experimentalAdditionalBlockPatterns ?? // WP 6.0 @@ -137,6 +145,7 @@ export default function BlockEditor() { contentRef, useClipboardHandler(), useTypingObserver(), + usePageContentLockNotifications(), ] ); const isMobileViewport = useViewportMatch( 'small', '<' ); const { clearSelectedBlock } = useDispatch( blockEditorStore ); @@ -162,6 +171,9 @@ export default function BlockEditor() { onChange={ onChange } useSubRegistry={ false } > + { hasPageContentLock && ( + + ) } @@ -215,3 +227,8 @@ export default function BlockEditor() { ); } + +function SetRootBlockEditingMode( { mode } ) { + useBlockEditingMode( mode ); + return null; +} diff --git a/packages/edit-site/src/components/editor/index.js b/packages/edit-site/src/components/editor/index.js index 44b31c6945f57f..2549fc5e00bd78 100644 --- a/packages/edit-site/src/components/editor/index.js +++ b/packages/edit-site/src/components/editor/index.js @@ -37,12 +37,12 @@ import WelcomeGuide from '../welcome-guide'; import StartTemplateOptions from '../start-template-options'; import { store as editSiteStore } from '../../store'; import { GlobalStylesRenderer } from '../global-styles-renderer'; - import useTitle from '../routes/use-title'; import CanvasSpinner from '../canvas-spinner'; import { unlock } from '../../private-apis'; import useEditedEntityRecord from '../use-edited-entity-record'; import { SidebarFixedBottomSlot } from '../sidebar-edit-mode/sidebar-fixed-bottom'; +import removePageFromBlockContext from '../../utils/remove-page-from-block-context'; const interfaceLabels = { /* translators: accessibility text for the editor content landmark region. */ @@ -74,6 +74,7 @@ export default function Editor( { isLoading } ) { isListViewOpen, showIconLabels, showBlockBreadcrumbs, + hasPageContentLock, } = useSelect( ( select ) => { const { getEditedPostContext, @@ -81,6 +82,7 @@ export default function Editor( { isLoading } ) { getCanvasMode, isInserterOpened, isListViewOpened, + hasPageContentLock: _hasPageContentLock, } = unlock( select( editSiteStore ) ); const { __unstableGetEditorMode } = select( blockEditorStore ); const { getActiveComplementaryArea } = select( interfaceStore ); @@ -105,6 +107,7 @@ export default function Editor( { isLoading } ) { 'core/edit-site', 'showBlockBreadcrumbs' ), + hasPageContentLock: _hasPageContentLock(), }; }, [] ); const { setEditedPostContext } = useDispatch( editSiteStore ); @@ -123,21 +126,14 @@ export default function Editor( { isLoading } ) { ? __( 'List View' ) : __( 'Block Library' ); const blockContext = useMemo( - () => ( { - ...context, - queryContext: [ - context?.queryContext || { page: 1 }, - ( newQueryContext ) => - setEditedPostContext( { - ...context, - queryContext: { - ...context?.queryContext, - ...newQueryContext, - }, - } ), - ], - } ), - [ context, setEditedPostContext ] + () => + addQueryContextToBlockContext( + hasPageContentLock + ? context + : removePageFromBlockContext( context ), + setEditedPostContext + ), + [ hasPageContentLock, context, setEditedPostContext ] ); let title; @@ -247,3 +243,20 @@ export default function Editor( { isLoading } ) { ); } + +function addQueryContextToBlockContext( context, setContext ) { + return { + ...context, + queryContext: [ + context?.queryContext || { page: 1 }, + ( newQueryContext ) => + setContext( { + ...context, + queryContext: { + ...context?.queryContext, + ...newQueryContext, + }, + } ), + ], + }; +} diff --git a/packages/edit-site/src/components/sidebar-edit-mode/index.js b/packages/edit-site/src/components/sidebar-edit-mode/index.js index 5086981f871447..78ada88a4d5fa8 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/index.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/index.js @@ -1,7 +1,7 @@ /** * WordPress dependencies */ -import { createSlotFill, PanelBody, PanelRow } from '@wordpress/components'; +import { createSlotFill } from '@wordpress/components'; import { isRTL, __ } from '@wordpress/i18n'; import { drawerLeft, drawerRight } from '@wordpress/icons'; import { useEffect } from '@wordpress/element'; @@ -16,8 +16,8 @@ import DefaultSidebar from './default-sidebar'; import GlobalStylesSidebar from './global-styles-sidebar'; import { STORE_NAME } from '../../store/constants'; import SettingsHeader from './settings-header'; -import LastRevision from './template-revisions'; -import TemplateCard from './template-card'; +import PagePanels from './page-panels'; +import TemplatePanel from './template-panel'; import PluginTemplateSettingPanel from '../plugin-template-setting-panel'; import { SIDEBAR_BLOCK, SIDEBAR_TEMPLATE } from './constants'; import { store as editSiteStore } from '../../store'; @@ -33,6 +33,7 @@ export function SidebarComplementaryAreaFills() { isEditorSidebarOpened, hasBlockSelection, supportsGlobalStyles, + hasPageContentLock, } = useSelect( ( select ) => { const _sidebar = select( interfaceStore ).getActiveComplementaryArea( STORE_NAME ); @@ -47,18 +48,23 @@ export function SidebarComplementaryAreaFills() { hasBlockSelection: !! select( blockEditorStore ).getBlockSelectionStart(), supportsGlobalStyles: ! settings?.supportsTemplatePartsMode, + hasPageContentLock: select( editSiteStore ).hasPageContentLock(), }; }, [] ); const { enableComplementaryArea } = useDispatch( interfaceStore ); useEffect( () => { - if ( ! isEditorSidebarOpened ) return; + // Don't automatically switch tab when the sidebar is closed or when we + // are focused on page content. + if ( ! isEditorSidebarOpened || hasPageContentLock ) { + return; + } if ( hasBlockSelection ) { enableComplementaryArea( STORE_NAME, SIDEBAR_BLOCK ); } else { enableComplementaryArea( STORE_NAME, SIDEBAR_TEMPLATE ); } - }, [ hasBlockSelection, isEditorSidebarOpened ] ); + }, [ hasBlockSelection, isEditorSidebarOpened, hasPageContentLock ] ); let sidebarName = sidebar; if ( ! isEditorSidebarOpened ) { @@ -77,15 +83,11 @@ export function SidebarComplementaryAreaFills() { > { sidebarName === SIDEBAR_TEMPLATE && ( <> - - - - - - + { hasPageContentLock ? ( + + ) : ( + + ) } ) } diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/index.js b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/index.js new file mode 100644 index 00000000000000..19329228be2172 --- /dev/null +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/index.js @@ -0,0 +1,93 @@ +/** + * WordPress dependencies + */ +import { + PanelBody, + __experimentalVStack as VStack, + Button, +} from '@wordpress/components'; +import { page as pageIcon } from '@wordpress/icons'; +import { __, sprintf } from '@wordpress/i18n'; +import { humanTimeDiff } from '@wordpress/date'; +import { useSelect, useDispatch } from '@wordpress/data'; +import { useEntityRecord } from '@wordpress/core-data'; +import { BlockContextProvider, BlockPreview } from '@wordpress/block-editor'; +import { useMemo } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import { store as editSiteStore } from '../../../store'; +import useEditedEntityRecord from '../../use-edited-entity-record'; +import removePageFromBlockContext from '../../../utils/remove-page-from-block-context'; +import SidebarCard from '../sidebar-card'; + +export default function PagePanels() { + const context = useSelect( + ( select ) => select( editSiteStore ).getEditedPostContext(), + [] + ); + + const { hasResolved: hasPageResolved, editedRecord: page } = + useEntityRecord( 'postType', context.postType, context.postId ); + + const { + isLoaded: isTemplateLoaded, + getTitle: getTemplateTitle, + record: template, + } = useEditedEntityRecord(); + + const { togglePageContentLock } = useDispatch( editSiteStore ); + + const blockContext = useMemo( + () => removePageFromBlockContext( context ), + [ context ] + ); + + if ( ! hasPageResolved || ! isTemplateLoaded ) { + return null; + } + + return ( + <> + + + + + TODO + { /* */ } + + + +
{ getTemplateTitle() }
+
+ + + +
+ +
+
+ + ); +} diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/style.scss b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/style.scss new file mode 100644 index 00000000000000..eaae34c57a9cbd --- /dev/null +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/style.scss @@ -0,0 +1,10 @@ +.edit-site-edit-template-panel__preview { + border: 1px solid $gray-200; + height: 200px; + max-height: 200px; + overflow: hidden; +} + +.edit-site-edit-template-panel__button { + justify-content: center; +} diff --git a/packages/edit-site/src/components/sidebar-edit-mode/settings-header/index.js b/packages/edit-site/src/components/sidebar-edit-mode/settings-header/index.js index 8e5e80d9fecc57..b11d9acb2314f0 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/settings-header/index.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/settings-header/index.js @@ -1,9 +1,14 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + /** * WordPress dependencies */ import { Button } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; -import { useDispatch } from '@wordpress/data'; +import { useSelect, useDispatch } from '@wordpress/data'; import { store as interfaceStore } from '@wordpress/interface'; /** @@ -11,27 +16,35 @@ import { store as interfaceStore } from '@wordpress/interface'; */ import { STORE_NAME } from '../../../store/constants'; import { SIDEBAR_BLOCK, SIDEBAR_TEMPLATE } from '../constants'; +import { store as editSiteStore } from '../../../store'; const SettingsHeader = ( { sidebarName } ) => { + const hasPageContentLock = useSelect( ( select ) => + select( editSiteStore ).hasPageContentLock() + ); + const { enableComplementaryArea } = useDispatch( interfaceStore ); const openTemplateSettings = () => enableComplementaryArea( STORE_NAME, SIDEBAR_TEMPLATE ); const openBlockSettings = () => enableComplementaryArea( STORE_NAME, SIDEBAR_BLOCK ); - const [ templateAriaLabel, templateActiveClass ] = - sidebarName === SIDEBAR_TEMPLATE - ? // translators: ARIA label for the Template sidebar tab, selected. - [ __( 'Template (selected)' ), 'is-active' ] - : // translators: ARIA label for the Template Settings Sidebar tab, not selected. - [ __( 'Template' ), '' ]; - - const [ blockAriaLabel, blockActiveClass ] = - sidebarName === SIDEBAR_BLOCK - ? // translators: ARIA label for the Block Settings Sidebar tab, selected. - [ __( 'Block (selected)' ), 'is-active' ] - : // translators: ARIA label for the Block Settings Sidebar tab, not selected. - [ __( 'Block' ), '' ]; + let templateAriaLabel; + if ( hasPageContentLock ) { + templateAriaLabel = + sidebarName === SIDEBAR_TEMPLATE + ? // translators: ARIA label for the Template sidebar tab, selected. + __( 'Page (selected)' ) + : // translators: ARIA label for the Template Settings Sidebar tab, not selected. + __( 'Page' ); + } else { + templateAriaLabel = + sidebarName === SIDEBAR_TEMPLATE + ? // translators: ARIA label for the Template sidebar tab, selected. + __( 'Template (selected)' ) + : // translators: ARIA label for the Template Settings Sidebar tab, not selected. + __( 'Template' ); + } /* Use a list so screen readers will announce how many tabs there are. */ return ( @@ -39,29 +52,39 @@ const SettingsHeader = ( { sidebarName } ) => {
  • diff --git a/packages/edit-site/src/components/sidebar-edit-mode/sidebar-card/index.js b/packages/edit-site/src/components/sidebar-edit-mode/sidebar-card/index.js new file mode 100644 index 00000000000000..04e8d5667a2c20 --- /dev/null +++ b/packages/edit-site/src/components/sidebar-edit-mode/sidebar-card/index.js @@ -0,0 +1,34 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + +/** + * WordPress dependencies + */ +import { Icon } from '@wordpress/components'; + +export default function SidebarCard( { + className, + title, + icon, + description, + actions, + children, +} ) { + return ( +
    + +
    +
    +

    { title }

    + { actions } +
    +
    + { description } +
    + { children } +
    +
    + ); +} diff --git a/packages/edit-site/src/components/sidebar-edit-mode/sidebar-card/style.scss b/packages/edit-site/src/components/sidebar-edit-mode/sidebar-card/style.scss new file mode 100644 index 00000000000000..718fe8fb5a0fbd --- /dev/null +++ b/packages/edit-site/src/components/sidebar-edit-mode/sidebar-card/style.scss @@ -0,0 +1,34 @@ +.edit-site-sidebar-card { + display: flex; + align-items: flex-start; + + &__content { + flex-grow: 1; + margin-bottom: $grid-unit-05; + } + + &__title { + font-weight: 500; + line-height: $icon-size; + &.edit-site-sidebar-card__title { + margin: 0; + } + } + + &__description { + font-size: $default-font-size; + } + + &__icon { + flex: 0 0 $icon-size; + margin-right: $grid-unit-15; + width: $icon-size; + height: $icon-size; + } + + &__header { + display: flex; + justify-content: space-between; + margin: 0 0 $grid-unit-05; + } +} diff --git a/packages/edit-site/src/components/sidebar-edit-mode/template-card/index.js b/packages/edit-site/src/components/sidebar-edit-mode/template-panel/index.js similarity index 60% rename from packages/edit-site/src/components/sidebar-edit-mode/template-card/index.js rename to packages/edit-site/src/components/sidebar-edit-mode/template-panel/index.js index d43dca3b803f52..1c369703be5d72 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/template-card/index.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/template-panel/index.js @@ -2,10 +2,11 @@ * WordPress dependencies */ import { useSelect } from '@wordpress/data'; -import { Icon } from '@wordpress/components'; +import { PanelRow, PanelBody } from '@wordpress/components'; import { store as editorStore } from '@wordpress/editor'; import { store as coreStore } from '@wordpress/core-data'; import { decodeEntities } from '@wordpress/html-entities'; +import { __ } from '@wordpress/i18n'; /** * Internal dependencies @@ -13,8 +14,10 @@ import { decodeEntities } from '@wordpress/html-entities'; import { store as editSiteStore } from '../../../store'; import TemplateActions from './template-actions'; import TemplateAreas from './template-areas'; +import LastRevision from './last-revision'; +import SidebarCard from '../sidebar-card'; -export default function TemplateCard() { +export default function TemplatePanel() { const { info: { title, description, icon }, template, @@ -38,22 +41,22 @@ export default function TemplateCard() { } return ( - <> -
    - -
    -
    -

    - { decodeEntities( title ) } -

    - -
    -
    - { decodeEntities( description ) } -
    - -
    -
    - + + } + > + + + + + + ); } diff --git a/packages/edit-site/src/components/sidebar-edit-mode/template-revisions/index.js b/packages/edit-site/src/components/sidebar-edit-mode/template-panel/last-revision.js similarity index 100% rename from packages/edit-site/src/components/sidebar-edit-mode/template-revisions/index.js rename to packages/edit-site/src/components/sidebar-edit-mode/template-panel/last-revision.js diff --git a/packages/edit-site/src/components/sidebar-edit-mode/template-card/style.scss b/packages/edit-site/src/components/sidebar-edit-mode/template-panel/style.scss similarity index 50% rename from packages/edit-site/src/components/sidebar-edit-mode/template-card/style.scss rename to packages/edit-site/src/components/sidebar-edit-mode/template-panel/style.scss index 67054c25d2476c..4c8ef94855dcb1 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/template-card/style.scss +++ b/packages/edit-site/src/components/sidebar-edit-mode/template-panel/style.scss @@ -1,30 +1,6 @@ .edit-site-template-card { - display: flex; - align-items: flex-start; - - &__content { - flex-grow: 1; - margin-bottom: $grid-unit-05; - } - - &__title { - font-weight: 500; - line-height: $icon-size; - &.edit-site-template-card__title { - margin: 0; - } - } - - &__description { - font-size: $default-font-size; - margin: 0 0 $grid-unit-20; - } - - &__icon { - flex: 0 0 $icon-size; - margin-right: $grid-unit-15; - width: $icon-size; - height: $icon-size; + &__template-areas { + margin-top: $grid-unit-20; } &__template-areas-list { @@ -44,12 +20,6 @@ } } - &__header { - display: flex; - justify-content: space-between; - margin: 0 0 $grid-unit-05; - } - &__actions { line-height: 0; > .components-button.is-small.has-icon { diff --git a/packages/edit-site/src/components/sidebar-edit-mode/template-card/template-actions.js b/packages/edit-site/src/components/sidebar-edit-mode/template-panel/template-actions.js similarity index 100% rename from packages/edit-site/src/components/sidebar-edit-mode/template-card/template-actions.js rename to packages/edit-site/src/components/sidebar-edit-mode/template-panel/template-actions.js diff --git a/packages/edit-site/src/components/sidebar-edit-mode/template-card/template-areas.js b/packages/edit-site/src/components/sidebar-edit-mode/template-panel/template-areas.js similarity index 100% rename from packages/edit-site/src/components/sidebar-edit-mode/template-card/template-areas.js rename to packages/edit-site/src/components/sidebar-edit-mode/template-panel/template-areas.js diff --git a/packages/edit-site/src/components/use-page-content-lock-notifications/index.js b/packages/edit-site/src/components/use-page-content-lock-notifications/index.js new file mode 100644 index 00000000000000..32a10800fc4691 --- /dev/null +++ b/packages/edit-site/src/components/use-page-content-lock-notifications/index.js @@ -0,0 +1,128 @@ +/** + * WordPress dependencies + */ +import { useSelect, useDispatch } from '@wordpress/data'; +import { useEffect, useRef } from '@wordpress/element'; +import { store as noticesStore } from '@wordpress/notices'; +import { __ } from '@wordpress/i18n'; +import { useRefEffect } from '@wordpress/compose'; + +/** + * Internal dependencies + */ +import { store as editSiteStore } from '../../store'; + +/** + * Hook that displays notifications that guide the user towards using the + * content vs. template editing modes. + * + * @return {import('react').RefObject} Ref which should be passed + * (using useMergeRefs()) to + * the editor iframe canvas. + */ +export default function usePageContentLockNotifications() { + const ref = useEditTemplateNotification(); + useBackToPageNotification(); + return ref; +} + +/** + * Hook that displays a 'Edit your template to edit this block' notification + * when the user is focusing on editing page content and clicks on a locked + * template block. + * + * @return {import('react').RefObject} Ref which should be passed + * (using useMergeRefs()) to + * the editor iframe canvas. + */ +function useEditTemplateNotification() { + const hasPageContentLock = useSelect( + ( select ) => select( editSiteStore ).hasPageContentLock(), + [] + ); + + const alreadySeen = useRef( false ); + + const { createInfoNotice } = useDispatch( noticesStore ); + const { togglePageContentLock } = useDispatch( editSiteStore ); + + return useRefEffect( + ( node ) => { + const handleClick = ( event ) => { + if ( + ! alreadySeen.current && + hasPageContentLock && + event.target.classList.contains( 'is-root-container' ) + ) { + createInfoNotice( + __( 'Edit your template to edit this block' ), + { + isDismissible: true, + type: 'snackbar', + actions: [ + { + label: __( 'Edit template' ), + onClick: () => + togglePageContentLock( false ), + }, + ], + } + ); + alreadySeen.current = true; + } + }; + node.addEventListener( 'click', handleClick ); + return () => node.removeEventListener( 'click', handleClick ); + }, + [ + hasPageContentLock, + alreadySeen, + createInfoNotice, + togglePageContentLock, + ] + ); +} + +/** + * Hook that displays a 'You are editing a template' notification when the user + * switches from focusing on editing page content to editing a template. + */ +function useBackToPageNotification() { + const hasPageContentLock = useSelect( + ( select ) => select( editSiteStore ).hasPageContentLock(), + [] + ); + + const alreadySeen = useRef( false ); + const prevHasPageContentLock = useRef( false ); + + const { createInfoNotice } = useDispatch( noticesStore ); + const { togglePageContentLock } = useDispatch( editSiteStore ); + + useEffect( () => { + if ( + ! alreadySeen.current && + prevHasPageContentLock.current && + ! hasPageContentLock + ) { + createInfoNotice( __( 'You are editing a template' ), { + isDismissible: true, + type: 'snackbar', + actions: [ + { + label: __( 'Back to page' ), + onClick: () => togglePageContentLock( true ), + }, + ], + } ); + alreadySeen.current = true; + } + prevHasPageContentLock.current = hasPageContentLock; + }, [ + alreadySeen, + prevHasPageContentLock, + hasPageContentLock, + createInfoNotice, + togglePageContentLock, + ] ); +} diff --git a/packages/edit-site/src/hooks/block-editing-mode.js b/packages/edit-site/src/hooks/block-editing-mode.js new file mode 100644 index 00000000000000..2f3912d76eb35a --- /dev/null +++ b/packages/edit-site/src/hooks/block-editing-mode.js @@ -0,0 +1,57 @@ +/** + * WordPress dependencies + */ +import { createHigherOrderComponent } from '@wordpress/compose'; +import { addFilter } from '@wordpress/hooks'; +import { + store as blockEditorStore, + privateApis as blockEditorPrivateApis, +} from '@wordpress/block-editor'; +import { useSelect } from '@wordpress/data'; + +/** + * Internal dependencies + */ +import { unlock } from '../private-apis'; +import { store as editSiteStore } from '../store'; + +const { useBlockEditingMode } = unlock( blockEditorPrivateApis ); + +export const withBlockEditingMode = createHigherOrderComponent( + ( BlockEdit ) => ( props ) => { + const mode = useSelect( + ( select ) => { + if ( ! select( editSiteStore ).hasPageContentLock() ) { + return; + } + if ( + [ + 'core/post-title', + 'core/post-featured-image', + 'core/post-content', + ].includes( props.name ) + ) { + return 'contentOnly'; + } + if ( + select( blockEditorStore ).getBlockParentsByBlockName( + props.clientId, + 'core/post-content' + ).length + ) { + return 'default'; + } + }, + [ props.name, props.clientId ] + ); + useBlockEditingMode( mode ); + return ; + }, + 'withBlockEditingMode' +); + +addFilter( + 'editor.BlockEdit', + 'core/edit-site/block-editing-mode', + withBlockEditingMode +); diff --git a/packages/edit-site/src/hooks/index.js b/packages/edit-site/src/hooks/index.js index 513634c55b8f01..de9dc8c3f764d3 100644 --- a/packages/edit-site/src/hooks/index.js +++ b/packages/edit-site/src/hooks/index.js @@ -1,6 +1,7 @@ /** * Internal dependencies */ +import './block-editing-mode'; import './components'; import './push-changes-to-global-styles'; import './template-part-edit'; diff --git a/packages/edit-site/src/store/actions.js b/packages/edit-site/src/store/actions.js index d1f41d5a62aca5..542cb1831cfacc 100644 --- a/packages/edit-site/src/store/actions.js +++ b/packages/edit-site/src/store/actions.js @@ -529,3 +529,19 @@ export const switchEditorMode = speak( __( 'Code editor selected' ), 'assertive' ); } }; + +/** + * Action that toggles whether or not the editor is locked so that only page + * content can be edited. + * + * @param {boolean} hasPageContentLock True to enable lock, false to disable, or + * undefined to toggle. + * + * @return {Object} Action object. + */ +export function togglePageContentLock( hasPageContentLock ) { + return { + type: 'TOGGLE_PAGE_CONTENT_LOCK', + hasPageContentLock, + }; +} diff --git a/packages/edit-site/src/store/reducer.js b/packages/edit-site/src/store/reducer.js index a46d215f905074..1008afd95176f2 100644 --- a/packages/edit-site/src/store/reducer.js +++ b/packages/edit-site/src/store/reducer.js @@ -157,6 +157,25 @@ function editorCanvasContainerView( state = undefined, action ) { return state; } +/** + * Reducer used to track whether the page content is locked. + * + * @param {boolean} state Current state. + * @param {Object} action Dispatched action. + * + * @return {boolean} Updated state. + */ +export function hasPageContentLock( state = false, action ) { + switch ( action.type ) { + case 'SET_EDITED_POST': + return !! action.context?.postId; + case 'TOGGLE_PAGE_CONTENT_LOCK': + return action.hasPageContentLock ?? ! state; + } + + return state; +} + export default combineReducers( { deviceType, settings, @@ -166,4 +185,5 @@ export default combineReducers( { saveViewPanel, canvasMode, editorCanvasContainerView, + hasPageContentLock, } ); diff --git a/packages/edit-site/src/store/selectors.js b/packages/edit-site/src/store/selectors.js index 583f37b55241bd..16b6dc588ea26f 100644 --- a/packages/edit-site/src/store/selectors.js +++ b/packages/edit-site/src/store/selectors.js @@ -321,3 +321,27 @@ export function isNavigationOpened() { version: '6.4', } ); } + +/** + * Whether or not the editor has a page loaded into it. + * + * @see setPage + * + * @param {Object} state Global application state. + * + * @return {boolean} Whether or not the editor has a page loaded into it. + */ +export function isPage( state ) { + return !! state.editedPost.context?.postId; +} + +/** + * Whether or not the editor is locked so that only page content can be edited. + * + * @param {Object} state Global application state. + * + * @return {boolean} Whether or not the editor is locked. + */ +export function hasPageContentLock( state ) { + return isPage( state ) ? state.hasPageContentLock : false; +} diff --git a/packages/edit-site/src/store/test/actions.js b/packages/edit-site/src/store/test/actions.js index 2df1cc72b66115..159b13252f161a 100644 --- a/packages/edit-site/src/store/test/actions.js +++ b/packages/edit-site/src/store/test/actions.js @@ -13,6 +13,7 @@ import { store as preferencesStore } from '@wordpress/preferences'; * Internal dependencies */ import { store as editSiteStore } from '..'; +import { togglePageContentLock } from '../actions'; const ENTITY_TYPES = { wp_template: { @@ -215,4 +216,20 @@ describe( 'actions', () => { ); } ); } ); + + describe( 'togglePageContentLock', () => { + it( 'returns the correct toggle action', () => { + expect( togglePageContentLock( true ) ).toEqual( { + type: 'TOGGLE_PAGE_CONTENT_LOCK', + hasPageContentLock: true, + } ); + expect( togglePageContentLock( false ) ).toEqual( { + type: 'TOGGLE_PAGE_CONTENT_LOCK', + hasPageContentLock: false, + } ); + expect( togglePageContentLock() ).toEqual( { + type: 'TOGGLE_PAGE_CONTENT_LOCK', + } ); + } ); + } ); } ); diff --git a/packages/edit-site/src/store/test/reducer.js b/packages/edit-site/src/store/test/reducer.js index f6ce205ad63533..0ea196f1079a9c 100644 --- a/packages/edit-site/src/store/test/reducer.js +++ b/packages/edit-site/src/store/test/reducer.js @@ -11,6 +11,7 @@ import { editedPost, blockInserterPanel, listViewPanel, + hasPageContentLock, } from '../reducer'; import { setIsInserterOpened, setIsListViewOpened } from '../actions'; @@ -135,4 +136,60 @@ describe( 'state', () => { ); } ); } ); + + describe( 'hasPageContentLocked()', () => { + it( 'defaults to false', () => { + expect( hasPageContentLock( undefined, {} ) ).toBe( false ); + } ); + + it( 'becomes false when editing a template', () => { + expect( + hasPageContentLock( true, { + type: 'SET_EDITED_POST', + postType: 'wp_template', + } ) + ).toBe( false ); + } ); + + it( 'becomes true when editing a page', () => { + expect( + hasPageContentLock( false, { + type: 'SET_EDITED_POST', + postType: 'wp_template', + context: { + postType: 'page', + postId: 123, + }, + } ) + ).toBe( true ); + } ); + + it( 'can be explicitly set', () => { + expect( + hasPageContentLock( false, { + type: 'TOGGLE_PAGE_CONTENT_LOCK', + hasPageContentLock: true, + } ) + ).toBe( true ); + expect( + hasPageContentLock( true, { + type: 'TOGGLE_PAGE_CONTENT_LOCK', + hasPageContentLock: false, + } ) + ).toBe( false ); + } ); + + it( 'can be toggled', () => { + expect( + hasPageContentLock( true, { + type: 'TOGGLE_PAGE_CONTENT_LOCK', + } ) + ).toBe( false ); + expect( + hasPageContentLock( false, { + type: 'TOGGLE_PAGE_CONTENT_LOCK', + } ) + ).toBe( true ); + } ); + } ); } ); diff --git a/packages/edit-site/src/store/test/selectors.js b/packages/edit-site/src/store/test/selectors.js index 223bcd1f0ba041..d9ed31411ffcc2 100644 --- a/packages/edit-site/src/store/test/selectors.js +++ b/packages/edit-site/src/store/test/selectors.js @@ -15,6 +15,8 @@ import { isInserterOpened, isListViewOpened, __unstableGetPreference, + isPage, + hasPageContentLock, } from '../selectors'; describe( 'selectors', () => { @@ -145,4 +147,59 @@ describe( 'selectors', () => { expect( isListViewOpened( state ) ).toBe( false ); } ); } ); + + describe( 'isPage', () => { + it( 'returns true if the edited post type is a page', () => { + const state = { + editedPost: { + postType: 'wp_template', + context: { postType: 'page', postId: 123 }, + }, + }; + expect( isPage( state ) ).toBe( true ); + } ); + + it( 'returns false if the edited post type is a template', () => { + const state = { + editedPost: { + postType: 'wp_template', + }, + }; + expect( isPage( state ) ).toBe( false ); + } ); + } ); + + describe( 'hasPageContentLock', () => { + it( 'returns true if locked and the edited post type is a page', () => { + const state = { + editedPost: { + postType: 'wp_template', + context: { postType: 'page', postId: 123 }, + }, + hasPageContentLock: true, + }; + expect( hasPageContentLock( state ) ).toBe( true ); + } ); + + it( 'returns false if not locked and the edited post type is a page', () => { + const state = { + editedPost: { + postType: 'wp_template', + context: { postType: 'page', postId: 123 }, + }, + hasPageContentLock: false, + }; + expect( hasPageContentLock( state ) ).toBe( false ); + } ); + + it( 'returns false if locked and the edited post type is a template', () => { + const state = { + editedPost: { + postType: 'wp_template', + }, + hasPageContentLock: true, + }; + expect( hasPageContentLock( state ) ).toBe( false ); + } ); + } ); } ); diff --git a/packages/edit-site/src/style.scss b/packages/edit-site/src/style.scss index 3be15cd02d2599..a7494f9fe4e077 100644 --- a/packages/edit-site/src/style.scss +++ b/packages/edit-site/src/style.scss @@ -10,8 +10,10 @@ @import "./components/header-edit-mode/document-actions/style.scss"; @import "./components/list/style.scss"; @import "./components/sidebar-edit-mode/style.scss"; +@import "./components/sidebar-edit-mode/page-panels/style.scss"; @import "./components/sidebar-edit-mode/settings-header/style.scss"; -@import "./components/sidebar-edit-mode/template-card/style.scss"; +@import "./components/sidebar-edit-mode/sidebar-card/style.scss"; +@import "./components/sidebar-edit-mode/template-panel/style.scss"; @import "./components/editor/style.scss"; @import "./components/create-template-part-modal/style.scss"; @import "./components/secondary-sidebar/style.scss"; diff --git a/packages/edit-site/src/utils/remove-page-from-block-context.js b/packages/edit-site/src/utils/remove-page-from-block-context.js new file mode 100644 index 00000000000000..95846473a88b85 --- /dev/null +++ b/packages/edit-site/src/utils/remove-page-from-block-context.js @@ -0,0 +1,7 @@ +export default function removePageFromBlockContext( context ) { + return { + ...context, + postType: null, + postId: null, + }; +} diff --git a/packages/edit-site/src/utils/test/remove-page-from-block-context.js b/packages/edit-site/src/utils/test/remove-page-from-block-context.js new file mode 100644 index 00000000000000..833bdd35eb91b5 --- /dev/null +++ b/packages/edit-site/src/utils/test/remove-page-from-block-context.js @@ -0,0 +1,20 @@ +/** + * Internal dependencies + */ +import removePageFromBlockContext from '../remove-page-from-block-context'; + +describe( 'removePageFromBlockContext', () => { + it( 'should remove the page from the block context', () => { + expect( + removePageFromBlockContext( { + postType: 'page', + postId: 123, + templateSlug: 'my-template', + } ) + ).toEqual( { + postType: null, + postId: null, + templateSlug: 'my-template', + } ); + } ); +} ); From 727ecd2365150f3202ac5ddd3ae1c38b42e47d3f Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Wed, 24 May 2023 11:25:00 +1000 Subject: [PATCH 15/44] Show page information in DocumentActions --- .../document-actions/index.js | 93 ++++++++++++++++--- .../document-actions/style.scss | 2 +- 2 files changed, 82 insertions(+), 13 deletions(-) diff --git a/packages/edit-site/src/components/header-edit-mode/document-actions/index.js b/packages/edit-site/src/components/header-edit-mode/document-actions/index.js index 97bb0acb3bdd49..a4f3ab360ba91f 100644 --- a/packages/edit-site/src/components/header-edit-mode/document-actions/index.js +++ b/packages/edit-site/src/components/header-edit-mode/document-actions/index.js @@ -2,7 +2,7 @@ * WordPress dependencies */ import { sprintf, __ } from '@wordpress/i18n'; -import { useDispatch } from '@wordpress/data'; +import { useSelect, useDispatch } from '@wordpress/data'; import { Button, VisuallyHidden, @@ -11,17 +11,67 @@ import { } from '@wordpress/components'; import { BlockIcon } from '@wordpress/block-editor'; import { privateApis as commandsPrivateApis } from '@wordpress/commands'; +import { + chevronLeftSmall as chevronLeftSmallIcon, + sidebar as sidebarIcon, +} from '@wordpress/icons'; +import { useEntityRecord } from '@wordpress/core-data'; /** * Internal dependencies */ import useEditedEntityRecord from '../../use-edited-entity-record'; import { unlock } from '../../../private-apis'; +import { store as editSiteStore } from '../../../store'; const { store: commandsStore } = unlock( commandsPrivateApis ); export default function DocumentActions() { - const { open: openCommandCenter } = useDispatch( commandsStore ); + const isPage = useSelect( ( select ) => select( editSiteStore ).isPage() ); + return isPage ? : ; +} + +function PageDocumentActions() { + const { hasPageContentLock, context } = useSelect( + ( select ) => ( { + hasPageContentLock: select( editSiteStore ).hasPageContentLock(), + context: select( editSiteStore ).getEditedPostContext(), + } ), + [] + ); + + const { hasResolved, editedRecord } = useEntityRecord( + 'postType', + context.postType, + context.postId + ); + + const { togglePageContentLock } = useDispatch( editSiteStore ); + + // Return a simple loading indicator until we have information to show. + if ( ! hasResolved ) { + return null; + } + + // Return feedback that the page does not seem to exist. + if ( ! editedRecord ) { + return ( +
    + { __( 'Document not found' ) } +
    + ); + } + + return hasPageContentLock ? ( + + { editedRecord.title } + + ) : ( + togglePageContentLock() } /> + ); +} + +function TemplateDocumentActions( { onBack } ) { const { isLoaded, record, getTitle, icon } = useEditedEntityRecord(); // Return a simple loading indicator until we have information to show. @@ -43,14 +93,40 @@ export default function DocumentActions() { ? __( 'template part' ) : __( 'template' ); - const isMac = /Mac|iPod|iPhone|iPad/.test( window.navigator.platform ); + return ( + + + { sprintf( + /* translators: %s: the entity being edited, like "template"*/ + __( 'Editing %s: ' ), + entityLabel + ) } + + { getTitle() } + + ); +} +function BaseDocumentActions( { icon, children, onBack } ) { + const { open: openCommandCenter } = useDispatch( commandsStore ); + const isMac = /Mac|iPod|iPhone|iPad/.test( window.navigator.platform ); return ( + ) } - - { sprintf( - /* translators: %s: the entity being edited, like "template"*/ - __( 'Editing %s: ' ), - entityLabel - ) } - - { getTitle() } + { children } diff --git a/packages/edit-site/src/components/header-edit-mode/document-actions/style.scss b/packages/edit-site/src/components/header-edit-mode/document-actions/style.scss index 247b901975fd8e..077cbbb13bf75a 100644 --- a/packages/edit-site/src/components/header-edit-mode/document-actions/style.scss +++ b/packages/edit-site/src/components/header-edit-mode/document-actions/style.scss @@ -42,7 +42,7 @@ } } -.edit-site-document-actions__left { +.edit-site-document-actions__back { min-width: $button-size; flex-shrink: 0; } From 12e8ad4754232dde9926075ea3a689d78cf5877d Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Wed, 24 May 2023 11:55:25 +1000 Subject: [PATCH 16/44] Implement Content panel --- .../page-panels/content-blocks-list.js | 72 +++++++++++++++++++ .../sidebar-edit-mode/page-panels/index.js | 4 +- 2 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 packages/edit-site/src/components/sidebar-edit-mode/page-panels/content-blocks-list.js diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/content-blocks-list.js b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/content-blocks-list.js new file mode 100644 index 00000000000000..8f07790d4f5976 --- /dev/null +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/content-blocks-list.js @@ -0,0 +1,72 @@ +/** + * WordPress dependencies + */ +import { useSelect, useDispatch } from '@wordpress/data'; +import { + Button, + __experimentalVStack as VStack, + __experimentalHStack as HStack, + FlexItem, +} from '@wordpress/components'; +import { getBlockType } from '@wordpress/blocks'; +import { store as blockEditorStore, BlockIcon } from '@wordpress/block-editor'; + +// TODO: This overlaps a lot with BlockInspectorLockedBlocks in +// @wordpress/block-editor. DRY them into a single component. +export default function ContentBlocksList() { + const contentBlocks = useSelect( ( select ) => { + const { + getClientIdsWithDescendants, + getBlockName, + isBlockSelected, + hasSelectedInnerBlock, + } = select( blockEditorStore ); + return getClientIdsWithDescendants().flatMap( ( clientId ) => { + const blockName = getBlockName( clientId ); + if ( + ! [ + 'core/post-title', + 'core/post-featured-image', + 'core/post-content', + ].includes( blockName ) + ) { + return []; + } + return [ + { + clientId, + blockName, + isSelected: + isBlockSelected( clientId ) || + hasSelectedInnerBlock( clientId, /* deep: */ true ), + }, + ]; + } ); + }, [] ); + + const { selectBlock } = useDispatch( blockEditorStore ); + + if ( ! contentBlocks.length ) { + return null; + } + + return ( + + { contentBlocks.map( ( { clientId, blockName, isSelected } ) => { + const blockType = getBlockType( blockName ); + return ( + + ); + } ) } + + ); +} diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/index.js b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/index.js index 19329228be2172..5ce102560a8b2a 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/index.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/index.js @@ -21,6 +21,7 @@ import { store as editSiteStore } from '../../../store'; import useEditedEntityRecord from '../../use-edited-entity-record'; import removePageFromBlockContext from '../../../utils/remove-page-from-block-context'; import SidebarCard from '../sidebar-card'; +import ContentBlocksList from './content-blocks-list'; export default function PagePanels() { const context = useSelect( @@ -62,8 +63,7 @@ export default function PagePanels() { />
    - TODO - { /* */ } + Date: Wed, 24 May 2023 12:17:03 +1000 Subject: [PATCH 17/44] Prevent block overlay on disabled blocks --- packages/block-editor/src/store/selectors.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js index 59c36dca2b8237..a740ddc7194ebc 100644 --- a/packages/block-editor/src/store/selectors.js +++ b/packages/block-editor/src/store/selectors.js @@ -26,6 +26,7 @@ import deprecated from '@wordpress/deprecated'; */ import { mapRichTextSettings } from './utils'; import { orderBy } from '../utils/sorting'; +import { getBlockEditingMode } from './private-selectors'; /** * A block selection object. @@ -2788,6 +2789,13 @@ export function __unstableGetTemporarilyEditingAsBlocks( state ) { } export function __unstableHasActiveBlockOverlayActive( state, clientId ) { + // Prevent overlay on disabled blocks. It's redundant since disabled blocks + // can't be selected, and prevents non-disabled nested blocks from being + // selected. + if ( getBlockEditingMode( state, clientId ) === 'disabled' ) { + return false; + } + // If the block editing is locked, the block overlay is always active. if ( ! canEditBlock( state, clientId ) ) { return true; From fda46cd60b08dbd3c2e6de4e5c74764b12965cbd Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Wed, 24 May 2023 12:37:38 +1000 Subject: [PATCH 18/44] Fix Navigation block being selectable --- .../block-editor/src/components/block-list/content.scss | 1 - packages/block-library/src/navigation/editor.scss | 8 +++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/block-editor/src/components/block-list/content.scss b/packages/block-editor/src/components/block-list/content.scss index dab07ced873e9f..d7436c33812176 100644 --- a/packages/block-editor/src/components/block-list/content.scss +++ b/packages/block-editor/src/components/block-list/content.scss @@ -161,7 +161,6 @@ padding: 0; } -.block-editor-block-list__layout, .block-editor-block-list__block { pointer-events: initial; diff --git a/packages/block-library/src/navigation/editor.scss b/packages/block-library/src/navigation/editor.scss index 949a7c773eb6e6..cd3b00a06aab86 100644 --- a/packages/block-library/src/navigation/editor.scss +++ b/packages/block-library/src/navigation/editor.scss @@ -513,9 +513,11 @@ body.editor-styles-wrapper .wp-block-navigation__responsive-container.is-menu-op @include break-small() { pointer-events: none; - .wp-block-navigation__responsive-container-close, - .block-editor-block-list__layout * { - pointer-events: all; + .wp-block-navigation:not(.is-editing-disabled) { + .wp-block-navigation__responsive-container-close, + .block-editor-block-list__layout * { + pointer-events: all; + } } } From 0443db49fe5174d6e140bf530933000f92b3c58e Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Wed, 24 May 2023 13:08:03 +1000 Subject: [PATCH 19/44] Show 'Page' in breadcrumbs when focused on editing page --- packages/edit-site/src/components/editor/index.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/edit-site/src/components/editor/index.js b/packages/edit-site/src/components/editor/index.js index d40cbd49e477d2..aef441a0574563 100644 --- a/packages/edit-site/src/components/editor/index.js +++ b/packages/edit-site/src/components/editor/index.js @@ -223,7 +223,11 @@ export default function Editor( { isLoading } ) { footer={ shouldShowBlockBreakcrumbs && ( ) } From 8c1c4a6f221935750c2e98c496976be85808bff9 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Wed, 24 May 2023 15:30:40 +1000 Subject: [PATCH 20/44] Update post title, post featured image, and post content blocks to say 'Page' instead of 'Post' --- .../src/components/block-editor/index.js | 18 +++---- .../src/components/page-content-lock/index.js | 16 +++++++ .../use-disable-non-content-blocks.js} | 36 +++++++++----- .../use-page-content-lock-notifications.js} | 2 +- ...e-remove-post-from-content-block-labels.js | 47 +++++++++++++++++++ .../page-panels/content-blocks-list.js | 22 +++++---- packages/edit-site/src/hooks/index.js | 1 - 7 files changed, 107 insertions(+), 35 deletions(-) create mode 100644 packages/edit-site/src/components/page-content-lock/index.js rename packages/edit-site/src/{hooks/block-editing-mode.js => components/page-content-lock/use-disable-non-content-blocks.js} (59%) rename packages/edit-site/src/components/{use-page-content-lock-notifications/index.js => page-content-lock/use-page-content-lock-notifications.js} (98%) create mode 100644 packages/edit-site/src/components/page-content-lock/use-remove-post-from-content-block-labels.js diff --git a/packages/edit-site/src/components/block-editor/index.js b/packages/edit-site/src/components/block-editor/index.js index 3302d5eed6b330..a2409b3f1baa2c 100644 --- a/packages/edit-site/src/components/block-editor/index.js +++ b/packages/edit-site/src/components/block-editor/index.js @@ -38,11 +38,12 @@ import ResizableEditor from './resizable-editor'; import EditorCanvas from './editor-canvas'; import { unlock } from '../../private-apis'; import EditorCanvasContainer from '../editor-canvas-container'; -import usePageContentLockNotifications from '../use-page-content-lock-notifications'; +import { + PageContentLock, + usePageContentLockNotifications, +} from '../page-content-lock'; -const { ExperimentalBlockEditorProvider, useBlockEditingMode } = unlock( - blockEditorPrivateApis -); +const { ExperimentalBlockEditorProvider } = unlock( blockEditorPrivateApis ); const LAYOUT = { type: 'default', @@ -171,9 +172,7 @@ export default function BlockEditor() { onChange={ onChange } useSubRegistry={ false } > - { hasPageContentLock && ( - - ) } + { hasPageContentLock && } @@ -227,8 +226,3 @@ export default function BlockEditor() { ); } - -function SetRootBlockEditingMode( { mode } ) { - useBlockEditingMode( mode ); - return null; -} diff --git a/packages/edit-site/src/components/page-content-lock/index.js b/packages/edit-site/src/components/page-content-lock/index.js new file mode 100644 index 00000000000000..fa8c7c01f72d1d --- /dev/null +++ b/packages/edit-site/src/components/page-content-lock/index.js @@ -0,0 +1,16 @@ +/** + * Internal dependencies + */ +import { useDisableNonContentBlocks } from './use-disable-non-content-blocks'; +import { useRemovePostFromContentBlockLabels } from './use-remove-post-from-content-block-labels'; + +/** + * Component that when rendered, locks the site editor so that only page content + * can be edited. + */ +export function PageContentLock() { + useDisableNonContentBlocks(); + useRemovePostFromContentBlockLabels(); +} + +export { usePageContentLockNotifications } from './use-page-content-lock-notifications'; diff --git a/packages/edit-site/src/hooks/block-editing-mode.js b/packages/edit-site/src/components/page-content-lock/use-disable-non-content-blocks.js similarity index 59% rename from packages/edit-site/src/hooks/block-editing-mode.js rename to packages/edit-site/src/components/page-content-lock/use-disable-non-content-blocks.js index 2f3912d76eb35a..cd2eabec9336c9 100644 --- a/packages/edit-site/src/hooks/block-editing-mode.js +++ b/packages/edit-site/src/components/page-content-lock/use-disable-non-content-blocks.js @@ -2,28 +2,44 @@ * WordPress dependencies */ import { createHigherOrderComponent } from '@wordpress/compose'; -import { addFilter } from '@wordpress/hooks'; +import { addFilter, removeFilter } from '@wordpress/hooks'; import { store as blockEditorStore, privateApis as blockEditorPrivateApis, } from '@wordpress/block-editor'; import { useSelect } from '@wordpress/data'; +import { useEffect } from '@wordpress/element'; /** * Internal dependencies */ -import { unlock } from '../private-apis'; -import { store as editSiteStore } from '../store'; +import { unlock } from '../../private-apis'; const { useBlockEditingMode } = unlock( blockEditorPrivateApis ); -export const withBlockEditingMode = createHigherOrderComponent( +/** + * Disables non-content blocks using the `useBlockEditingMode` hook. + */ +export function useDisableNonContentBlocks() { + useBlockEditingMode( 'disabled' ); + useEffect( () => { + addFilter( + 'editor.BlockEdit', + 'core/edit-site/disable-non-content-blocks', + withDisableNonContentBlocks + ); + return () => + removeFilter( + 'editor.BlockEdit', + 'core/edit-site/disable-non-content-blocks' + ); + }, [] ); +} + +const withDisableNonContentBlocks = createHigherOrderComponent( ( BlockEdit ) => ( props ) => { const mode = useSelect( ( select ) => { - if ( ! select( editSiteStore ).hasPageContentLock() ) { - return; - } if ( [ 'core/post-title', @@ -49,9 +65,3 @@ export const withBlockEditingMode = createHigherOrderComponent( }, 'withBlockEditingMode' ); - -addFilter( - 'editor.BlockEdit', - 'core/edit-site/block-editing-mode', - withBlockEditingMode -); diff --git a/packages/edit-site/src/components/use-page-content-lock-notifications/index.js b/packages/edit-site/src/components/page-content-lock/use-page-content-lock-notifications.js similarity index 98% rename from packages/edit-site/src/components/use-page-content-lock-notifications/index.js rename to packages/edit-site/src/components/page-content-lock/use-page-content-lock-notifications.js index 32a10800fc4691..f03f33914fd200 100644 --- a/packages/edit-site/src/components/use-page-content-lock-notifications/index.js +++ b/packages/edit-site/src/components/page-content-lock/use-page-content-lock-notifications.js @@ -20,7 +20,7 @@ import { store as editSiteStore } from '../../store'; * (using useMergeRefs()) to * the editor iframe canvas. */ -export default function usePageContentLockNotifications() { +export function usePageContentLockNotifications() { const ref = useEditTemplateNotification(); useBackToPageNotification(); return ref; diff --git a/packages/edit-site/src/components/page-content-lock/use-remove-post-from-content-block-labels.js b/packages/edit-site/src/components/page-content-lock/use-remove-post-from-content-block-labels.js new file mode 100644 index 00000000000000..deabecd64ac393 --- /dev/null +++ b/packages/edit-site/src/components/page-content-lock/use-remove-post-from-content-block-labels.js @@ -0,0 +1,47 @@ +/** + * WordPress dependencies + */ +import { useEffect } from '@wordpress/element'; +import { addFilter, removeFilter } from '@wordpress/hooks'; +import { store as blocksStore } from '@wordpress/blocks'; +import { useDispatch } from '@wordpress/data'; +import { __ } from '@wordpress/i18n'; + +/** + * Adjusts the labels of the post title, featured image, and content blocks so + * that they say 'Page' instead of 'Post'. + */ +export function useRemovePostFromContentBlockLabels() { + const { __experimentalReapplyBlockTypeFilters } = + useDispatch( blocksStore ); + useEffect( () => { + addFilter( + 'blocks.registerBlockType', + 'core/edit-site/remove-post-from-content-block-labels', + removePostFromContentBlockLabels + ); + __experimentalReapplyBlockTypeFilters(); + return () => { + removeFilter( + 'blocks.registerBlockType', + 'core/edit-site/remove-post-from-content-block-labels' + ); + __experimentalReapplyBlockTypeFilters(); + }; + }, [] ); +} + +function removePostFromContentBlockLabels( settings, name ) { + switch ( name ) { + case 'core/post-title': + settings.__experimentalLabel = () => __( 'Page Title' ); + break; + case 'core/post-featured-image': + settings.__experimentalLabel = () => __( 'Page Featured Image' ); + break; + case 'core/post-content': + settings.__experimentalLabel = () => __( 'Page Content' ); + break; + } + return settings; +} diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/content-blocks-list.js b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/content-blocks-list.js index 8f07790d4f5976..0d326d2c9a5e4e 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/content-blocks-list.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/content-blocks-list.js @@ -8,7 +8,7 @@ import { __experimentalHStack as HStack, FlexItem, } from '@wordpress/components'; -import { getBlockType } from '@wordpress/blocks'; +import { getBlockType, __experimentalGetBlockLabel } from '@wordpress/blocks'; import { store as blockEditorStore, BlockIcon } from '@wordpress/block-editor'; // TODO: This overlaps a lot with BlockInspectorLockedBlocks in @@ -18,6 +18,7 @@ export default function ContentBlocksList() { const { getClientIdsWithDescendants, getBlockName, + getBlock, isBlockSelected, hasSelectedInnerBlock, } = select( blockEditorStore ); @@ -34,8 +35,7 @@ export default function ContentBlocksList() { } return [ { - clientId, - blockName, + block: getBlock( clientId ), isSelected: isBlockSelected( clientId ) || hasSelectedInnerBlock( clientId, /* deep: */ true ), @@ -52,17 +52,23 @@ export default function ContentBlocksList() { return ( - { contentBlocks.map( ( { clientId, blockName, isSelected } ) => { - const blockType = getBlockType( blockName ); + { contentBlocks.map( ( { block, isSelected } ) => { + const blockType = getBlockType( block.name ); return ( ); diff --git a/packages/edit-site/src/hooks/index.js b/packages/edit-site/src/hooks/index.js index de9dc8c3f764d3..513634c55b8f01 100644 --- a/packages/edit-site/src/hooks/index.js +++ b/packages/edit-site/src/hooks/index.js @@ -1,7 +1,6 @@ /** * Internal dependencies */ -import './block-editing-mode'; import './components'; import './push-changes-to-global-styles'; import './template-part-edit'; From bed91ecfef7fc9a1bcdee310dbfce52c192fd8a0 Mon Sep 17 00:00:00 2001 From: Saxon Fletcher Date: Wed, 24 May 2023 17:16:27 +1000 Subject: [PATCH 21/44] toolbar title styling --- .../document-actions/index.js | 52 ++++++++++++------- .../document-actions/style.scss | 30 ++++++++--- 2 files changed, 54 insertions(+), 28 deletions(-) diff --git a/packages/edit-site/src/components/header-edit-mode/document-actions/index.js b/packages/edit-site/src/components/header-edit-mode/document-actions/index.js index d9a73e84de62e8..a793c92c7bd489 100644 --- a/packages/edit-site/src/components/header-edit-mode/document-actions/index.js +++ b/packages/edit-site/src/components/header-edit-mode/document-actions/index.js @@ -1,3 +1,8 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + /** * WordPress dependencies */ @@ -13,7 +18,7 @@ import { BlockIcon } from '@wordpress/block-editor'; import { privateApis as commandsPrivateApis } from '@wordpress/commands'; import { chevronLeftSmall as chevronLeftSmallIcon, - sidebar as sidebarIcon, + page as pageIcon, } from '@wordpress/icons'; import { useEntityRecord } from '@wordpress/core-data'; import { displayShortcut } from '@wordpress/keycodes'; @@ -64,7 +69,7 @@ function PageDocumentActions() { } return hasPageContentLock ? ( - + { editedRecord.title } ) : ( @@ -108,13 +113,10 @@ function TemplateDocumentActions( { onBack } ) { ); } -function BaseDocumentActions( { icon, children, onBack } ) { +function BaseDocumentActions( { icon, children, onBack, isPage = false } ) { const { open: openCommandCenter } = useDispatch( commandsStore ); return ( - + + + + { children } + + + + { displayShortcut.primary( 'k' ) } + + +
    ); } diff --git a/packages/edit-site/src/components/header-edit-mode/document-actions/style.scss b/packages/edit-site/src/components/header-edit-mode/document-actions/style.scss index 077cbbb13bf75a..8bd3475de69564 100644 --- a/packages/edit-site/src/components/header-edit-mode/document-actions/style.scss +++ b/packages/edit-site/src/components/header-edit-mode/document-actions/style.scss @@ -1,10 +1,7 @@ .edit-site-document-actions { - display: flex; - align-items: center; - gap: $grid-unit; + display: grid; + grid-template-columns: 1fr 2fr 1fr; height: $button-size; - padding: $grid-unit; - justify-content: space-between; // Flex items will, by default, refuse to shrink below a minimum // intrinsic width. In order to shrink this flexbox item, and // subsequently truncate child text, we set an explicit min-width. @@ -20,23 +17,37 @@ } } +.edit-site-document-actions__command { + grid-column: 1 / -1; + display: grid; + grid-template-columns: 1fr 2fr 1fr; + grid-row: 1; +} + + .edit-site-document-actions__title { flex-grow: 1; color: var(--wp-block-synced-color); overflow: hidden; + grid-column: 2 / 3; + &.is-page { + color: $gray-800; + h1 { + color: $gray-800; + } + } h1 { - color: var(--wp-block-synced-color); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + color: var(--wp-block-synced-color); } } .edit-site-document-actions__shortcut { - flex-shrink: 0; color: $gray-700; - width: #{$grid-unit * 4.5}; + text-align: right; &:hover { color: $gray-700; } @@ -45,4 +56,7 @@ .edit-site-document-actions__back { min-width: $button-size; flex-shrink: 0; + grid-column: 1 / 2; + grid-row: 1; + z-index: 1; } From 23837deb7e97deab15e87a94fb8c79f3025c6730 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Thu, 25 May 2023 10:04:01 +1000 Subject: [PATCH 22/44] Remove removePostFromContentBlockLabels for now --- .../src/components/page-content-lock/index.js | 2 - ...e-remove-post-from-content-block-labels.js | 47 ------------------- 2 files changed, 49 deletions(-) delete mode 100644 packages/edit-site/src/components/page-content-lock/use-remove-post-from-content-block-labels.js diff --git a/packages/edit-site/src/components/page-content-lock/index.js b/packages/edit-site/src/components/page-content-lock/index.js index fa8c7c01f72d1d..83d096fb39f5d0 100644 --- a/packages/edit-site/src/components/page-content-lock/index.js +++ b/packages/edit-site/src/components/page-content-lock/index.js @@ -2,7 +2,6 @@ * Internal dependencies */ import { useDisableNonContentBlocks } from './use-disable-non-content-blocks'; -import { useRemovePostFromContentBlockLabels } from './use-remove-post-from-content-block-labels'; /** * Component that when rendered, locks the site editor so that only page content @@ -10,7 +9,6 @@ import { useRemovePostFromContentBlockLabels } from './use-remove-post-from-cont */ export function PageContentLock() { useDisableNonContentBlocks(); - useRemovePostFromContentBlockLabels(); } export { usePageContentLockNotifications } from './use-page-content-lock-notifications'; diff --git a/packages/edit-site/src/components/page-content-lock/use-remove-post-from-content-block-labels.js b/packages/edit-site/src/components/page-content-lock/use-remove-post-from-content-block-labels.js deleted file mode 100644 index deabecd64ac393..00000000000000 --- a/packages/edit-site/src/components/page-content-lock/use-remove-post-from-content-block-labels.js +++ /dev/null @@ -1,47 +0,0 @@ -/** - * WordPress dependencies - */ -import { useEffect } from '@wordpress/element'; -import { addFilter, removeFilter } from '@wordpress/hooks'; -import { store as blocksStore } from '@wordpress/blocks'; -import { useDispatch } from '@wordpress/data'; -import { __ } from '@wordpress/i18n'; - -/** - * Adjusts the labels of the post title, featured image, and content blocks so - * that they say 'Page' instead of 'Post'. - */ -export function useRemovePostFromContentBlockLabels() { - const { __experimentalReapplyBlockTypeFilters } = - useDispatch( blocksStore ); - useEffect( () => { - addFilter( - 'blocks.registerBlockType', - 'core/edit-site/remove-post-from-content-block-labels', - removePostFromContentBlockLabels - ); - __experimentalReapplyBlockTypeFilters(); - return () => { - removeFilter( - 'blocks.registerBlockType', - 'core/edit-site/remove-post-from-content-block-labels' - ); - __experimentalReapplyBlockTypeFilters(); - }; - }, [] ); -} - -function removePostFromContentBlockLabels( settings, name ) { - switch ( name ) { - case 'core/post-title': - settings.__experimentalLabel = () => __( 'Page Title' ); - break; - case 'core/post-featured-image': - settings.__experimentalLabel = () => __( 'Page Featured Image' ); - break; - case 'core/post-content': - settings.__experimentalLabel = () => __( 'Page Content' ); - break; - } - return settings; -} From 3cd4a1725f527846dd263478a5da7da8d42521d7 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Thu, 25 May 2023 11:23:49 +1000 Subject: [PATCH 23/44] Fix being able to select text within disabled blocks --- .../src/components/block-list/content.scss | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/packages/block-editor/src/components/block-list/content.scss b/packages/block-editor/src/components/block-list/content.scss index d7436c33812176..16c2d15b22d5e5 100644 --- a/packages/block-editor/src/components/block-list/content.scss +++ b/packages/block-editor/src/components/block-list/content.scss @@ -161,14 +161,6 @@ padding: 0; } -.block-editor-block-list__block { - pointer-events: initial; - - &.is-editing-disabled { - pointer-events: none; - } -} - .block-editor-block-list__layout .block-editor-block-list__block { // With `position: static`, Safari marks a full-width selection rectangle, including margins. // With `position: relative`, Safari marks an inline selection rectangle, similar to that of @@ -177,12 +169,19 @@ // We choose relative, as that matches the multi-selection, which is limited to the block footprint. position: relative; - // Re-enable text-selection on editable blocks. - user-select: text; - // Break long strings of text without spaces so they don't overflow the block. overflow-wrap: break-word; + // Enable pointer events on editable blocks. + pointer-events: auto; + user-select: text; + + // But disable when editing is disabled. + &.is-editing-disabled { + pointer-events: none; + user-select: none; + } + .reusable-block-edit-panel * { z-index: z-index(".block-editor-block-list__block .reusable-block-edit-panel *"); } From 599a4d1ab24d295371232cb992cc274043099612 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Thu, 25 May 2023 11:34:25 +1000 Subject: [PATCH 24/44] Hide BlockAppender when block is disabled --- .../block-editor/src/components/block-list-appender/index.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/block-list-appender/index.js b/packages/block-editor/src/components/block-list-appender/index.js index 56c044b6c5a8ab..99d0fc56374e42 100644 --- a/packages/block-editor/src/components/block-list-appender/index.js +++ b/packages/block-editor/src/components/block-list-appender/index.js @@ -15,6 +15,7 @@ import { getDefaultBlockName } from '@wordpress/blocks'; import DefaultBlockAppender from '../default-block-appender'; import ButtonBlockAppender from '../button-block-appender'; import { store as blockEditorStore } from '../../store'; +import { unlock } from '../../lock-unlock'; function DefaultAppender( { rootClientId } ) { const canInsertDefaultBlock = useSelect( ( select ) => @@ -46,13 +47,15 @@ function useAppender( rootClientId, CustomAppender ) { getTemplateLock, getSelectedBlockClientId, __unstableGetEditorMode, - } = select( blockEditorStore ); + getBlockEditingMode, + } = unlock( select( blockEditorStore ) ); const selectedBlockClientId = getSelectedBlockClientId(); return { hideInserter: !! getTemplateLock( rootClientId ) || + getBlockEditingMode( rootClientId ) === 'disabled' || __unstableGetEditorMode() === 'zoom-out', isParentSelected: rootClientId === selectedBlockClientId || From 5d523594e8352de736b8f6e3c8791e04f1ed65d7 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Thu, 25 May 2023 15:17:33 +1000 Subject: [PATCH 25/44] Fix comments block in non-post templates --- .../src/utils/remove-page-from-block-context.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/edit-site/src/utils/remove-page-from-block-context.js b/packages/edit-site/src/utils/remove-page-from-block-context.js index 95846473a88b85..44ba4a8aa6ccd7 100644 --- a/packages/edit-site/src/utils/remove-page-from-block-context.js +++ b/packages/edit-site/src/utils/remove-page-from-block-context.js @@ -1,7 +1,7 @@ export default function removePageFromBlockContext( context ) { - return { - ...context, - postType: null, - postId: null, - }; + if ( context ) { + const { postType, postId, ...rest } = context; + return rest; + } + return context; } From 055b7f176ae2d42ab21bd08e02071f99b3317e80 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Thu, 25 May 2023 15:27:02 +1000 Subject: [PATCH 26/44] Update template card selector in E2E tests --- packages/e2e-tests/specs/site-editor/settings-sidebar.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/e2e-tests/specs/site-editor/settings-sidebar.test.js b/packages/e2e-tests/specs/site-editor/settings-sidebar.test.js index 88bf954e86ce2c..ae28019cf0d992 100644 --- a/packages/e2e-tests/specs/site-editor/settings-sidebar.test.js +++ b/packages/e2e-tests/specs/site-editor/settings-sidebar.test.js @@ -27,11 +27,11 @@ async function getActiveTabLabel() { async function getTemplateCard() { return { title: await page.$eval( - '.edit-site-template-card__title', + '.edit-site-sidebar-card__title', ( element ) => element.innerText ), description: await page.$eval( - '.edit-site-template-card__description', + '.edit-site-sidebar-card__description', ( element ) => element.innerText ), }; From 79c59bf9646a748c7c72f60ae765c74f18510223 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Thu, 25 May 2023 15:42:34 +1000 Subject: [PATCH 27/44] Fix 'Add submenu' button in Navigation block --- .../block-library/src/navigation/editor.scss | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/block-library/src/navigation/editor.scss b/packages/block-library/src/navigation/editor.scss index cd3b00a06aab86..4a6a6fe6b43951 100644 --- a/packages/block-library/src/navigation/editor.scss +++ b/packages/block-library/src/navigation/editor.scss @@ -508,22 +508,22 @@ body.editor-styles-wrapper .wp-block-navigation__responsive-container.is-menu-op // so focus is applied naturally on the block container. // It's important the right container has focus, otherwise you can't press // "Delete" to remove the block. -.wp-block-navigation__responsive-container, -.wp-block-navigation__responsive-close { - @include break-small() { - pointer-events: none; +.wp-block-navigation:not(.is-editing-disabled) { + .wp-block-navigation__responsive-container, + .wp-block-navigation__responsive-close { + @include break-small() { + pointer-events: none; - .wp-block-navigation:not(.is-editing-disabled) { .wp-block-navigation__responsive-container-close, .block-editor-block-list__layout * { pointer-events: all; } } - } - // Page List items should remain inert. - .wp-block-pages-list__item__link { - pointer-events: none; + // Page List items should remain inert. + .wp-block-pages-list__item__link { + pointer-events: none; + } } } From 89212cdc44d71f6f332f4b547bfdd0869fbbe421 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Thu, 25 May 2023 16:05:09 +1000 Subject: [PATCH 28/44] Remove unhelpful comments --- packages/block-editor/src/components/block-list/content.scss | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/block-editor/src/components/block-list/content.scss b/packages/block-editor/src/components/block-list/content.scss index 16c2d15b22d5e5..a163ddaa789551 100644 --- a/packages/block-editor/src/components/block-list/content.scss +++ b/packages/block-editor/src/components/block-list/content.scss @@ -172,11 +172,9 @@ // Break long strings of text without spaces so they don't overflow the block. overflow-wrap: break-word; - // Enable pointer events on editable blocks. pointer-events: auto; user-select: text; - // But disable when editing is disabled. &.is-editing-disabled { pointer-events: none; user-select: none; From bdee82add2e025a77125b7a584466d05142d8098 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Thu, 25 May 2023 16:07:21 +1000 Subject: [PATCH 29/44] Remove more unnecessary comments --- .../src/components/header-edit-mode/document-actions/index.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/edit-site/src/components/header-edit-mode/document-actions/index.js b/packages/edit-site/src/components/header-edit-mode/document-actions/index.js index a793c92c7bd489..8f95e1efe10e2b 100644 --- a/packages/edit-site/src/components/header-edit-mode/document-actions/index.js +++ b/packages/edit-site/src/components/header-edit-mode/document-actions/index.js @@ -54,12 +54,10 @@ function PageDocumentActions() { const { togglePageContentLock } = useDispatch( editSiteStore ); - // Return a simple loading indicator until we have information to show. if ( ! hasResolved ) { return null; } - // Return feedback that the page does not seem to exist. if ( ! editedRecord ) { return (
    @@ -80,12 +78,10 @@ function PageDocumentActions() { function TemplateDocumentActions( { onBack } ) { const { isLoaded, record, getTitle, icon } = useEditedEntityRecord(); - // Return a simple loading indicator until we have information to show. if ( ! isLoaded ) { return null; } - // Return feedback that the template does not seem to exist. if ( ! record ) { return (
    From 0395bf0055f1ee94b0a93ebcbc83eae57296feba Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Thu, 25 May 2023 16:11:38 +1000 Subject: [PATCH 30/44] Use constant for block types array --- .../src/components/page-content-lock/constants.js | 5 +++++ .../use-disable-non-content-blocks.js | 9 ++------- .../page-panels/content-blocks-list.js | 13 ++++++------- 3 files changed, 13 insertions(+), 14 deletions(-) create mode 100644 packages/edit-site/src/components/page-content-lock/constants.js diff --git a/packages/edit-site/src/components/page-content-lock/constants.js b/packages/edit-site/src/components/page-content-lock/constants.js new file mode 100644 index 00000000000000..668fe8af00d69d --- /dev/null +++ b/packages/edit-site/src/components/page-content-lock/constants.js @@ -0,0 +1,5 @@ +export const CONTENT_BLOCK_TYPES = [ + 'core/post-title', + 'core/post-featured-image', + 'core/post-content', +]; diff --git a/packages/edit-site/src/components/page-content-lock/use-disable-non-content-blocks.js b/packages/edit-site/src/components/page-content-lock/use-disable-non-content-blocks.js index cd2eabec9336c9..554a483284a0ce 100644 --- a/packages/edit-site/src/components/page-content-lock/use-disable-non-content-blocks.js +++ b/packages/edit-site/src/components/page-content-lock/use-disable-non-content-blocks.js @@ -14,6 +14,7 @@ import { useEffect } from '@wordpress/element'; * Internal dependencies */ import { unlock } from '../../private-apis'; +import { CONTENT_BLOCK_TYPES } from './constants'; const { useBlockEditingMode } = unlock( blockEditorPrivateApis ); @@ -40,13 +41,7 @@ const withDisableNonContentBlocks = createHigherOrderComponent( ( BlockEdit ) => ( props ) => { const mode = useSelect( ( select ) => { - if ( - [ - 'core/post-title', - 'core/post-featured-image', - 'core/post-content', - ].includes( props.name ) - ) { + if ( CONTENT_BLOCK_TYPES.includes( props.name ) ) { return 'contentOnly'; } if ( diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/content-blocks-list.js b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/content-blocks-list.js index 0d326d2c9a5e4e..9035c5677f91ac 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/content-blocks-list.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/content-blocks-list.js @@ -11,6 +11,11 @@ import { import { getBlockType, __experimentalGetBlockLabel } from '@wordpress/blocks'; import { store as blockEditorStore, BlockIcon } from '@wordpress/block-editor'; +/** + * Internal dependencies + */ +import { CONTENT_BLOCK_TYPES } from '../../page-content-lock/constants'; + // TODO: This overlaps a lot with BlockInspectorLockedBlocks in // @wordpress/block-editor. DRY them into a single component. export default function ContentBlocksList() { @@ -24,13 +29,7 @@ export default function ContentBlocksList() { } = select( blockEditorStore ); return getClientIdsWithDescendants().flatMap( ( clientId ) => { const blockName = getBlockName( clientId ); - if ( - ! [ - 'core/post-title', - 'core/post-featured-image', - 'core/post-content', - ].includes( blockName ) - ) { + if ( ! CONTENT_BLOCK_TYPES.includes( blockName ) ) { return []; } return [ From 67cf0dbacf7da56c5dea35ca634455c8153ccbf3 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Thu, 25 May 2023 16:18:44 +1000 Subject: [PATCH 31/44] Use BEMish selectors --- .../components/sidebar-edit-mode/page-panels/index.js | 9 +++------ .../components/sidebar-edit-mode/page-panels/style.scss | 4 ++-- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/index.js b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/index.js index 5ce102560a8b2a..6241670e78e21b 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/index.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/index.js @@ -65,13 +65,10 @@ export default function PagePanels() { - +
    { getTemplateTitle() }
    -
    +
    From a468d55a1c893c22dad167b5365ad269597b0ea7 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Thu, 25 May 2023 16:40:17 +1000 Subject: [PATCH 33/44] Update removePageFromBlockContext() test --- .../edit-site/src/utils/test/remove-page-from-block-context.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/edit-site/src/utils/test/remove-page-from-block-context.js b/packages/edit-site/src/utils/test/remove-page-from-block-context.js index 833bdd35eb91b5..28ca9d7d950350 100644 --- a/packages/edit-site/src/utils/test/remove-page-from-block-context.js +++ b/packages/edit-site/src/utils/test/remove-page-from-block-context.js @@ -12,8 +12,6 @@ describe( 'removePageFromBlockContext', () => { templateSlug: 'my-template', } ) ).toEqual( { - postType: null, - postId: null, templateSlug: 'my-template', } ); } ); From 261d076f689b0eb5558d03192442d3b4a7d0cc85 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Thu, 25 May 2023 16:55:20 +1000 Subject: [PATCH 34/44] Fix post context from appearing in Edit Template preview We have to set postId and postType to null for the preview and omit them in the editor. No point having helper methods, therefore. --- .../edit-site/src/components/editor/index.js | 45 +++++++------------ .../sidebar-edit-mode/page-panels/index.js | 3 +- .../utils/remove-page-from-block-context.js | 7 --- .../test/remove-page-from-block-context.js | 18 -------- 4 files changed, 18 insertions(+), 55 deletions(-) delete mode 100644 packages/edit-site/src/utils/remove-page-from-block-context.js delete mode 100644 packages/edit-site/src/utils/test/remove-page-from-block-context.js diff --git a/packages/edit-site/src/components/editor/index.js b/packages/edit-site/src/components/editor/index.js index 2e753a8d2dbc7c..2f550a2b94d604 100644 --- a/packages/edit-site/src/components/editor/index.js +++ b/packages/edit-site/src/components/editor/index.js @@ -42,7 +42,6 @@ import CanvasSpinner from '../canvas-spinner'; import { unlock } from '../../private-apis'; import useEditedEntityRecord from '../use-edited-entity-record'; import { SidebarFixedBottomSlot } from '../sidebar-edit-mode/sidebar-fixed-bottom'; -import removePageFromBlockContext from '../../utils/remove-page-from-block-context'; const interfaceLabels = { /* translators: accessibility text for the editor content landmark region. */ @@ -125,16 +124,23 @@ export default function Editor( { isLoading } ) { const secondarySidebarLabel = isListViewOpen ? __( 'List View' ) : __( 'Block Library' ); - const blockContext = useMemo( - () => - addQueryContextToBlockContext( - hasPageContentLock - ? context - : removePageFromBlockContext( context ), - setEditedPostContext - ), - [ hasPageContentLock, context, setEditedPostContext ] - ); + const blockContext = useMemo( () => { + const { postType, postId, ...nonPostFields } = context ?? {}; + return { + ...( hasPageContentLock ? context : nonPostFields ), + queryContext: [ + context?.queryContext || { page: 1 }, + ( newQueryContext ) => + setEditedPostContext( { + ...context, + queryContext: { + ...context?.queryContext, + ...newQueryContext, + }, + } ), + ], + }; + }, [ hasPageContentLock, context, setEditedPostContext ] ); let title; if ( hasLoadedPost ) { @@ -247,20 +253,3 @@ export default function Editor( { isLoading } ) { ); } - -function addQueryContextToBlockContext( context, setContext ) { - return { - ...context, - queryContext: [ - context?.queryContext || { page: 1 }, - ( newQueryContext ) => - setContext( { - ...context, - queryContext: { - ...context?.queryContext, - ...newQueryContext, - }, - } ), - ], - }; -} diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/index.js b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/index.js index 0036eee464dd75..8f8675d2b5b891 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/index.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/index.js @@ -19,7 +19,6 @@ import { useMemo } from '@wordpress/element'; */ import { store as editSiteStore } from '../../../store'; import useEditedEntityRecord from '../../use-edited-entity-record'; -import removePageFromBlockContext from '../../../utils/remove-page-from-block-context'; import SidebarCard from '../sidebar-card'; import ContentBlocksList from './content-blocks-list'; @@ -41,7 +40,7 @@ export default function PagePanels() { const { togglePageContentLock } = useDispatch( editSiteStore ); const blockContext = useMemo( - () => removePageFromBlockContext( context ), + () => ( { ...context, postType: null, postId: null } ), [ context ] ); diff --git a/packages/edit-site/src/utils/remove-page-from-block-context.js b/packages/edit-site/src/utils/remove-page-from-block-context.js deleted file mode 100644 index 44ba4a8aa6ccd7..00000000000000 --- a/packages/edit-site/src/utils/remove-page-from-block-context.js +++ /dev/null @@ -1,7 +0,0 @@ -export default function removePageFromBlockContext( context ) { - if ( context ) { - const { postType, postId, ...rest } = context; - return rest; - } - return context; -} diff --git a/packages/edit-site/src/utils/test/remove-page-from-block-context.js b/packages/edit-site/src/utils/test/remove-page-from-block-context.js deleted file mode 100644 index 28ca9d7d950350..00000000000000 --- a/packages/edit-site/src/utils/test/remove-page-from-block-context.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Internal dependencies - */ -import removePageFromBlockContext from '../remove-page-from-block-context'; - -describe( 'removePageFromBlockContext', () => { - it( 'should remove the page from the block context', () => { - expect( - removePageFromBlockContext( { - postType: 'page', - postId: 123, - templateSlug: 'my-template', - } ) - ).toEqual( { - templateSlug: 'my-template', - } ); - } ); -} ); From 64d0e43b5439c4937bd84484bb0ff60055623136 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Fri, 26 May 2023 08:50:21 +1000 Subject: [PATCH 35/44] Clear block selection when switching from template focus to page focus --- .../data/data-core-edit-site.md | 20 +++++------ .../document-actions/index.js | 6 ++-- .../use-page-content-lock-notifications.js | 12 +++---- .../sidebar-edit-mode/page-panels/index.js | 4 +-- packages/edit-site/src/store/actions.js | 24 +++++++------ packages/edit-site/src/store/reducer.js | 4 +-- packages/edit-site/src/store/test/actions.js | 34 +++++++++++++------ packages/edit-site/src/store/test/reducer.js | 19 ++--------- 8 files changed, 62 insertions(+), 61 deletions(-) diff --git a/docs/reference-guides/data/data-core-edit-site.md b/docs/reference-guides/data/data-core-edit-site.md index aae6188cba2dd7..523bb8d2bbff5f 100644 --- a/docs/reference-guides/data/data-core-edit-site.md +++ b/docs/reference-guides/data/data-core-edit-site.md @@ -280,6 +280,14 @@ _Returns_ - `number`: The resolved template ID for the page route. +### setHasPageContentLock + +Sets whether or not the editor is locked so that only page content can be edited. + +_Parameters_ + +- _hasPageContentLock_ `boolean`: True to enable lock, false to disable. + ### setHomeTemplateId > **Deprecated** @@ -383,18 +391,6 @@ _Parameters_ - _featureName_ `string`: Feature name. -### togglePageContentLock - -Action that toggles whether or not the editor is locked so that only page content can be edited. - -_Parameters_ - -- _hasPageContentLock_ `boolean`: True to enable lock, false to disable, or undefined to toggle. - -_Returns_ - -- `Object`: Action object. - ### updateSettings Returns an action object used to update the settings. diff --git a/packages/edit-site/src/components/header-edit-mode/document-actions/index.js b/packages/edit-site/src/components/header-edit-mode/document-actions/index.js index 8f95e1efe10e2b..a23c9c3595d32e 100644 --- a/packages/edit-site/src/components/header-edit-mode/document-actions/index.js +++ b/packages/edit-site/src/components/header-edit-mode/document-actions/index.js @@ -52,7 +52,7 @@ function PageDocumentActions() { context.postId ); - const { togglePageContentLock } = useDispatch( editSiteStore ); + const { setHasPageContentLock } = useDispatch( editSiteStore ); if ( ! hasResolved ) { return null; @@ -71,7 +71,9 @@ function PageDocumentActions() { { editedRecord.title } ) : ( - togglePageContentLock() } /> + setHasPageContentLock( true ) } + /> ); } diff --git a/packages/edit-site/src/components/page-content-lock/use-page-content-lock-notifications.js b/packages/edit-site/src/components/page-content-lock/use-page-content-lock-notifications.js index f03f33914fd200..2a800317a33a95 100644 --- a/packages/edit-site/src/components/page-content-lock/use-page-content-lock-notifications.js +++ b/packages/edit-site/src/components/page-content-lock/use-page-content-lock-notifications.js @@ -44,7 +44,7 @@ function useEditTemplateNotification() { const alreadySeen = useRef( false ); const { createInfoNotice } = useDispatch( noticesStore ); - const { togglePageContentLock } = useDispatch( editSiteStore ); + const { setHasPageContentLock } = useDispatch( editSiteStore ); return useRefEffect( ( node ) => { @@ -63,7 +63,7 @@ function useEditTemplateNotification() { { label: __( 'Edit template' ), onClick: () => - togglePageContentLock( false ), + setHasPageContentLock( false ), }, ], } @@ -78,7 +78,7 @@ function useEditTemplateNotification() { hasPageContentLock, alreadySeen, createInfoNotice, - togglePageContentLock, + setHasPageContentLock, ] ); } @@ -97,7 +97,7 @@ function useBackToPageNotification() { const prevHasPageContentLock = useRef( false ); const { createInfoNotice } = useDispatch( noticesStore ); - const { togglePageContentLock } = useDispatch( editSiteStore ); + const { setHasPageContentLock } = useDispatch( editSiteStore ); useEffect( () => { if ( @@ -111,7 +111,7 @@ function useBackToPageNotification() { actions: [ { label: __( 'Back to page' ), - onClick: () => togglePageContentLock( true ), + onClick: () => setHasPageContentLock( true ), }, ], } ); @@ -123,6 +123,6 @@ function useBackToPageNotification() { prevHasPageContentLock, hasPageContentLock, createInfoNotice, - togglePageContentLock, + setHasPageContentLock, ] ); } diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/index.js b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/index.js index 8f8675d2b5b891..c913a689d54dc2 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/index.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/index.js @@ -37,7 +37,7 @@ export default function PagePanels() { record: template, } = useEditedEntityRecord(); - const { togglePageContentLock } = useDispatch( editSiteStore ); + const { setHasPageContentLock } = useDispatch( editSiteStore ); const blockContext = useMemo( () => ( { ...context, postType: null, postId: null } ), @@ -78,7 +78,7 @@ export default function PagePanels() { diff --git a/packages/edit-site/src/store/actions.js b/packages/edit-site/src/store/actions.js index 542cb1831cfacc..02ea870f698cb6 100644 --- a/packages/edit-site/src/store/actions.js +++ b/packages/edit-site/src/store/actions.js @@ -531,17 +531,19 @@ export const switchEditorMode = }; /** - * Action that toggles whether or not the editor is locked so that only page - * content can be edited. + * Sets whether or not the editor is locked so that only page content can be + * edited. * - * @param {boolean} hasPageContentLock True to enable lock, false to disable, or - * undefined to toggle. - * - * @return {Object} Action object. + * @param {boolean} hasPageContentLock True to enable lock, false to disable. */ -export function togglePageContentLock( hasPageContentLock ) { - return { - type: 'TOGGLE_PAGE_CONTENT_LOCK', - hasPageContentLock, +export const setHasPageContentLock = + ( hasPageContentLock ) => + ( { dispatch, registry } ) => { + if ( hasPageContentLock ) { + registry.dispatch( blockEditorStore ).clearSelectedBlock(); + } + dispatch( { + type: 'SET_HAS_PAGE_CONTENT_LOCK', + hasPageContentLock, + } ); }; -} diff --git a/packages/edit-site/src/store/reducer.js b/packages/edit-site/src/store/reducer.js index 1008afd95176f2..a003ee958894e5 100644 --- a/packages/edit-site/src/store/reducer.js +++ b/packages/edit-site/src/store/reducer.js @@ -169,8 +169,8 @@ export function hasPageContentLock( state = false, action ) { switch ( action.type ) { case 'SET_EDITED_POST': return !! action.context?.postId; - case 'TOGGLE_PAGE_CONTENT_LOCK': - return action.hasPageContentLock ?? ! state; + case 'SET_HAS_PAGE_CONTENT_LOCK': + return action.hasPageContentLock; } return state; diff --git a/packages/edit-site/src/store/test/actions.js b/packages/edit-site/src/store/test/actions.js index 159b13252f161a..cca479e2776626 100644 --- a/packages/edit-site/src/store/test/actions.js +++ b/packages/edit-site/src/store/test/actions.js @@ -13,7 +13,7 @@ import { store as preferencesStore } from '@wordpress/preferences'; * Internal dependencies */ import { store as editSiteStore } from '..'; -import { togglePageContentLock } from '../actions'; +import { setHasPageContentLock } from '../actions'; const ENTITY_TYPES = { wp_template: { @@ -217,19 +217,33 @@ describe( 'actions', () => { } ); } ); - describe( 'togglePageContentLock', () => { - it( 'returns the correct toggle action', () => { - expect( togglePageContentLock( true ) ).toEqual( { - type: 'TOGGLE_PAGE_CONTENT_LOCK', + describe( 'setHasPageContentLock', () => { + it( 'toggles the page content lock on', () => { + const dispatch = jest.fn(); + const clearSelectedBlock = jest.fn(); + const registry = { + dispatch: () => ( { clearSelectedBlock } ), + }; + setHasPageContentLock( true )( { dispatch, registry } ); + expect( clearSelectedBlock ).toHaveBeenCalled(); + expect( dispatch ).toHaveBeenCalledWith( { + type: 'SET_HAS_PAGE_CONTENT_LOCK', hasPageContentLock: true, } ); - expect( togglePageContentLock( false ) ).toEqual( { - type: 'TOGGLE_PAGE_CONTENT_LOCK', + } ); + + it( 'toggles the page content lock off', () => { + const dispatch = jest.fn(); + const clearSelectedBlock = jest.fn(); + const registry = { + dispatch: () => ( { clearSelectedBlock } ), + }; + setHasPageContentLock( false )( { dispatch, registry } ); + expect( clearSelectedBlock ).not.toHaveBeenCalled(); + expect( dispatch ).toHaveBeenCalledWith( { + type: 'SET_HAS_PAGE_CONTENT_LOCK', hasPageContentLock: false, } ); - expect( togglePageContentLock() ).toEqual( { - type: 'TOGGLE_PAGE_CONTENT_LOCK', - } ); } ); } ); } ); diff --git a/packages/edit-site/src/store/test/reducer.js b/packages/edit-site/src/store/test/reducer.js index 0ea196f1079a9c..1ddc6bfb6fa7b7 100644 --- a/packages/edit-site/src/store/test/reducer.js +++ b/packages/edit-site/src/store/test/reducer.js @@ -164,32 +164,19 @@ describe( 'state', () => { ).toBe( true ); } ); - it( 'can be explicitly set', () => { + it( 'can be set', () => { expect( hasPageContentLock( false, { - type: 'TOGGLE_PAGE_CONTENT_LOCK', + type: 'SET_HAS_PAGE_CONTENT_LOCK', hasPageContentLock: true, } ) ).toBe( true ); expect( hasPageContentLock( true, { - type: 'TOGGLE_PAGE_CONTENT_LOCK', + type: 'SET_HAS_PAGE_CONTENT_LOCK', hasPageContentLock: false, } ) ).toBe( false ); } ); - - it( 'can be toggled', () => { - expect( - hasPageContentLock( true, { - type: 'TOGGLE_PAGE_CONTENT_LOCK', - } ) - ).toBe( false ); - expect( - hasPageContentLock( false, { - type: 'TOGGLE_PAGE_CONTENT_LOCK', - } ) - ).toBe( true ); - } ); } ); } ); From c8602585ab8c6b5046d95c4a6a3896050624f0d2 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Fri, 26 May 2023 09:26:29 +1000 Subject: [PATCH 36/44] Prevent insertion into a disabled block --- packages/block-editor/src/store/selectors.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js index a511dc35886038..2744a7bc84d103 100644 --- a/packages/block-editor/src/store/selectors.js +++ b/packages/block-editor/src/store/selectors.js @@ -1540,6 +1540,10 @@ const canInsertBlockTypeUnmemoized = ( return false; } + if ( getBlockEditingMode( state, rootClientId ) === 'disabled' ) { + return false; + } + const parentBlockListSettings = getBlockListSettings( state, rootClientId ); // The parent block doesn't have settings indicating it doesn't support From c22368a0bb49a91621f8d39b51d7e7b00ea30694 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Fri, 26 May 2023 09:41:44 +1000 Subject: [PATCH 37/44] Don't allow removing and moving children of disabled blocks --- packages/block-editor/src/store/selectors.js | 38 ++++++++++---------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js index 2744a7bc84d103..55de64a93bc781 100644 --- a/packages/block-editor/src/store/selectors.js +++ b/packages/block-editor/src/store/selectors.js @@ -1668,21 +1668,19 @@ export function canInsertBlocks( state, clientIds, rootClientId = null ) { */ export function canRemoveBlock( state, clientId, rootClientId = null ) { const attributes = getBlockAttributes( state, clientId ); - - // attributes can be null if the block is already deleted. if ( attributes === null ) { return true; } - - const { lock } = attributes; - const parentIsLocked = !! getTemplateLock( state, rootClientId ); - // If we don't have a lock on the blockType level, we defer to the parent templateLock. - if ( lock === undefined || lock?.remove === undefined ) { - return ! parentIsLocked; + if ( attributes.lock?.remove ) { + return false; } - - // When remove is true, it means we cannot remove it. - return ! lock?.remove; + if ( getTemplateLock( state, rootClientId ) ) { + return false; + } + if ( getBlockEditingMode( state, rootClientId ) === 'disabled' ) { + return false; + } + return true; } /** @@ -1714,16 +1712,16 @@ export function canMoveBlock( state, clientId, rootClientId = null ) { if ( attributes === null ) { return; } - - const { lock } = attributes; - const parentIsLocked = getTemplateLock( state, rootClientId ) === 'all'; - // If we don't have a lock on the blockType level, we defer to the parent templateLock. - if ( lock === undefined || lock?.move === undefined ) { - return ! parentIsLocked; + if ( attributes.lock?.move ) { + return false; } - - // When move is true, it means we cannot move it. - return ! lock?.move; + if ( getTemplateLock( state, rootClientId ) === 'all' ) { + return false; + } + if ( getBlockEditingMode( state, rootClientId ) === 'disabled' ) { + return false; + } + return true; } /** From 32b541373ae456db6c395d4688fd4df4071be49e Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Fri, 26 May 2023 11:52:41 +1000 Subject: [PATCH 38/44] Work around @wordpress/data bug by not using createRegistrySelector() for now --- .../src/store/private-selectors.js | 58 +++++++++---------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/packages/block-editor/src/store/private-selectors.js b/packages/block-editor/src/store/private-selectors.js index ce7802036184e5..1034bab412a586 100644 --- a/packages/block-editor/src/store/private-selectors.js +++ b/packages/block-editor/src/store/private-selectors.js @@ -6,7 +6,7 @@ import createSelector from 'rememo'; /** * WordPress dependencies */ -import { createRegistrySelector } from '@wordpress/data'; +import { select } from '@wordpress/data'; import { store as blocksStore } from '@wordpress/blocks'; /** @@ -71,35 +71,33 @@ export function getLastInsertedBlocksClientIds( state ) { * @return {BlockEditingMode} The block editing mode. One of `'disabled'`, * `'contentOnly'`, or `'default'`. */ -export const getBlockEditingMode = createRegistrySelector( - ( select ) => - ( state, clientId = '' ) => { - const explicitEditingMode = getExplcitBlockEditingMode( - state, - clientId - ); - const rootClientId = getBlockRootClientId( state, clientId ); - const templateLock = getTemplateLock( state, rootClientId ); - const name = getBlockName( state, clientId ); - const isContent = - select( blocksStore ).__experimentalHasContentRoleAttribute( - name - ); - if ( - explicitEditingMode === 'disabled' || - ( templateLock === 'contentOnly' && ! isContent ) - ) { - return 'disabled'; - } - if ( - explicitEditingMode === 'contentOnly' || - ( templateLock === 'contentOnly' && isContent ) - ) { - return 'contentOnly'; - } - return 'default'; - } -); +export const getBlockEditingMode = ( state, clientId = '' ) => { + const explicitEditingMode = getExplcitBlockEditingMode( state, clientId ); + const rootClientId = getBlockRootClientId( state, clientId ); + const templateLock = getTemplateLock( state, rootClientId ); + const name = getBlockName( state, clientId ); + // TODO: Terrible hack! We're calling the global select() function here + // instead of using createRegistrySelector(). The problem with using + // createRegistrySelector() is that then the public block-editor selectors + // (e.g. canInsertBlockTypeUnmemoized) can't call this private block-editor + // selector due to a bug in @wordpress/data. See + // https://github.com/WordPress/gutenberg/pull/50985. + const isContent = + select( blocksStore ).__experimentalHasContentRoleAttribute( name ); + if ( + explicitEditingMode === 'disabled' || + ( templateLock === 'contentOnly' && ! isContent ) + ) { + return 'disabled'; + } + if ( + explicitEditingMode === 'contentOnly' || + ( templateLock === 'contentOnly' && isContent ) + ) { + return 'contentOnly'; + } + return 'default'; +}; const getExplcitBlockEditingMode = createSelector( ( state, clientId = '' ) => { From 9eba2068716dce9f79c1190c60ac6ff1f2de6689 Mon Sep 17 00:00:00 2001 From: ramon Date: Wed, 31 May 2023 12:21:57 +1000 Subject: [PATCH 39/44] Fix typo --- packages/block-editor/src/store/private-selectors.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/block-editor/src/store/private-selectors.js b/packages/block-editor/src/store/private-selectors.js index 1034bab412a586..bcc032a4ee9037 100644 --- a/packages/block-editor/src/store/private-selectors.js +++ b/packages/block-editor/src/store/private-selectors.js @@ -72,7 +72,7 @@ export function getLastInsertedBlocksClientIds( state ) { * `'contentOnly'`, or `'default'`. */ export const getBlockEditingMode = ( state, clientId = '' ) => { - const explicitEditingMode = getExplcitBlockEditingMode( state, clientId ); + const explicitEditingMode = getExplicitBlockEditingMode( state, clientId ); const rootClientId = getBlockRootClientId( state, clientId ); const templateLock = getTemplateLock( state, rootClientId ); const name = getBlockName( state, clientId ); @@ -99,7 +99,7 @@ export const getBlockEditingMode = ( state, clientId = '' ) => { return 'default'; }; -const getExplcitBlockEditingMode = createSelector( +const getExplicitBlockEditingMode = createSelector( ( state, clientId = '' ) => { while ( ! state.blockEditingModes.has( clientId ) && From 245a0bbb84dc7378fdcb81f7a5fa9fccae9aa4a1 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Thu, 1 Jun 2023 11:23:48 +1000 Subject: [PATCH 40/44] Fix select() mock --- .../src/store/test/private-selectors.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/block-editor/src/store/test/private-selectors.js b/packages/block-editor/src/store/test/private-selectors.js index 954c8c94c13799..f9bde867b1032e 100644 --- a/packages/block-editor/src/store/test/private-selectors.js +++ b/packages/block-editor/src/store/test/private-selectors.js @@ -1,3 +1,8 @@ +/** + * WordPress dependencies + */ +import { select } from '@wordpress/data'; + /** * Internal dependencies */ @@ -7,6 +12,10 @@ import { getBlockEditingMode, } from '../private-selectors'; +jest.mock( '@wordpress/data/src/select', () => ( { + select: jest.fn(), +} ) ); + describe( 'private selectors', () => { describe( 'isBlockInterfaceHidden', () => { it( 'should return the true if toggled true in state', () => { @@ -92,11 +101,9 @@ describe( 'private selectors', () => { }; const __experimentalHasContentRoleAttribute = jest.fn( () => false ); - getBlockEditingMode.registry = { - select: jest.fn( () => ( { - __experimentalHasContentRoleAttribute, - } ) ), - }; + select.mockReturnValue( { + __experimentalHasContentRoleAttribute, + } ); it( 'should return default by default', () => { expect( From 97e8f23bff74d3cd93cde0ca0c21e36a68552d1c Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Thu, 1 Jun 2023 11:51:56 +1000 Subject: [PATCH 41/44] Fix block-editor selector tests --- packages/block-editor/src/store/selectors.js | 3 +- .../block-editor/src/store/test/selectors.js | 99 +++++++++++++++++++ 2 files changed, 101 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js index 55de64a93bc781..5b615f67defbd4 100644 --- a/packages/block-editor/src/store/selectors.js +++ b/packages/block-editor/src/store/selectors.js @@ -1540,7 +1540,7 @@ const canInsertBlockTypeUnmemoized = ( return false; } - if ( getBlockEditingMode( state, rootClientId ) === 'disabled' ) { + if ( getBlockEditingMode( state, rootClientId ?? '' ) === 'disabled' ) { return false; } @@ -1638,6 +1638,7 @@ export const canInsertBlockType = createSelector( state.blocks.byClientId.get( rootClientId ), state.settings.allowedBlockTypes, state.settings.templateLock, + state.blockEditingModes, ] ); diff --git a/packages/block-editor/src/store/test/selectors.js b/packages/block-editor/src/store/test/selectors.js index 60d90d80b9d41e..5cc17fc08b3142 100644 --- a/packages/block-editor/src/store/test/selectors.js +++ b/packages/block-editor/src/store/test/selectors.js @@ -2693,11 +2693,13 @@ describe( 'selectors', () => { blocks: { byClientId: new Map(), attributes: new Map(), + parents: new Map(), }, blockListSettings: {}, settings: { allowedBlockTypes: [ 'core/test-block-a' ], }, + blockEditingModes: new Map(), }; expect( canInsertBlockType( state, 'core/test-block-a' ) ).toBe( true @@ -2720,14 +2722,36 @@ describe( 'selectors', () => { ); } ); + it( 'should deny blocks when the editor has a disabled editing mode', () => { + const state = { + blocks: { + byClientId: new Map(), + attributes: new Map(), + parents: new Map(), + }, + blockListSettings: {}, + settings: {}, + blockEditingModes: new Map( + Object.entries( { + '': 'disabled', + } ) + ), + }; + expect( canInsertBlockType( state, 'core/test-block-a' ) ).toBe( + false + ); + } ); + it( 'should deny blocks that restrict parent from being inserted into the root', () => { const state = { blocks: { byClientId: new Map(), attributes: new Map(), + parents: new Map(), }, blockListSettings: {}, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlockType( state, 'core/test-block-c' ) ).toBe( false @@ -2747,9 +2771,11 @@ describe( 'selectors', () => { block1: {}, } ) ), + parents: new Map(), }, blockListSettings: {}, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlockType( state, 'core/test-block-c', 'block1' ) @@ -2769,11 +2795,13 @@ describe( 'selectors', () => { block1: {}, } ) ), + parents: new Map(), }, blockListSettings: { block1: {}, }, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlockType( state, 'core/test-block-c', 'block1' ) @@ -2793,11 +2821,13 @@ describe( 'selectors', () => { block1: {}, } ) ), + parents: new Map(), }, blockListSettings: { block1: {}, }, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlockType( state, 'core/test-block-c', 'block1' ) @@ -2817,6 +2847,7 @@ describe( 'selectors', () => { block1: {}, } ) ), + parents: new Map(), }, blockListSettings: { block1: { @@ -2824,6 +2855,7 @@ describe( 'selectors', () => { }, }, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlockType( state, 'core/test-block-b', 'block1' ) @@ -2843,6 +2875,7 @@ describe( 'selectors', () => { block1: {}, } ) ), + parents: new Map(), }, blockListSettings: { block1: { @@ -2850,12 +2883,41 @@ describe( 'selectors', () => { }, }, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlockType( state, 'core/test-block-b', 'block1' ) ).toBe( true ); } ); + it( 'should deny blocks from being inserted into a block that has a disabled editing mode', () => { + const state = { + blocks: { + byClientId: new Map( + Object.entries( { + block1: { name: 'core/test-block-a' }, + } ) + ), + attributes: new Map( + Object.entries( { + block1: {}, + } ) + ), + parents: new Map(), + }, + blockListSettings: {}, + settings: {}, + blockEditingModes: new Map( + Object.entries( { + block1: 'disabled', + } ) + ), + }; + expect( + canInsertBlockType( state, 'core/test-block-b', 'block1' ) + ).toBe( false ); + } ); + it( 'should prioritise parent over allowedBlocks', () => { const state = { blocks: { @@ -2869,6 +2931,7 @@ describe( 'selectors', () => { block1: {}, } ) ), + parents: new Map(), }, blockListSettings: { block1: { @@ -2876,6 +2939,7 @@ describe( 'selectors', () => { }, }, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlockType( state, 'core/test-block-c', 'block1' ) @@ -2895,9 +2959,11 @@ describe( 'selectors', () => { block1: {}, } ) ), + parents: new Map(), }, blockListSettings: {}, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlockType( state, 'core/post-content-child', 'block1' ) @@ -2909,9 +2975,11 @@ describe( 'selectors', () => { blocks: { byClientId: new Map(), attributes: new Map(), + parents: new Map(), }, blockListSettings: {}, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlockType( state, 'core/post-content-child' ) @@ -2944,6 +3012,7 @@ describe( 'selectors', () => { block2: {}, }, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlockType( @@ -2984,6 +3053,7 @@ describe( 'selectors', () => { block3: {}, }, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlockType( @@ -3023,6 +3093,7 @@ describe( 'selectors', () => { block3: {}, }, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlockType( @@ -3062,6 +3133,7 @@ describe( 'selectors', () => { block3: {}, }, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlockType( @@ -3100,6 +3172,7 @@ describe( 'selectors', () => { }, }, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlockType( @@ -3136,6 +3209,7 @@ describe( 'selectors', () => { block2: {}, }, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlockType( @@ -3165,6 +3239,7 @@ describe( 'selectors', () => { 3: {}, } ) ), + parents: new Map(), }, blockListSettings: { 1: { @@ -3175,6 +3250,7 @@ describe( 'selectors', () => { }, }, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlocks( state, [ '2', '3' ], '1' ) ).toBe( true ); } ); @@ -3196,6 +3272,7 @@ describe( 'selectors', () => { 3: {}, } ) ), + parents: new Map(), }, blockListSettings: { 1: { @@ -3203,6 +3280,7 @@ describe( 'selectors', () => { }, }, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlocks( state, [ '2', '3' ], '1' ) ).toBe( false ); } ); @@ -3241,6 +3319,7 @@ describe( 'selectors', () => { // See: https://github.com/WordPress/gutenberg/issues/14580 preferences: {}, blockListSettings: {}, + blockEditingModes: new Map(), }; const items = getInserterItems( state ); const testBlockAItem = items.find( @@ -3349,6 +3428,7 @@ describe( 'selectors', () => { block3: {}, block4: {}, }, + blockEditingModes: new Map(), }; const stateSecondBlockRestricted = { @@ -3436,6 +3516,7 @@ describe( 'selectors', () => { }, blockListSettings: {}, settings: {}, + blockEditingModes: new Map(), }; const items = getInserterItems( state ); const testBlockBItem = items.find( @@ -3460,6 +3541,7 @@ describe( 'selectors', () => { }, blockListSettings: {}, settings: {}, + blockEditingModes: new Map(), }; const items = getInserterItems( state ); const reusableBlock2Item = items.find( @@ -3551,6 +3633,7 @@ describe( 'selectors', () => { settings: {}, preferences: {}, blockListSettings: {}, + blockEditingModes: new Map(), }; const blocks = [ { name: 'core/with-tranforms-a' } ]; const items = getBlockTransformItems( state, blocks ); @@ -3591,6 +3674,7 @@ describe( 'selectors', () => { settings: {}, preferences: {}, blockListSettings: {}, + blockEditingModes: new Map(), }; const block = { name: 'core/with-tranforms-a' }; const items = getBlockTransformItems( state, block ); @@ -3629,6 +3713,7 @@ describe( 'selectors', () => { }, block2: {}, }, + blockEditingModes: new Map(), }; const blocks = [ { clientId: 'block2', name: 'core/with-tranforms-a' }, @@ -3676,6 +3761,7 @@ describe( 'selectors', () => { }, blockListSettings: {}, settings: {}, + blockEditingModes: new Map(), }; const blocks = [ { name: 'core/with-tranforms-a' } ]; const items = getBlockTransformItems( state, blocks ); @@ -3709,6 +3795,7 @@ describe( 'selectors', () => { }, blockListSettings: {}, settings: {}, + blockEditingModes: new Map(), }; const blocks = [ { name: 'core/with-tranforms-c' } ]; const items = getBlockTransformItems( state, blocks ); @@ -4121,6 +4208,12 @@ describe( 'selectors', () => { block2: {}, } ) ), + parents: new Map( + Object.entries( { + block1: '', + block2: '', + } ) + ), }, blockListSettings: { block1: { @@ -4152,6 +4245,7 @@ describe( 'selectors', () => { }, ], }, + blockEditingModes: new Map(), }; it( 'should return all patterns for root level', () => { @@ -4249,6 +4343,7 @@ describe( 'selectors', () => { block1: { name: 'core/test-block-a' }, } ) ), + parents: new Map(), }, blockListSettings: { block1: { @@ -4279,6 +4374,7 @@ describe( 'selectors', () => { }, ], }, + blockEditingModes: new Map(), }; it( 'should return empty array if no block name is provided', () => { expect( getPatternsByBlockTypes( state ) ).toEqual( [] ); @@ -4329,6 +4425,7 @@ describe( 'selectors', () => { block2: { name: 'core/test-block-b' }, } ) ), + parents: new Map(), controlledInnerBlocks: { 'block2-clientId': true }, }, blockListSettings: { @@ -4371,6 +4468,7 @@ describe( 'selectors', () => { }, ], }, + blockEditingModes: new Map(), }; describe( 'should return empty array', () => { it( 'when no blocks are selected', () => { @@ -4591,6 +4689,7 @@ describe( 'getInserterItems with core blocks prioritization', () => { settings: {}, preferences: {}, blockListSettings: {}, + blockEditingModes: new Map(), }; const items = getInserterItems( state ); const expectedResult = [ From cd90a6308c8ab6e9e81be1854249d38975d481ce Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Thu, 1 Jun 2023 14:27:30 +1000 Subject: [PATCH 42/44] Revert block-editor changes --- .../components/block-list-appender/index.js | 5 +- .../src/components/block-list/content.scss | 20 ++-- .../src/store/private-selectors.js | 60 +++++------ packages/block-editor/src/store/selectors.js | 51 ++++------ .../src/store/test/private-selectors.js | 17 +--- .../block-editor/src/store/test/selectors.js | 99 ------------------- 6 files changed, 69 insertions(+), 183 deletions(-) diff --git a/packages/block-editor/src/components/block-list-appender/index.js b/packages/block-editor/src/components/block-list-appender/index.js index 99d0fc56374e42..56c044b6c5a8ab 100644 --- a/packages/block-editor/src/components/block-list-appender/index.js +++ b/packages/block-editor/src/components/block-list-appender/index.js @@ -15,7 +15,6 @@ import { getDefaultBlockName } from '@wordpress/blocks'; import DefaultBlockAppender from '../default-block-appender'; import ButtonBlockAppender from '../button-block-appender'; import { store as blockEditorStore } from '../../store'; -import { unlock } from '../../lock-unlock'; function DefaultAppender( { rootClientId } ) { const canInsertDefaultBlock = useSelect( ( select ) => @@ -47,15 +46,13 @@ function useAppender( rootClientId, CustomAppender ) { getTemplateLock, getSelectedBlockClientId, __unstableGetEditorMode, - getBlockEditingMode, - } = unlock( select( blockEditorStore ) ); + } = select( blockEditorStore ); const selectedBlockClientId = getSelectedBlockClientId(); return { hideInserter: !! getTemplateLock( rootClientId ) || - getBlockEditingMode( rootClientId ) === 'disabled' || __unstableGetEditorMode() === 'zoom-out', isParentSelected: rootClientId === selectedBlockClientId || diff --git a/packages/block-editor/src/components/block-list/content.scss b/packages/block-editor/src/components/block-list/content.scss index a163ddaa789551..dab07ced873e9f 100644 --- a/packages/block-editor/src/components/block-list/content.scss +++ b/packages/block-editor/src/components/block-list/content.scss @@ -161,6 +161,15 @@ padding: 0; } +.block-editor-block-list__layout, +.block-editor-block-list__block { + pointer-events: initial; + + &.is-editing-disabled { + pointer-events: none; + } +} + .block-editor-block-list__layout .block-editor-block-list__block { // With `position: static`, Safari marks a full-width selection rectangle, including margins. // With `position: relative`, Safari marks an inline selection rectangle, similar to that of @@ -169,16 +178,11 @@ // We choose relative, as that matches the multi-selection, which is limited to the block footprint. position: relative; - // Break long strings of text without spaces so they don't overflow the block. - overflow-wrap: break-word; - - pointer-events: auto; + // Re-enable text-selection on editable blocks. user-select: text; - &.is-editing-disabled { - pointer-events: none; - user-select: none; - } + // Break long strings of text without spaces so they don't overflow the block. + overflow-wrap: break-word; .reusable-block-edit-panel * { z-index: z-index(".block-editor-block-list__block .reusable-block-edit-panel *"); diff --git a/packages/block-editor/src/store/private-selectors.js b/packages/block-editor/src/store/private-selectors.js index bcc032a4ee9037..ce7802036184e5 100644 --- a/packages/block-editor/src/store/private-selectors.js +++ b/packages/block-editor/src/store/private-selectors.js @@ -6,7 +6,7 @@ import createSelector from 'rememo'; /** * WordPress dependencies */ -import { select } from '@wordpress/data'; +import { createRegistrySelector } from '@wordpress/data'; import { store as blocksStore } from '@wordpress/blocks'; /** @@ -71,35 +71,37 @@ export function getLastInsertedBlocksClientIds( state ) { * @return {BlockEditingMode} The block editing mode. One of `'disabled'`, * `'contentOnly'`, or `'default'`. */ -export const getBlockEditingMode = ( state, clientId = '' ) => { - const explicitEditingMode = getExplicitBlockEditingMode( state, clientId ); - const rootClientId = getBlockRootClientId( state, clientId ); - const templateLock = getTemplateLock( state, rootClientId ); - const name = getBlockName( state, clientId ); - // TODO: Terrible hack! We're calling the global select() function here - // instead of using createRegistrySelector(). The problem with using - // createRegistrySelector() is that then the public block-editor selectors - // (e.g. canInsertBlockTypeUnmemoized) can't call this private block-editor - // selector due to a bug in @wordpress/data. See - // https://github.com/WordPress/gutenberg/pull/50985. - const isContent = - select( blocksStore ).__experimentalHasContentRoleAttribute( name ); - if ( - explicitEditingMode === 'disabled' || - ( templateLock === 'contentOnly' && ! isContent ) - ) { - return 'disabled'; - } - if ( - explicitEditingMode === 'contentOnly' || - ( templateLock === 'contentOnly' && isContent ) - ) { - return 'contentOnly'; - } - return 'default'; -}; +export const getBlockEditingMode = createRegistrySelector( + ( select ) => + ( state, clientId = '' ) => { + const explicitEditingMode = getExplcitBlockEditingMode( + state, + clientId + ); + const rootClientId = getBlockRootClientId( state, clientId ); + const templateLock = getTemplateLock( state, rootClientId ); + const name = getBlockName( state, clientId ); + const isContent = + select( blocksStore ).__experimentalHasContentRoleAttribute( + name + ); + if ( + explicitEditingMode === 'disabled' || + ( templateLock === 'contentOnly' && ! isContent ) + ) { + return 'disabled'; + } + if ( + explicitEditingMode === 'contentOnly' || + ( templateLock === 'contentOnly' && isContent ) + ) { + return 'contentOnly'; + } + return 'default'; + } +); -const getExplicitBlockEditingMode = createSelector( +const getExplcitBlockEditingMode = createSelector( ( state, clientId = '' ) => { while ( ! state.blockEditingModes.has( clientId ) && diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js index 5b615f67defbd4..487d13db811d84 100644 --- a/packages/block-editor/src/store/selectors.js +++ b/packages/block-editor/src/store/selectors.js @@ -26,7 +26,6 @@ import deprecated from '@wordpress/deprecated'; */ import { mapRichTextSettings } from './utils'; import { orderBy } from '../utils/sorting'; -import { getBlockEditingMode } from './private-selectors'; /** * A block selection object. @@ -1540,10 +1539,6 @@ const canInsertBlockTypeUnmemoized = ( return false; } - if ( getBlockEditingMode( state, rootClientId ?? '' ) === 'disabled' ) { - return false; - } - const parentBlockListSettings = getBlockListSettings( state, rootClientId ); // The parent block doesn't have settings indicating it doesn't support @@ -1638,7 +1633,6 @@ export const canInsertBlockType = createSelector( state.blocks.byClientId.get( rootClientId ), state.settings.allowedBlockTypes, state.settings.templateLock, - state.blockEditingModes, ] ); @@ -1669,19 +1663,21 @@ export function canInsertBlocks( state, clientIds, rootClientId = null ) { */ export function canRemoveBlock( state, clientId, rootClientId = null ) { const attributes = getBlockAttributes( state, clientId ); + + // attributes can be null if the block is already deleted. if ( attributes === null ) { return true; } - if ( attributes.lock?.remove ) { - return false; - } - if ( getTemplateLock( state, rootClientId ) ) { - return false; - } - if ( getBlockEditingMode( state, rootClientId ) === 'disabled' ) { - return false; + + const { lock } = attributes; + const parentIsLocked = !! getTemplateLock( state, rootClientId ); + // If we don't have a lock on the blockType level, we defer to the parent templateLock. + if ( lock === undefined || lock?.remove === undefined ) { + return ! parentIsLocked; } - return true; + + // When remove is true, it means we cannot remove it. + return ! lock?.remove; } /** @@ -1713,16 +1709,16 @@ export function canMoveBlock( state, clientId, rootClientId = null ) { if ( attributes === null ) { return; } - if ( attributes.lock?.move ) { - return false; - } - if ( getTemplateLock( state, rootClientId ) === 'all' ) { - return false; - } - if ( getBlockEditingMode( state, rootClientId ) === 'disabled' ) { - return false; + + const { lock } = attributes; + const parentIsLocked = getTemplateLock( state, rootClientId ) === 'all'; + // If we don't have a lock on the blockType level, we defer to the parent templateLock. + if ( lock === undefined || lock?.move === undefined ) { + return ! parentIsLocked; } - return true; + + // When move is true, it means we cannot move it. + return ! lock?.move; } /** @@ -2816,13 +2812,6 @@ export function __unstableGetTemporarilyEditingAsBlocks( state ) { } export function __unstableHasActiveBlockOverlayActive( state, clientId ) { - // Prevent overlay on disabled blocks. It's redundant since disabled blocks - // can't be selected, and prevents non-disabled nested blocks from being - // selected. - if ( getBlockEditingMode( state, clientId ) === 'disabled' ) { - return false; - } - // If the block editing is locked, the block overlay is always active. if ( ! canEditBlock( state, clientId ) ) { return true; diff --git a/packages/block-editor/src/store/test/private-selectors.js b/packages/block-editor/src/store/test/private-selectors.js index f9bde867b1032e..954c8c94c13799 100644 --- a/packages/block-editor/src/store/test/private-selectors.js +++ b/packages/block-editor/src/store/test/private-selectors.js @@ -1,8 +1,3 @@ -/** - * WordPress dependencies - */ -import { select } from '@wordpress/data'; - /** * Internal dependencies */ @@ -12,10 +7,6 @@ import { getBlockEditingMode, } from '../private-selectors'; -jest.mock( '@wordpress/data/src/select', () => ( { - select: jest.fn(), -} ) ); - describe( 'private selectors', () => { describe( 'isBlockInterfaceHidden', () => { it( 'should return the true if toggled true in state', () => { @@ -101,9 +92,11 @@ describe( 'private selectors', () => { }; const __experimentalHasContentRoleAttribute = jest.fn( () => false ); - select.mockReturnValue( { - __experimentalHasContentRoleAttribute, - } ); + getBlockEditingMode.registry = { + select: jest.fn( () => ( { + __experimentalHasContentRoleAttribute, + } ) ), + }; it( 'should return default by default', () => { expect( diff --git a/packages/block-editor/src/store/test/selectors.js b/packages/block-editor/src/store/test/selectors.js index 5cc17fc08b3142..60d90d80b9d41e 100644 --- a/packages/block-editor/src/store/test/selectors.js +++ b/packages/block-editor/src/store/test/selectors.js @@ -2693,13 +2693,11 @@ describe( 'selectors', () => { blocks: { byClientId: new Map(), attributes: new Map(), - parents: new Map(), }, blockListSettings: {}, settings: { allowedBlockTypes: [ 'core/test-block-a' ], }, - blockEditingModes: new Map(), }; expect( canInsertBlockType( state, 'core/test-block-a' ) ).toBe( true @@ -2722,36 +2720,14 @@ describe( 'selectors', () => { ); } ); - it( 'should deny blocks when the editor has a disabled editing mode', () => { - const state = { - blocks: { - byClientId: new Map(), - attributes: new Map(), - parents: new Map(), - }, - blockListSettings: {}, - settings: {}, - blockEditingModes: new Map( - Object.entries( { - '': 'disabled', - } ) - ), - }; - expect( canInsertBlockType( state, 'core/test-block-a' ) ).toBe( - false - ); - } ); - it( 'should deny blocks that restrict parent from being inserted into the root', () => { const state = { blocks: { byClientId: new Map(), attributes: new Map(), - parents: new Map(), }, blockListSettings: {}, settings: {}, - blockEditingModes: new Map(), }; expect( canInsertBlockType( state, 'core/test-block-c' ) ).toBe( false @@ -2771,11 +2747,9 @@ describe( 'selectors', () => { block1: {}, } ) ), - parents: new Map(), }, blockListSettings: {}, settings: {}, - blockEditingModes: new Map(), }; expect( canInsertBlockType( state, 'core/test-block-c', 'block1' ) @@ -2795,13 +2769,11 @@ describe( 'selectors', () => { block1: {}, } ) ), - parents: new Map(), }, blockListSettings: { block1: {}, }, settings: {}, - blockEditingModes: new Map(), }; expect( canInsertBlockType( state, 'core/test-block-c', 'block1' ) @@ -2821,13 +2793,11 @@ describe( 'selectors', () => { block1: {}, } ) ), - parents: new Map(), }, blockListSettings: { block1: {}, }, settings: {}, - blockEditingModes: new Map(), }; expect( canInsertBlockType( state, 'core/test-block-c', 'block1' ) @@ -2847,7 +2817,6 @@ describe( 'selectors', () => { block1: {}, } ) ), - parents: new Map(), }, blockListSettings: { block1: { @@ -2855,7 +2824,6 @@ describe( 'selectors', () => { }, }, settings: {}, - blockEditingModes: new Map(), }; expect( canInsertBlockType( state, 'core/test-block-b', 'block1' ) @@ -2875,7 +2843,6 @@ describe( 'selectors', () => { block1: {}, } ) ), - parents: new Map(), }, blockListSettings: { block1: { @@ -2883,41 +2850,12 @@ describe( 'selectors', () => { }, }, settings: {}, - blockEditingModes: new Map(), }; expect( canInsertBlockType( state, 'core/test-block-b', 'block1' ) ).toBe( true ); } ); - it( 'should deny blocks from being inserted into a block that has a disabled editing mode', () => { - const state = { - blocks: { - byClientId: new Map( - Object.entries( { - block1: { name: 'core/test-block-a' }, - } ) - ), - attributes: new Map( - Object.entries( { - block1: {}, - } ) - ), - parents: new Map(), - }, - blockListSettings: {}, - settings: {}, - blockEditingModes: new Map( - Object.entries( { - block1: 'disabled', - } ) - ), - }; - expect( - canInsertBlockType( state, 'core/test-block-b', 'block1' ) - ).toBe( false ); - } ); - it( 'should prioritise parent over allowedBlocks', () => { const state = { blocks: { @@ -2931,7 +2869,6 @@ describe( 'selectors', () => { block1: {}, } ) ), - parents: new Map(), }, blockListSettings: { block1: { @@ -2939,7 +2876,6 @@ describe( 'selectors', () => { }, }, settings: {}, - blockEditingModes: new Map(), }; expect( canInsertBlockType( state, 'core/test-block-c', 'block1' ) @@ -2959,11 +2895,9 @@ describe( 'selectors', () => { block1: {}, } ) ), - parents: new Map(), }, blockListSettings: {}, settings: {}, - blockEditingModes: new Map(), }; expect( canInsertBlockType( state, 'core/post-content-child', 'block1' ) @@ -2975,11 +2909,9 @@ describe( 'selectors', () => { blocks: { byClientId: new Map(), attributes: new Map(), - parents: new Map(), }, blockListSettings: {}, settings: {}, - blockEditingModes: new Map(), }; expect( canInsertBlockType( state, 'core/post-content-child' ) @@ -3012,7 +2944,6 @@ describe( 'selectors', () => { block2: {}, }, settings: {}, - blockEditingModes: new Map(), }; expect( canInsertBlockType( @@ -3053,7 +2984,6 @@ describe( 'selectors', () => { block3: {}, }, settings: {}, - blockEditingModes: new Map(), }; expect( canInsertBlockType( @@ -3093,7 +3023,6 @@ describe( 'selectors', () => { block3: {}, }, settings: {}, - blockEditingModes: new Map(), }; expect( canInsertBlockType( @@ -3133,7 +3062,6 @@ describe( 'selectors', () => { block3: {}, }, settings: {}, - blockEditingModes: new Map(), }; expect( canInsertBlockType( @@ -3172,7 +3100,6 @@ describe( 'selectors', () => { }, }, settings: {}, - blockEditingModes: new Map(), }; expect( canInsertBlockType( @@ -3209,7 +3136,6 @@ describe( 'selectors', () => { block2: {}, }, settings: {}, - blockEditingModes: new Map(), }; expect( canInsertBlockType( @@ -3239,7 +3165,6 @@ describe( 'selectors', () => { 3: {}, } ) ), - parents: new Map(), }, blockListSettings: { 1: { @@ -3250,7 +3175,6 @@ describe( 'selectors', () => { }, }, settings: {}, - blockEditingModes: new Map(), }; expect( canInsertBlocks( state, [ '2', '3' ], '1' ) ).toBe( true ); } ); @@ -3272,7 +3196,6 @@ describe( 'selectors', () => { 3: {}, } ) ), - parents: new Map(), }, blockListSettings: { 1: { @@ -3280,7 +3203,6 @@ describe( 'selectors', () => { }, }, settings: {}, - blockEditingModes: new Map(), }; expect( canInsertBlocks( state, [ '2', '3' ], '1' ) ).toBe( false ); } ); @@ -3319,7 +3241,6 @@ describe( 'selectors', () => { // See: https://github.com/WordPress/gutenberg/issues/14580 preferences: {}, blockListSettings: {}, - blockEditingModes: new Map(), }; const items = getInserterItems( state ); const testBlockAItem = items.find( @@ -3428,7 +3349,6 @@ describe( 'selectors', () => { block3: {}, block4: {}, }, - blockEditingModes: new Map(), }; const stateSecondBlockRestricted = { @@ -3516,7 +3436,6 @@ describe( 'selectors', () => { }, blockListSettings: {}, settings: {}, - blockEditingModes: new Map(), }; const items = getInserterItems( state ); const testBlockBItem = items.find( @@ -3541,7 +3460,6 @@ describe( 'selectors', () => { }, blockListSettings: {}, settings: {}, - blockEditingModes: new Map(), }; const items = getInserterItems( state ); const reusableBlock2Item = items.find( @@ -3633,7 +3551,6 @@ describe( 'selectors', () => { settings: {}, preferences: {}, blockListSettings: {}, - blockEditingModes: new Map(), }; const blocks = [ { name: 'core/with-tranforms-a' } ]; const items = getBlockTransformItems( state, blocks ); @@ -3674,7 +3591,6 @@ describe( 'selectors', () => { settings: {}, preferences: {}, blockListSettings: {}, - blockEditingModes: new Map(), }; const block = { name: 'core/with-tranforms-a' }; const items = getBlockTransformItems( state, block ); @@ -3713,7 +3629,6 @@ describe( 'selectors', () => { }, block2: {}, }, - blockEditingModes: new Map(), }; const blocks = [ { clientId: 'block2', name: 'core/with-tranforms-a' }, @@ -3761,7 +3676,6 @@ describe( 'selectors', () => { }, blockListSettings: {}, settings: {}, - blockEditingModes: new Map(), }; const blocks = [ { name: 'core/with-tranforms-a' } ]; const items = getBlockTransformItems( state, blocks ); @@ -3795,7 +3709,6 @@ describe( 'selectors', () => { }, blockListSettings: {}, settings: {}, - blockEditingModes: new Map(), }; const blocks = [ { name: 'core/with-tranforms-c' } ]; const items = getBlockTransformItems( state, blocks ); @@ -4208,12 +4121,6 @@ describe( 'selectors', () => { block2: {}, } ) ), - parents: new Map( - Object.entries( { - block1: '', - block2: '', - } ) - ), }, blockListSettings: { block1: { @@ -4245,7 +4152,6 @@ describe( 'selectors', () => { }, ], }, - blockEditingModes: new Map(), }; it( 'should return all patterns for root level', () => { @@ -4343,7 +4249,6 @@ describe( 'selectors', () => { block1: { name: 'core/test-block-a' }, } ) ), - parents: new Map(), }, blockListSettings: { block1: { @@ -4374,7 +4279,6 @@ describe( 'selectors', () => { }, ], }, - blockEditingModes: new Map(), }; it( 'should return empty array if no block name is provided', () => { expect( getPatternsByBlockTypes( state ) ).toEqual( [] ); @@ -4425,7 +4329,6 @@ describe( 'selectors', () => { block2: { name: 'core/test-block-b' }, } ) ), - parents: new Map(), controlledInnerBlocks: { 'block2-clientId': true }, }, blockListSettings: { @@ -4468,7 +4371,6 @@ describe( 'selectors', () => { }, ], }, - blockEditingModes: new Map(), }; describe( 'should return empty array', () => { it( 'when no blocks are selected', () => { @@ -4689,7 +4591,6 @@ describe( 'getInserterItems with core blocks prioritization', () => { settings: {}, preferences: {}, blockListSettings: {}, - blockEditingModes: new Map(), }; const items = getInserterItems( state ); const expectedResult = [ From fa8133bd109222e992d795374270d2df243007eb Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Fri, 2 Jun 2023 12:59:19 +1000 Subject: [PATCH 43/44] Improve useDisableNonContentBlocks performance --- .../use-disable-non-content-blocks.js | 24 +++---------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/packages/edit-site/src/components/page-content-lock/use-disable-non-content-blocks.js b/packages/edit-site/src/components/page-content-lock/use-disable-non-content-blocks.js index 554a483284a0ce..ce198909877f6b 100644 --- a/packages/edit-site/src/components/page-content-lock/use-disable-non-content-blocks.js +++ b/packages/edit-site/src/components/page-content-lock/use-disable-non-content-blocks.js @@ -3,11 +3,7 @@ */ import { createHigherOrderComponent } from '@wordpress/compose'; import { addFilter, removeFilter } from '@wordpress/hooks'; -import { - store as blockEditorStore, - privateApis as blockEditorPrivateApis, -} from '@wordpress/block-editor'; -import { useSelect } from '@wordpress/data'; +import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; import { useEffect } from '@wordpress/element'; /** @@ -39,22 +35,8 @@ export function useDisableNonContentBlocks() { const withDisableNonContentBlocks = createHigherOrderComponent( ( BlockEdit ) => ( props ) => { - const mode = useSelect( - ( select ) => { - if ( CONTENT_BLOCK_TYPES.includes( props.name ) ) { - return 'contentOnly'; - } - if ( - select( blockEditorStore ).getBlockParentsByBlockName( - props.clientId, - 'core/post-content' - ).length - ) { - return 'default'; - } - }, - [ props.name, props.clientId ] - ); + const isContent = CONTENT_BLOCK_TYPES.includes( props.name ); + const mode = isContent ? 'contentOnly' : undefined; useBlockEditingMode( mode ); return ; }, From f3fc2ca0dca92aced8abeab8f94256e3cfdb1c10 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Fri, 2 Jun 2023 14:49:37 +1000 Subject: [PATCH 44/44] Fix performance tests --- packages/e2e-tests/specs/performance/site-editor.test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/e2e-tests/specs/performance/site-editor.test.js b/packages/e2e-tests/specs/performance/site-editor.test.js index 22c1af35ff7161..e8f705c6dc0d79 100644 --- a/packages/e2e-tests/specs/performance/site-editor.test.js +++ b/packages/e2e-tests/specs/performance/site-editor.test.js @@ -151,7 +151,8 @@ describe( 'Site Editor Performance', () => { await enterEditMode(); // Insert a new paragraph right under the first one. - await firstParagraph.focus(); + await firstParagraph.click(); // Once to select the block overlay. + await firstParagraph.click(); // Once again to select the paragraph. await insertBlock( 'Paragraph' ); // Start tracing.