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 0000000000000..ed572f56f73b3 --- /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 3980dd7b2aead..964aacae99ac2 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 80056f35cf0d6..dab07ced873e9 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 6e9365ad10224..854d1dc7ca86a 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 d9799849b1399..af5fe6f509b58 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 385b120c352d2..d709869de52b2 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 23e6809685377..1a8896513ab2d 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 c28310cc7b86b..f018444de0c67 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 a7357311eedbe..f96130b670e24 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 2d33ea82cb9b6..496562687118b 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 60712e6b8eb6e..8f9af5df0b692 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 4239cb1aba848..f0c44244371c0 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 8cd71881e06de..a30b01dee7456 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 ed572f56f73b3..056721209ddfc 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 964aacae99ac2..d331fe7e541f3 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 1a8896513ab2d..58c076fd8e21c 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 f018444de0c67..42a9374ac098b 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 a30b01dee7456..3b54c58f838ea 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 056721209ddfc..82a7781142945 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 496562687118b..aa2030c1dcc52 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 8f9af5df0b692..b7b63a9ea875b 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 f0c44244371c0..8bef78a07fa7a 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 c4dc12643673b..50a0ade0d551c 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 d331fe7e541f3..185c8791a27e4 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 854d1dc7ca86a..2c1d8736ceefd 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 af5fe6f509b58..4dc53aae0afff 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 d709869de52b2..d9c06f0324701 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 d0700bd8d05ab..75f1de2b03e59 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 58c076fd8e21c..a417d11d90043 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 42a9374ac098b..2ecd35c99ee8c 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 9b11e991004b3..815b36e785a81 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 c4d8de316ea99..95de37062c09a 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 f2848a584d0d8..dcf8eae4ecf5a 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 e5a6270bad8dc..951c0013b76eb 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 1afde32cf1ec6..e58c68445ac71 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 419d4c729b17d..9e4ab5391d8c4 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 82a7781142945..94de18dd9d562 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 aa2030c1dcc52..593086ff120ba 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 6cdb77ec83de6..f33e9e55e3045 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 8bef78a07fa7a..b316bbeb5079e 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 c4453547f6ce6..fdfe993091fef 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 c5df265f75db3..0dcb89f5363c1 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 609cbb59c6e54..67ed0ae69106d 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 94de18dd9d562..a9bb85197619b 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 593086ff120ba..0a3484154e5a7 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 f33e9e55e3045..ce7802036184e 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 b4e9713bbd74c..0339100948a01 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 3b54c58f838ea..8cd71881e06de 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 a9bb85197619b..0347a9b7378d0 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 0000000000000..6fa09c6969ec5 --- /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 9304840eef614..aa1a40ef48057 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 ca6bb4355f52d..acc2bd7f510ed 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 0dad03bbc8ca2..aae6188cba2dd 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 8cd71881e06de..3b54c58f838ea 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 44b31c6945f57..2549fc5e00bd7 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 5086981f87144..78ada88a4d5fa 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 0000000000000..19329228be217 --- /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 0000000000000..eaae34c57a9cb --- /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 8e5e80d9fecc5..b11d9acb2314f 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 0000000000000..04e8d5667a2c2 --- /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 0000000000000..718fe8fb5a0fb --- /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 d43dca3b803f5..1c369703be5d7 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 67054c25d2476..4c8ef94855dcb 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 0000000000000..32a10800fc469 --- /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 0000000000000..2f3912d76eb35 --- /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 513634c55b8f0..de9dc8c3f764d 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 d1f41d5a62aca..542cb1831cfac 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 a46d215f90507..1008afd95176f 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 583f37b55241b..16b6dc588ea26 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 2df1cc72b6611..159b13252f161 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 f6ce205ad6353..0ea196f1079a9 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 223bcd1f0ba04..d9ed31411ffcc 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 3be15cd02d259..a7494f9fe4e07 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 0000000000000..95846473a88b8 --- /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 0000000000000..833bdd35eb91b --- /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 97bb0acb3bdd4..a4f3ab360ba91 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 247b901975fd8..077cbbb13bf75 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 0000000000000..8f07790d4f597 --- /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 19329228be217..5ce102560a8b2 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 59c36dca2b823..a740ddc7194eb 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 dab07ced873e9..d7436c3381217 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 949a7c773eb6e..cd3b00a06aab8 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 d40cbd49e477d..aef441a057456 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 3302d5eed6b33..a2409b3f1baa2 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 0000000000000..fa8c7c01f72d1 --- /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 2f3912d76eb35..cd2eabec9336c 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 32a10800fc469..f03f33914fd20 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 0000000000000..deabecd64ac39 --- /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 8f07790d4f597..0d326d2c9a5e4 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 de9dc8c3f764d..513634c55b8f0 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 d9a73e84de62e..a793c92c7bd48 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 077cbbb13bf75..8bd3475de6956 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 fa8c7c01f72d1..83d096fb39f5d 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 deabecd64ac39..0000000000000 --- 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 d7436c3381217..16c2d15b22d5e 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 56c044b6c5a8a..99d0fc56374e4 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 95846473a88b8..44ba4a8aa6ccd 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 88bf954e86ce2..ae28019cf0d99 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 cd3b00a06aab8..4a6a6fe6b4395 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 16c2d15b22d5e..a163ddaa78955 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 a793c92c7bd48..8f95e1efe10e2 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 0000000000000..668fe8af00d69 --- /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 cd2eabec9336c..554a483284a0c 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 0d326d2c9a5e4..9035c5677f91a 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 5ce102560a8b2..6241670e78e21 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 833bdd35eb91b..28ca9d7d95035 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 2e753a8d2dbc7..2f550a2b94d60 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 0036eee464dd7..8f8675d2b5b89 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 44ba4a8aa6ccd..0000000000000 --- 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 28ca9d7d95035..0000000000000 --- 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 aae6188cba2dd..523bb8d2bbff5 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 8f95e1efe10e2..a23c9c3595d32 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 f03f33914fd20..2a800317a33a9 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 8f8675d2b5b89..c913a689d54dc 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 542cb1831cfac..02ea870f698cb 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 1008afd95176f..a003ee958894e 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 159b13252f161..cca479e277662 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 0ea196f1079a9..1ddc6bfb6fa7b 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 a511dc3588603..2744a7bc84d10 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 2744a7bc84d10..55de64a93bc78 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 ce7802036184e..1034bab412a58 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 1034bab412a58..bcc032a4ee903 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 954c8c94c1379..f9bde867b1032 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 55de64a93bc78..5b615f67defbd 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 60d90d80b9d41..5cc17fc08b314 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 99d0fc56374e4..56c044b6c5a8a 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 a163ddaa78955..dab07ced873e9 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 bcc032a4ee903..ce7802036184e 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 5b615f67defbd..487d13db811d8 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 f9bde867b1032..954c8c94c1379 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 5cc17fc08b314..60d90d80b9d41 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 554a483284a0c..ce198909877f6 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 22c1af35ff716..e8f705c6dc0d7 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.