From d8c00b8f2b1b142a5e1223479a4d8932babee93b Mon Sep 17 00:00:00 2001 From: Ella Date: Tue, 12 Dec 2023 21:05:26 +0100 Subject: [PATCH 01/10] Block: combine store subscriptions --- packages/block-editor/README.md | 2 - .../src/components/block-edit/index.js | 65 +- .../src/components/block-list/block.js | 560 ++++++++++++------ .../block-list/use-block-props/index.js | 202 +------ 4 files changed, 402 insertions(+), 427 deletions(-) diff --git a/packages/block-editor/README.md b/packages/block-editor/README.md index 56ab5f1bd94d93..8ba720b6cec6ba 100644 --- a/packages/block-editor/README.md +++ b/packages/block-editor/README.md @@ -928,8 +928,6 @@ export default function Edit() { _Parameters_ - _props_ `Object`: Optional. Props to pass to the element. Must contain the ref if one is defined. -- _options_ `Object`: Options for internal use only. -- _options.\_\_unstableIsHtml_ `boolean`: _Returns_ diff --git a/packages/block-editor/src/components/block-edit/index.js b/packages/block-editor/src/components/block-edit/index.js index bbef47b27c5790..2062d0d968fbdb 100644 --- a/packages/block-editor/src/components/block-edit/index.js +++ b/packages/block-editor/src/components/block-edit/index.js @@ -1,19 +1,8 @@ -/** - * WordPress dependencies - */ -import { useMemo } from '@wordpress/element'; - -import { hasBlockSupport } from '@wordpress/blocks'; /** * Internal dependencies */ import Edit from './edit'; -import { - BlockEditContextProvider, - useBlockEditContext, - mayDisplayControlsKey, - mayDisplayParentControlsKey, -} from './context'; +import { useBlockEditContext } from './context'; /** * The `useBlockEditContext` hook provides information about the block this hook is being used in. @@ -25,54 +14,6 @@ import { */ export { useBlockEditContext }; -export default function BlockEdit( { - mayDisplayControls, - mayDisplayParentControls, - // The remaining props are passed through the BlockEdit filters and are thus - // public API! - ...props -} ) { - const { - name, - isSelected, - clientId, - attributes = {}, - __unstableLayoutClassNames, - } = props; - const { layout = null } = attributes; - const layoutSupport = - hasBlockSupport( name, 'layout', false ) || - hasBlockSupport( name, '__experimentalLayout', false ); - return ( - ( { - name, - isSelected, - clientId, - layout: layoutSupport ? layout : null, - __unstableLayoutClassNames, - // We use symbols in favour of an __unstable prefix to avoid - // usage outside of the package (this context is exposed). - [ mayDisplayControlsKey ]: mayDisplayControls, - [ mayDisplayParentControlsKey ]: mayDisplayParentControls, - } ), - [ - name, - isSelected, - clientId, - layoutSupport, - layout, - __unstableLayoutClassNames, - mayDisplayControls, - mayDisplayParentControls, - ] - ) } - > - - - ); +export default function BlockEdit( props ) { + return ; } diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index b38dcf3ef1f2ec..2683f1e2e32a3d 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -6,7 +6,7 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { useMemo, useCallback, RawHTML } from '@wordpress/element'; +import { useMemo, useCallback, RawHTML, useContext } from '@wordpress/element'; import { getBlockType, getSaveContent, @@ -15,31 +15,50 @@ import { switchToBlockType, getDefaultBlockName, isUnmodifiedBlock, + isReusableBlock, + getBlockDefaultClassName, + hasBlockSupport, store as blocksStore, } from '@wordpress/blocks'; import { withFilters } from '@wordpress/components'; -import { - withDispatch, - withSelect, - useDispatch, - useSelect, -} from '@wordpress/data'; -import { compose, pure, ifCondition } from '@wordpress/compose'; +import { withDispatch, useDispatch, useSelect } from '@wordpress/data'; +import { compose, pure, useMergeRefs, useDisabled } from '@wordpress/compose'; import { safeHTML } from '@wordpress/dom'; +import { __, sprintf } from '@wordpress/i18n'; /** * Internal dependencies */ import BlockEdit from '../block-edit'; +import { + BlockEditContextProvider, + mayDisplayControlsKey, + mayDisplayParentControlsKey, +} from '../block-edit/context'; import BlockInvalidWarning from './block-invalid-warning'; import BlockCrashWarning from './block-crash-warning'; import BlockCrashBoundary from './block-crash-boundary'; import BlockHtml from './block-html'; -import { useBlockProps } from './use-block-props'; import { store as blockEditorStore } from '../../store'; import { useLayout } from './layout'; import { BlockListBlockContext } from './block-list-block-context'; +import useMovingAnimation from '../use-moving-animation'; +import { useFocusFirstElement } from './use-block-props/use-focus-first-element'; +import { useIsHovered } from './use-block-props/use-is-hovered'; +import { useFocusHandler } from './use-block-props/use-focus-handler'; +import { useEventHandlers } from './use-block-props/use-selected-block-event-handlers'; +import { useNavModeExit } from './use-block-props/use-nav-mode-exit'; +import { useBlockRefProvider } from './use-block-props/use-block-refs'; +import { useIntersectionObserver } from './use-block-props/use-intersection-observer'; +import { unlock } from '../../lock-unlock'; + +/** + * If the block count exceeds the threshold, we disable the reordering animation + * to avoid laginess. + */ +const BLOCK_ANIMATION_THRESHOLD = 200; + /** * Merges wrapper props with special handling for classNames and styles. * @@ -72,9 +91,15 @@ function mergeWrapperProps( propsA, propsB ) { return newProps; } -function Block( { children, isHtml, ...props } ) { +function Block( { children, mode, isHtml, className } ) { + const blockProps = useContext( BlockListBlockContext ); + const htmlSuffix = mode === 'html' && ! isHtml ? '-visual' : ''; return ( -
+
{ children }
); @@ -88,67 +113,24 @@ function BlockListBlock( { clientId, isSelected, isSelectionEnabled, - className, - __unstableLayoutClassNames: layoutClassNames, name, isValid, attributes, - wrapperProps, setAttributes, onReplace, onInsertBlocksAfter, onMerge, toggleSelection, } ) { - const { - themeSupportsLayout, - isTemporarilyEditingAsBlocks, - blockEditingMode, - mayDisplayControls, - mayDisplayParentControls, - } = useSelect( - ( select ) => { - const { - getSettings, - __unstableGetTemporarilyEditingAsBlocks, - getBlockEditingMode, - getBlockName, - isFirstMultiSelectedBlock, - getMultiSelectedBlockClientIds, - hasSelectedInnerBlock, - } = select( blockEditorStore ); - const { hasBlockSupport } = select( blocksStore ); - return { - themeSupportsLayout: getSettings().supportsLayout, - isTemporarilyEditingAsBlocks: - __unstableGetTemporarilyEditingAsBlocks() === clientId, - blockEditingMode: getBlockEditingMode( clientId ), - mayDisplayControls: - isSelected || - ( isFirstMultiSelectedBlock( clientId ) && - getMultiSelectedBlockClientIds().every( - ( id ) => getBlockName( id ) === name - ) ), - mayDisplayParentControls: - hasBlockSupport( - getBlockName( clientId ), - '__experimentalExposeControlsToChildren', - false - ) && hasSelectedInnerBlock( clientId ), - }; - }, - [ clientId, isSelected, name ] - ); const { removeBlock } = useDispatch( blockEditorStore ); const onRemove = useCallback( () => removeBlock( clientId ), [ clientId ] ); - const parentLayout = useLayout() || {}; // 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 // `BlockHTML`, even in HTML mode. - let blockEdit = ( + const blockEdit = ( ); const blockType = getBlockType( name ); - - if ( blockEditingMode === 'disabled' ) { - wrapperProps = { - ...wrapperProps, - tabIndex: -1, - }; - } - // Determine whether the block has props to apply to the wrapper. - if ( blockType?.getEditWrapperProps ) { - wrapperProps = mergeWrapperProps( - wrapperProps, - blockType.getEditWrapperProps( attributes ) - ); - } - - const isAligned = - wrapperProps && - !! wrapperProps[ 'data-align' ] && - ! themeSupportsLayout; - - // Support for sticky position in classic themes with alignment wrappers. - - const isSticky = className?.includes( 'is-position-sticky' ); - - // For aligned blocks, provide a wrapper element so the block can be - // positioned relative to the block column. - // This is only kept for classic themes that don't support layout - // Historically we used to rely on extra divs and data-align to - // provide the alignments styles in the editor. - // Due to the differences between frontend and backend, we migrated - // to the layout feature, and we're now aligning the markup of frontend - // and backend. - if ( isAligned ) { - blockEdit = ( -
- { blockEdit } -
- ); - } - let block; if ( ! isValid ) { @@ -241,84 +177,368 @@ function BlockListBlock( { } else if ( blockType?.apiVersion > 1 ) { block = blockEdit; } else { - block = { blockEdit }; + block = { blockEdit }; } - const { 'data-align': dataAlign, ...restWrapperProps } = wrapperProps ?? {}; + return ( + + + + } + > + { block } + + ); +} - const value = { - clientId, - className: classnames( - { - 'is-editing-disabled': blockEditingMode === 'disabled', - 'is-content-locked-temporarily-editing-as-blocks': - isTemporarilyEditingAsBlocks, +const applyWithSelect = ( Component ) => { + return ( props ) => { + const { clientId, rootClientId, __unstableLayoutClassNames } = props; + let { wrapperProps, className } = props; + const selectedProps = useSelect( + ( select ) => { + const { + isBlockSelected, + getBlockMode, + isSelectionEnabled, + getTemplateLock, + __unstableGetBlockWithoutInnerBlocks, + canRemoveBlock, + canMoveBlock, + + getSettings, + __unstableGetTemporarilyEditingAsBlocks, + getBlockEditingMode, + getBlockName, + isFirstMultiSelectedBlock, + getMultiSelectedBlockClientIds, + hasSelectedInnerBlock, + + getBlockIndex, + isTyping, + getGlobalBlockCount, + isBlockMultiSelected, + isAncestorMultiSelected, + isBlockSubtreeDisabled, + isBlockHighlighted, + __unstableIsFullySelected, + __unstableSelectionHasUnmergeableBlock, + isBlockBeingDragged, + hasBlockMovingClientId, + canInsertBlockType, + getBlockRootClientId, + __unstableHasActiveBlockOverlayActive, + __unstableGetEditorMode, + getSelectedBlocksInitialCaretPosition, + } = unlock( select( blockEditorStore ) ); + const block = __unstableGetBlockWithoutInnerBlocks( clientId ); + + // This is a temporary fix. + // This function should never be called when a block is not + // present in the state. It happens now because the order in + // withSelect rendering is not correct. + if ( ! block ) { + return; + } + + const _isSelected = isBlockSelected( clientId ); + const templateLock = getTemplateLock( rootClientId ); + const canRemove = canRemoveBlock( clientId, rootClientId ); + const canMove = canMoveBlock( clientId, rootClientId ); + const { name: blockName, attributes, isValid } = block; + + const { hasBlockSupport: _hasBlockSupport } = + select( blocksStore ); + + const { getActiveBlockVariation } = select( blocksStore ); + const isPartOfMultiSelection = + isBlockMultiSelected( clientId ) || + isAncestorMultiSelected( clientId ); + const blockType = getBlockType( blockName ); + const match = getActiveBlockVariation( blockName, attributes ); + const { outlineMode, supportsLayout } = getSettings(); + const isMultiSelected = isBlockMultiSelected( clientId ); + const checkDeep = true; + const isAncestorOfSelectedBlock = hasSelectedInnerBlock( + clientId, + checkDeep + ); + const typing = isTyping(); + const hasLightBlockWrapper = blockType?.apiVersion > 1; + const movingClientId = hasBlockMovingClientId(); + + // Do not add new properties here, use `useSelect` instead to avoid + // leaking new props to the public API (editor.BlockListBlock filter). + return { + mode: getBlockMode( clientId ), + isSelectionEnabled: isSelectionEnabled(), + isLocked: !! templateLock, + canRemove, + canMove, + // Users of the editor.BlockListBlock filter used to be able to + // access the block prop. + // Ideally these blocks would rely on the clientId prop only. + // This is kept for backward compatibility reasons. + block, + name: blockName, + attributes, + isValid, + isSelected: _isSelected, + + themeSupportsLayout: supportsLayout, + isTemporarilyEditingAsBlocks: + __unstableGetTemporarilyEditingAsBlocks() === clientId, + blockEditingMode: getBlockEditingMode( clientId ), + mayDisplayControls: + _isSelected || + ( isFirstMultiSelectedBlock( clientId ) && + getMultiSelectedBlockClientIds().every( + ( id ) => getBlockName( id ) === blockName + ) ), + mayDisplayParentControls: + _hasBlockSupport( + getBlockName( clientId ), + '__experimentalExposeControlsToChildren', + false + ) && hasSelectedInnerBlock( clientId ), + + index: getBlockIndex( clientId ), + blockTitle: match?.title || blockType?.title, + blockType, + isPartOfSelection: _isSelected || isPartOfMultiSelection, + adjustScrolling: + _isSelected || isFirstMultiSelectedBlock( clientId ), + enableAnimation: + ! typing && + getGlobalBlockCount() <= BLOCK_ANIMATION_THRESHOLD, + isSubtreeDisabled: isBlockSubtreeDisabled( clientId ), + isOutlineEnabled: outlineMode, + hasOverlay: + __unstableHasActiveBlockOverlayActive( clientId ), + initialPosition: + _isSelected && __unstableGetEditorMode() === 'edit' + ? getSelectedBlocksInitialCaretPosition() + : undefined, + classNames: classnames( + { + 'is-selected': _isSelected, + 'is-highlighted': isBlockHighlighted( clientId ), + 'is-multi-selected': isMultiSelected, + 'is-partially-selected': + isMultiSelected && + ! __unstableIsFullySelected() && + ! __unstableSelectionHasUnmergeableBlock(), + 'is-reusable': isReusableBlock( blockType ), + 'is-dragging': isBlockBeingDragged( clientId ), + 'has-child-selected': isAncestorOfSelectedBlock, + 'remove-outline': + _isSelected && outlineMode && typing, + 'is-block-moving-mode': !! movingClientId, + 'can-insert-moving-block': + movingClientId && + canInsertBlockType( + getBlockName( movingClientId ), + getBlockRootClientId( clientId ) + ), + 'is-editing-disabled': + getBlockEditingMode( clientId ) === 'disabled', + 'is-content-locked-temporarily-editing-as-blocks': + __unstableGetTemporarilyEditingAsBlocks() === + clientId, + }, + hasLightBlockWrapper ? attributes.className : undefined, + hasLightBlockWrapper + ? getBlockDefaultClassName( blockName ) + : undefined + ), + }; }, + [ clientId, rootClientId ] + ); + + const publicProps = { + mode: selectedProps.mode, + isSelectionEnabled: selectedProps.isSelectionEnabled, + isLocked: selectedProps.isLocked, + canRemove: selectedProps.canRemove, + canMove: selectedProps.canMove, + // Users of the editor.BlockListBlock filter used to be able to + // access the block prop. + // Ideally these blocks would rely on the clientId prop only. + // This is kept for backward compatibility reasons. + block: selectedProps.block, + name: selectedProps.name, + attributes: selectedProps.attributes, + isValid: selectedProps.isValid, + isSelected: selectedProps.isSelected, + }; + + const { + index, + name, + blockTitle, + isSelected, + isPartOfSelection, + adjustScrolling, + enableAnimation, + isSubtreeDisabled, + isOutlineEnabled, + hasOverlay, + initialPosition, + classNames, + themeSupportsLayout, + blockType, + attributes, + blockEditingMode, + mayDisplayControls, + mayDisplayParentControls, + } = selectedProps; + + const mergedRefs = useMergeRefs( [ + props.ref, + useFocusFirstElement( { clientId, initialPosition } ), + useBlockRefProvider( clientId ), + useFocusHandler( clientId ), + useEventHandlers( { clientId, isSelected } ), + useNavModeExit( clientId ), + useIsHovered( { isEnabled: isOutlineEnabled } ), + useIntersectionObserver(), + useMovingAnimation( { + isSelected: isPartOfSelection, + adjustScrolling, + enableAnimation, + triggerAnimationOnChange: index, + } ), + useDisabled( { isDisabled: ! hasOverlay } ), + ] ); + + // Block is sometimes not mounted at the right time, causing it be + // undefined see issue for more info + // https://github.com/WordPress/gutenberg/issues/17013 + if ( ! selectedProps ) { + return null; + } + + // translators: %s: Type of block (i.e. Text, Image etc) + const blockLabel = sprintf( __( 'Block: %s' ), blockTitle ); + + // Determine whether the block has props to apply to the wrapper. + if ( blockType?.getEditWrapperProps ) { + wrapperProps = mergeWrapperProps( + wrapperProps, + blockType.getEditWrapperProps( attributes ) + ); + } + + const isAligned = + wrapperProps && + !! wrapperProps[ 'data-align' ] && + ! themeSupportsLayout; + + // Support for sticky position in classic themes with alignment wrappers. + + const isSticky = className?.includes( 'is-position-sticky' ); + const { 'data-align': dataAlign, ...restWrapperProps } = + wrapperProps ?? {}; + + className = classnames( dataAlign && themeSupportsLayout && `align${ dataAlign }`, ! ( dataAlign && isSticky ) && className - ), - wrapperProps: restWrapperProps, - isAligned, - }; + ); - const memoizedValue = useMemo( () => value, Object.values( value ) ); + const blockProps = { + tabIndex: blockEditingMode === 'disabled' ? -1 : 0, + ...restWrapperProps, + ref: mergedRefs, + id: `block-${ clientId }`, + role: 'document', + 'aria-label': blockLabel, + 'data-block': clientId, + 'data-type': name, + 'data-title': blockTitle, + inert: isSubtreeDisabled ? 'true' : undefined, + className: classnames( + 'block-editor-block-list__block', + { + // The wp-block className is important for editor styles. + 'wp-block': ! isAligned, + 'has-block-overlay': hasOverlay, + }, + className, + restWrapperProps.className, + classNames + ), + }; - return ( - - - - - } + const { layout = null } = attributes; + const layoutSupport = + hasBlockSupport( name, 'layout', false ) || + hasBlockSupport( name, '__experimentalLayout', false ); + + const component = ( + ( { + name, + isSelected, + clientId, + layout: layoutSupport ? layout : null, + __unstableLayoutClassNames, + // We use symbols in favour of an __unstable prefix to avoid + // usage outside of the package (this context is exposed). + [ mayDisplayControlsKey ]: mayDisplayControls, + [ mayDisplayParentControlsKey ]: + mayDisplayParentControls, + } ), + [ + name, + isSelected, + clientId, + layoutSupport, + layout, + __unstableLayoutClassNames, + mayDisplayControls, + mayDisplayParentControls, + ] + ) } > - { block } - - - ); -} + { /* To do: explain why it's ok to not memo */ } + + + + + ); -const applyWithSelect = withSelect( ( select, { clientId, rootClientId } ) => { - const { - isBlockSelected, - getBlockMode, - isSelectionEnabled, - getTemplateLock, - __unstableGetBlockWithoutInnerBlocks, - canRemoveBlock, - canMoveBlock, - } = select( blockEditorStore ); - const block = __unstableGetBlockWithoutInnerBlocks( clientId ); - const isSelected = isBlockSelected( clientId ); - const templateLock = getTemplateLock( rootClientId ); - const canRemove = canRemoveBlock( clientId, rootClientId ); - const canMove = canMoveBlock( clientId, rootClientId ); - - // The fallback to `{}` is a temporary fix. - // This function should never be called when a block is not present in - // the state. It happens now because the order in withSelect rendering - // is not correct. - const { name, attributes, isValid } = block || {}; - - // Do not add new properties here, use `useSelect` instead to avoid - // leaking new props to the public API (editor.BlockListBlock filter). - return { - mode: getBlockMode( clientId ), - isSelectionEnabled: isSelectionEnabled(), - isLocked: !! templateLock, - canRemove, - canMove, - // Users of the editor.BlockListBlock filter used to be able to - // access the block prop. - // Ideally these blocks would rely on the clientId prop only. - // This is kept for backward compatibility reasons. - block, - name, - attributes, - isValid, - isSelected, + // For aligned blocks, provide a wrapper element so the block can be + // positioned relative to the block column. + // This is only kept for classic themes that don't support layout + // Historically we used to rely on extra divs and data-align to + // provide the alignments styles in the editor. + // Due to the differences between frontend and backend, we migrated + // to the layout feature, and we're now aligning the markup of frontend + // and backend. + if ( isAligned ) { + return ( +
+ { component } +
+ ); + } + + return component; }; -} ); +}; const applyWithDispatch = withDispatch( ( dispatch, ownProps, registry ) => { const { @@ -562,9 +782,5 @@ export default compose( pure, applyWithSelect, applyWithDispatch, - // Block is sometimes not mounted at the right time, causing it be undefined - // see issue for more info - // https://github.com/WordPress/gutenberg/issues/17013 - ifCondition( ( { block } ) => !! block ), withFilters( 'editor.BlockListBlock' ) )( BlockListBlock ); 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 593beafa06d83f..f76847f11aea16 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 @@ -7,39 +7,17 @@ import classnames from 'classnames'; * WordPress dependencies */ import { useContext } from '@wordpress/element'; -import { __, sprintf } from '@wordpress/i18n'; import { __unstableGetBlockProps as getBlockProps, getBlockType, - isReusableBlock, - getBlockDefaultClassName, - store as blocksStore, } from '@wordpress/blocks'; -import { useMergeRefs, useDisabled } from '@wordpress/compose'; -import { useSelect } from '@wordpress/data'; import warning from '@wordpress/warning'; /** * Internal dependencies */ -import useMovingAnimation from '../../use-moving-animation'; 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'; -import { useFocusHandler } from './use-focus-handler'; -import { useEventHandlers } from './use-selected-block-event-handlers'; -import { useNavModeExit } from './use-nav-mode-exit'; -import { useBlockRefProvider } from './use-block-refs'; -import { useIntersectionObserver } from './use-intersection-observer'; -import { store as blockEditorStore } from '../../../store'; -import { unlock } from '../../../lock-unlock'; - -/** - * If the block count exceeds the threshold, we disable the reordering animation - * to avoid laginess. - */ -const BLOCK_ANIMATION_THRESHOLD = 200; /** * This hook is used to lightly mark an element as a block element. The element @@ -76,187 +54,29 @@ const BLOCK_ANIMATION_THRESHOLD = 200; * ``` * * - * @param {Object} props Optional. Props to pass to the element. Must contain - * the ref if one is defined. - * @param {Object} options Options for internal use only. - * @param {boolean} options.__unstableIsHtml + * @param {Object} props Optional. Props to pass to the element. Must contain + * the ref if one is defined. * * @return {Object} Props to pass to the element to mark as a block. */ -export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) { - const { - clientId, - className, - wrapperProps = {}, - isAligned, - } = useContext( BlockListBlockContext ); - const { - index, - mode, - name, - blockApiVersion, - blockTitle, - isSelected, - isPartOfSelection, - adjustScrolling, - enableAnimation, - isSubtreeDisabled, - isOutlineEnabled, - hasOverlay, - initialPosition, - classNames, - } = useSelect( - ( select ) => { - const { - getBlockAttributes, - getBlockIndex, - getBlockMode, - getBlockName, - isTyping, - getGlobalBlockCount, - isBlockSelected, - isBlockMultiSelected, - isAncestorMultiSelected, - isFirstMultiSelectedBlock, - isBlockSubtreeDisabled, - getSettings, - isBlockHighlighted, - __unstableIsFullySelected, - __unstableSelectionHasUnmergeableBlock, - isBlockBeingDragged, - hasSelectedInnerBlock, - hasBlockMovingClientId, - canInsertBlockType, - getBlockRootClientId, - __unstableHasActiveBlockOverlayActive, - __unstableGetEditorMode, - getSelectedBlocksInitialCaretPosition, - } = unlock( select( blockEditorStore ) ); - const { getActiveBlockVariation } = select( blocksStore ); - const _isSelected = isBlockSelected( clientId ); - const isPartOfMultiSelection = - isBlockMultiSelected( clientId ) || - isAncestorMultiSelected( clientId ); - const blockName = getBlockName( clientId ); - const blockType = getBlockType( blockName ); - const attributes = getBlockAttributes( clientId ); - const match = getActiveBlockVariation( blockName, attributes ); - const { outlineMode } = getSettings(); - const isMultiSelected = isBlockMultiSelected( clientId ); - const checkDeep = true; - const isAncestorOfSelectedBlock = hasSelectedInnerBlock( - clientId, - checkDeep - ); - const typing = isTyping(); - const hasLightBlockWrapper = blockType?.apiVersion > 1; - const movingClientId = hasBlockMovingClientId(); - - return { - index: getBlockIndex( clientId ), - mode: getBlockMode( clientId ), - name: blockName, - blockApiVersion: blockType?.apiVersion || 1, - blockTitle: match?.title || blockType?.title, - isSelected: _isSelected, - isPartOfSelection: _isSelected || isPartOfMultiSelection, - adjustScrolling: - _isSelected || isFirstMultiSelectedBlock( clientId ), - enableAnimation: - ! typing && - getGlobalBlockCount() <= BLOCK_ANIMATION_THRESHOLD, - isSubtreeDisabled: isBlockSubtreeDisabled( clientId ), - isOutlineEnabled: outlineMode, - hasOverlay: __unstableHasActiveBlockOverlayActive( clientId ), - initialPosition: - _isSelected && __unstableGetEditorMode() === 'edit' - ? getSelectedBlocksInitialCaretPosition() - : undefined, - classNames: classnames( - { - 'is-selected': _isSelected, - 'is-highlighted': isBlockHighlighted( clientId ), - 'is-multi-selected': isMultiSelected, - 'is-partially-selected': - isMultiSelected && - ! __unstableIsFullySelected() && - ! __unstableSelectionHasUnmergeableBlock(), - 'is-reusable': isReusableBlock( blockType ), - 'is-dragging': isBlockBeingDragged( clientId ), - 'has-child-selected': isAncestorOfSelectedBlock, - 'remove-outline': _isSelected && outlineMode && typing, - 'is-block-moving-mode': !! movingClientId, - 'can-insert-moving-block': - movingClientId && - canInsertBlockType( - getBlockName( movingClientId ), - getBlockRootClientId( clientId ) - ), - }, - hasLightBlockWrapper ? attributes.className : undefined, - hasLightBlockWrapper - ? getBlockDefaultClassName( blockName ) - : undefined - ), - }; - }, - [ clientId ] - ); - - // translators: %s: Type of block (i.e. Text, Image etc) - const blockLabel = sprintf( __( 'Block: %s' ), blockTitle ); - const htmlSuffix = mode === 'html' && ! __unstableIsHtml ? '-visual' : ''; - const mergedRefs = useMergeRefs( [ - props.ref, - useFocusFirstElement( { clientId, initialPosition } ), - useBlockRefProvider( clientId ), - useFocusHandler( clientId ), - useEventHandlers( { clientId, isSelected } ), - useNavModeExit( clientId ), - useIsHovered( { isEnabled: isOutlineEnabled } ), - useIntersectionObserver(), - useMovingAnimation( { - isSelected: isPartOfSelection, - adjustScrolling, - enableAnimation, - triggerAnimationOnChange: index, - } ), - useDisabled( { isDisabled: ! hasOverlay } ), - ] ); +export function useBlockProps( props = {} ) { + const blockProps = useContext( BlockListBlockContext ); + const { name } = useBlockEditContext(); + const blockType = getBlockType( name ); + const blockApiVersion = blockType?.apiVersion || 1; - const blockEditContext = useBlockEditContext(); // Ensures it warns only inside the `edit` implementation for the block. - if ( blockApiVersion < 2 && clientId === blockEditContext.clientId ) { + if ( blockApiVersion < 2 ) { warning( `Block type "${ name }" must support API version 2 or higher to work correctly with "useBlockProps" method.` ); } return { - tabIndex: 0, - ...wrapperProps, + ...blockProps, ...props, - ref: mergedRefs, - id: `block-${ clientId }${ htmlSuffix }`, - role: 'document', - 'aria-label': blockLabel, - 'data-block': clientId, - 'data-type': name, - 'data-title': blockTitle, - inert: isSubtreeDisabled ? 'true' : undefined, - className: classnames( - 'block-editor-block-list__block', - { - // The wp-block className is important for editor styles. - 'wp-block': ! isAligned, - 'has-block-overlay': hasOverlay, - }, - className, - props.className, - wrapperProps.className, - classNames - ), - style: { ...wrapperProps.style, ...props.style }, + className: classnames( props.className, blockProps.className ), + style: { ...blockProps.style, ...props.style }, }; } From 066cea02545cf89a8d274ae7f184696965f39025 Mon Sep 17 00:00:00 2001 From: Ella Date: Tue, 12 Dec 2023 21:47:48 +0100 Subject: [PATCH 02/10] merge refs --- .../src/components/block-list/block.js | 690 +++++++++--------- .../block-list/use-block-props/index.js | 2 + 2 files changed, 342 insertions(+), 350 deletions(-) diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index 2683f1e2e32a3d..6e3a8376b56334 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -193,353 +193,6 @@ function BlockListBlock( { ); } -const applyWithSelect = ( Component ) => { - return ( props ) => { - const { clientId, rootClientId, __unstableLayoutClassNames } = props; - let { wrapperProps, className } = props; - const selectedProps = useSelect( - ( select ) => { - const { - isBlockSelected, - getBlockMode, - isSelectionEnabled, - getTemplateLock, - __unstableGetBlockWithoutInnerBlocks, - canRemoveBlock, - canMoveBlock, - - getSettings, - __unstableGetTemporarilyEditingAsBlocks, - getBlockEditingMode, - getBlockName, - isFirstMultiSelectedBlock, - getMultiSelectedBlockClientIds, - hasSelectedInnerBlock, - - getBlockIndex, - isTyping, - getGlobalBlockCount, - isBlockMultiSelected, - isAncestorMultiSelected, - isBlockSubtreeDisabled, - isBlockHighlighted, - __unstableIsFullySelected, - __unstableSelectionHasUnmergeableBlock, - isBlockBeingDragged, - hasBlockMovingClientId, - canInsertBlockType, - getBlockRootClientId, - __unstableHasActiveBlockOverlayActive, - __unstableGetEditorMode, - getSelectedBlocksInitialCaretPosition, - } = unlock( select( blockEditorStore ) ); - const block = __unstableGetBlockWithoutInnerBlocks( clientId ); - - // This is a temporary fix. - // This function should never be called when a block is not - // present in the state. It happens now because the order in - // withSelect rendering is not correct. - if ( ! block ) { - return; - } - - const _isSelected = isBlockSelected( clientId ); - const templateLock = getTemplateLock( rootClientId ); - const canRemove = canRemoveBlock( clientId, rootClientId ); - const canMove = canMoveBlock( clientId, rootClientId ); - const { name: blockName, attributes, isValid } = block; - - const { hasBlockSupport: _hasBlockSupport } = - select( blocksStore ); - - const { getActiveBlockVariation } = select( blocksStore ); - const isPartOfMultiSelection = - isBlockMultiSelected( clientId ) || - isAncestorMultiSelected( clientId ); - const blockType = getBlockType( blockName ); - const match = getActiveBlockVariation( blockName, attributes ); - const { outlineMode, supportsLayout } = getSettings(); - const isMultiSelected = isBlockMultiSelected( clientId ); - const checkDeep = true; - const isAncestorOfSelectedBlock = hasSelectedInnerBlock( - clientId, - checkDeep - ); - const typing = isTyping(); - const hasLightBlockWrapper = blockType?.apiVersion > 1; - const movingClientId = hasBlockMovingClientId(); - - // Do not add new properties here, use `useSelect` instead to avoid - // leaking new props to the public API (editor.BlockListBlock filter). - return { - mode: getBlockMode( clientId ), - isSelectionEnabled: isSelectionEnabled(), - isLocked: !! templateLock, - canRemove, - canMove, - // Users of the editor.BlockListBlock filter used to be able to - // access the block prop. - // Ideally these blocks would rely on the clientId prop only. - // This is kept for backward compatibility reasons. - block, - name: blockName, - attributes, - isValid, - isSelected: _isSelected, - - themeSupportsLayout: supportsLayout, - isTemporarilyEditingAsBlocks: - __unstableGetTemporarilyEditingAsBlocks() === clientId, - blockEditingMode: getBlockEditingMode( clientId ), - mayDisplayControls: - _isSelected || - ( isFirstMultiSelectedBlock( clientId ) && - getMultiSelectedBlockClientIds().every( - ( id ) => getBlockName( id ) === blockName - ) ), - mayDisplayParentControls: - _hasBlockSupport( - getBlockName( clientId ), - '__experimentalExposeControlsToChildren', - false - ) && hasSelectedInnerBlock( clientId ), - - index: getBlockIndex( clientId ), - blockTitle: match?.title || blockType?.title, - blockType, - isPartOfSelection: _isSelected || isPartOfMultiSelection, - adjustScrolling: - _isSelected || isFirstMultiSelectedBlock( clientId ), - enableAnimation: - ! typing && - getGlobalBlockCount() <= BLOCK_ANIMATION_THRESHOLD, - isSubtreeDisabled: isBlockSubtreeDisabled( clientId ), - isOutlineEnabled: outlineMode, - hasOverlay: - __unstableHasActiveBlockOverlayActive( clientId ), - initialPosition: - _isSelected && __unstableGetEditorMode() === 'edit' - ? getSelectedBlocksInitialCaretPosition() - : undefined, - classNames: classnames( - { - 'is-selected': _isSelected, - 'is-highlighted': isBlockHighlighted( clientId ), - 'is-multi-selected': isMultiSelected, - 'is-partially-selected': - isMultiSelected && - ! __unstableIsFullySelected() && - ! __unstableSelectionHasUnmergeableBlock(), - 'is-reusable': isReusableBlock( blockType ), - 'is-dragging': isBlockBeingDragged( clientId ), - 'has-child-selected': isAncestorOfSelectedBlock, - 'remove-outline': - _isSelected && outlineMode && typing, - 'is-block-moving-mode': !! movingClientId, - 'can-insert-moving-block': - movingClientId && - canInsertBlockType( - getBlockName( movingClientId ), - getBlockRootClientId( clientId ) - ), - 'is-editing-disabled': - getBlockEditingMode( clientId ) === 'disabled', - 'is-content-locked-temporarily-editing-as-blocks': - __unstableGetTemporarilyEditingAsBlocks() === - clientId, - }, - hasLightBlockWrapper ? attributes.className : undefined, - hasLightBlockWrapper - ? getBlockDefaultClassName( blockName ) - : undefined - ), - }; - }, - [ clientId, rootClientId ] - ); - - const publicProps = { - mode: selectedProps.mode, - isSelectionEnabled: selectedProps.isSelectionEnabled, - isLocked: selectedProps.isLocked, - canRemove: selectedProps.canRemove, - canMove: selectedProps.canMove, - // Users of the editor.BlockListBlock filter used to be able to - // access the block prop. - // Ideally these blocks would rely on the clientId prop only. - // This is kept for backward compatibility reasons. - block: selectedProps.block, - name: selectedProps.name, - attributes: selectedProps.attributes, - isValid: selectedProps.isValid, - isSelected: selectedProps.isSelected, - }; - - const { - index, - name, - blockTitle, - isSelected, - isPartOfSelection, - adjustScrolling, - enableAnimation, - isSubtreeDisabled, - isOutlineEnabled, - hasOverlay, - initialPosition, - classNames, - themeSupportsLayout, - blockType, - attributes, - blockEditingMode, - mayDisplayControls, - mayDisplayParentControls, - } = selectedProps; - - const mergedRefs = useMergeRefs( [ - props.ref, - useFocusFirstElement( { clientId, initialPosition } ), - useBlockRefProvider( clientId ), - useFocusHandler( clientId ), - useEventHandlers( { clientId, isSelected } ), - useNavModeExit( clientId ), - useIsHovered( { isEnabled: isOutlineEnabled } ), - useIntersectionObserver(), - useMovingAnimation( { - isSelected: isPartOfSelection, - adjustScrolling, - enableAnimation, - triggerAnimationOnChange: index, - } ), - useDisabled( { isDisabled: ! hasOverlay } ), - ] ); - - // Block is sometimes not mounted at the right time, causing it be - // undefined see issue for more info - // https://github.com/WordPress/gutenberg/issues/17013 - if ( ! selectedProps ) { - return null; - } - - // translators: %s: Type of block (i.e. Text, Image etc) - const blockLabel = sprintf( __( 'Block: %s' ), blockTitle ); - - // Determine whether the block has props to apply to the wrapper. - if ( blockType?.getEditWrapperProps ) { - wrapperProps = mergeWrapperProps( - wrapperProps, - blockType.getEditWrapperProps( attributes ) - ); - } - - const isAligned = - wrapperProps && - !! wrapperProps[ 'data-align' ] && - ! themeSupportsLayout; - - // Support for sticky position in classic themes with alignment wrappers. - - const isSticky = className?.includes( 'is-position-sticky' ); - const { 'data-align': dataAlign, ...restWrapperProps } = - wrapperProps ?? {}; - - className = classnames( - dataAlign && themeSupportsLayout && `align${ dataAlign }`, - ! ( dataAlign && isSticky ) && className - ); - - const blockProps = { - tabIndex: blockEditingMode === 'disabled' ? -1 : 0, - ...restWrapperProps, - ref: mergedRefs, - id: `block-${ clientId }`, - role: 'document', - 'aria-label': blockLabel, - 'data-block': clientId, - 'data-type': name, - 'data-title': blockTitle, - inert: isSubtreeDisabled ? 'true' : undefined, - className: classnames( - 'block-editor-block-list__block', - { - // The wp-block className is important for editor styles. - 'wp-block': ! isAligned, - 'has-block-overlay': hasOverlay, - }, - className, - restWrapperProps.className, - classNames - ), - }; - - const { layout = null } = attributes; - const layoutSupport = - hasBlockSupport( name, 'layout', false ) || - hasBlockSupport( name, '__experimentalLayout', false ); - - const component = ( - ( { - name, - isSelected, - clientId, - layout: layoutSupport ? layout : null, - __unstableLayoutClassNames, - // We use symbols in favour of an __unstable prefix to avoid - // usage outside of the package (this context is exposed). - [ mayDisplayControlsKey ]: mayDisplayControls, - [ mayDisplayParentControlsKey ]: - mayDisplayParentControls, - } ), - [ - name, - isSelected, - clientId, - layoutSupport, - layout, - __unstableLayoutClassNames, - mayDisplayControls, - mayDisplayParentControls, - ] - ) } - > - { /* To do: explain why it's ok to not memo */ } - - - - - ); - - // For aligned blocks, provide a wrapper element so the block can be - // positioned relative to the block column. - // This is only kept for classic themes that don't support layout - // Historically we used to rely on extra divs and data-align to - // provide the alignments styles in the editor. - // Due to the differences between frontend and backend, we migrated - // to the layout feature, and we're now aligning the markup of frontend - // and backend. - if ( isAligned ) { - return ( -
- { component } -
- ); - } - - return component; - }; -}; - const applyWithDispatch = withDispatch( ( dispatch, ownProps, registry ) => { const { updateBlockAttributes, @@ -778,9 +431,346 @@ const applyWithDispatch = withDispatch( ( dispatch, ownProps, registry ) => { }; } ); -export default compose( - pure, - applyWithSelect, +BlockListBlock = compose( applyWithDispatch, withFilters( 'editor.BlockListBlock' ) )( BlockListBlock ); + +function BlockListBlockProvider( props ) { + const { clientId, rootClientId, __unstableLayoutClassNames } = props; + let { wrapperProps, className } = props; + const selectedProps = useSelect( + ( select ) => { + const { + isBlockSelected, + getBlockMode, + isSelectionEnabled, + getTemplateLock, + __unstableGetBlockWithoutInnerBlocks, + canRemoveBlock, + canMoveBlock, + + getSettings, + __unstableGetTemporarilyEditingAsBlocks, + getBlockEditingMode, + getBlockName, + isFirstMultiSelectedBlock, + getMultiSelectedBlockClientIds, + hasSelectedInnerBlock, + + getBlockIndex, + isTyping, + getGlobalBlockCount, + isBlockMultiSelected, + isAncestorMultiSelected, + isBlockSubtreeDisabled, + isBlockHighlighted, + __unstableIsFullySelected, + __unstableSelectionHasUnmergeableBlock, + isBlockBeingDragged, + hasBlockMovingClientId, + canInsertBlockType, + getBlockRootClientId, + __unstableHasActiveBlockOverlayActive, + __unstableGetEditorMode, + getSelectedBlocksInitialCaretPosition, + } = unlock( select( blockEditorStore ) ); + const block = __unstableGetBlockWithoutInnerBlocks( clientId ); + + // This is a temporary fix. + // This function should never be called when a block is not + // present in the state. It happens now because the order in + // withSelect rendering is not correct. + if ( ! block ) { + return; + } + + const _isSelected = isBlockSelected( clientId ); + const templateLock = getTemplateLock( rootClientId ); + const canRemove = canRemoveBlock( clientId, rootClientId ); + const canMove = canMoveBlock( clientId, rootClientId ); + const { name: blockName, attributes, isValid } = block; + + const { hasBlockSupport: _hasBlockSupport } = select( blocksStore ); + + const { getActiveBlockVariation } = select( blocksStore ); + const isPartOfMultiSelection = + isBlockMultiSelected( clientId ) || + isAncestorMultiSelected( clientId ); + const blockType = getBlockType( blockName ); + const match = getActiveBlockVariation( blockName, attributes ); + const { outlineMode, supportsLayout } = getSettings(); + const isMultiSelected = isBlockMultiSelected( clientId ); + const checkDeep = true; + const isAncestorOfSelectedBlock = hasSelectedInnerBlock( + clientId, + checkDeep + ); + const typing = isTyping(); + const hasLightBlockWrapper = blockType?.apiVersion > 1; + const movingClientId = hasBlockMovingClientId(); + + // Do not add new properties here, use `useSelect` instead to avoid + // leaking new props to the public API (editor.BlockListBlock filter). + return { + mode: getBlockMode( clientId ), + isSelectionEnabled: isSelectionEnabled(), + isLocked: !! templateLock, + canRemove, + canMove, + // Users of the editor.BlockListBlock filter used to be able to + // access the block prop. + // Ideally these blocks would rely on the clientId prop only. + // This is kept for backward compatibility reasons. + block, + name: blockName, + attributes, + isValid, + isSelected: _isSelected, + + themeSupportsLayout: supportsLayout, + isTemporarilyEditingAsBlocks: + __unstableGetTemporarilyEditingAsBlocks() === clientId, + blockEditingMode: getBlockEditingMode( clientId ), + mayDisplayControls: + _isSelected || + ( isFirstMultiSelectedBlock( clientId ) && + getMultiSelectedBlockClientIds().every( + ( id ) => getBlockName( id ) === blockName + ) ), + mayDisplayParentControls: + _hasBlockSupport( + getBlockName( clientId ), + '__experimentalExposeControlsToChildren', + false + ) && hasSelectedInnerBlock( clientId ), + + index: getBlockIndex( clientId ), + blockTitle: match?.title || blockType?.title, + blockType, + isPartOfSelection: _isSelected || isPartOfMultiSelection, + adjustScrolling: + _isSelected || isFirstMultiSelectedBlock( clientId ), + enableAnimation: + ! typing && + getGlobalBlockCount() <= BLOCK_ANIMATION_THRESHOLD, + isSubtreeDisabled: isBlockSubtreeDisabled( clientId ), + isOutlineEnabled: outlineMode, + hasOverlay: __unstableHasActiveBlockOverlayActive( clientId ), + initialPosition: + _isSelected && __unstableGetEditorMode() === 'edit' + ? getSelectedBlocksInitialCaretPosition() + : undefined, + classNames: classnames( + { + 'is-selected': _isSelected, + 'is-highlighted': isBlockHighlighted( clientId ), + 'is-multi-selected': isMultiSelected, + 'is-partially-selected': + isMultiSelected && + ! __unstableIsFullySelected() && + ! __unstableSelectionHasUnmergeableBlock(), + 'is-reusable': isReusableBlock( blockType ), + 'is-dragging': isBlockBeingDragged( clientId ), + 'has-child-selected': isAncestorOfSelectedBlock, + 'remove-outline': _isSelected && outlineMode && typing, + 'is-block-moving-mode': !! movingClientId, + 'can-insert-moving-block': + movingClientId && + canInsertBlockType( + getBlockName( movingClientId ), + getBlockRootClientId( clientId ) + ), + 'is-editing-disabled': + getBlockEditingMode( clientId ) === 'disabled', + 'is-content-locked-temporarily-editing-as-blocks': + __unstableGetTemporarilyEditingAsBlocks() === + clientId, + }, + hasLightBlockWrapper ? attributes.className : undefined, + hasLightBlockWrapper + ? getBlockDefaultClassName( blockName ) + : undefined + ), + }; + }, + [ clientId, rootClientId ] + ); + + const publicProps = { + mode: selectedProps.mode, + isSelectionEnabled: selectedProps.isSelectionEnabled, + isLocked: selectedProps.isLocked, + canRemove: selectedProps.canRemove, + canMove: selectedProps.canMove, + // Users of the editor.BlockListBlock filter used to be able to + // access the block prop. + // Ideally these blocks would rely on the clientId prop only. + // This is kept for backward compatibility reasons. + block: selectedProps.block, + name: selectedProps.name, + attributes: selectedProps.attributes, + isValid: selectedProps.isValid, + isSelected: selectedProps.isSelected, + }; + + const { + index, + name, + blockTitle, + isSelected, + isPartOfSelection, + adjustScrolling, + enableAnimation, + isSubtreeDisabled, + isOutlineEnabled, + hasOverlay, + initialPosition, + classNames, + themeSupportsLayout, + blockType, + attributes, + blockEditingMode, + mayDisplayControls, + mayDisplayParentControls, + } = selectedProps; + + const mergedRefs = useMergeRefs( [ + props.ref, + useFocusFirstElement( { clientId, initialPosition } ), + useBlockRefProvider( clientId ), + useFocusHandler( clientId ), + useEventHandlers( { clientId, isSelected } ), + useNavModeExit( clientId ), + useIsHovered( { isEnabled: isOutlineEnabled } ), + useIntersectionObserver(), + useMovingAnimation( { + isSelected: isPartOfSelection, + adjustScrolling, + enableAnimation, + triggerAnimationOnChange: index, + } ), + useDisabled( { isDisabled: ! hasOverlay } ), + ] ); + + const { layout = null } = attributes; + const layoutSupport = + hasBlockSupport( name, 'layout', false ) || + hasBlockSupport( name, '__experimentalLayout', false ); + const blockEditContext = useMemo( + () => ( { + name, + isSelected, + clientId, + layout: layoutSupport ? layout : null, + __unstableLayoutClassNames, + // We use symbols in favour of an __unstable prefix to avoid + // usage outside of the package (this context is exposed). + [ mayDisplayControlsKey ]: mayDisplayControls, + [ mayDisplayParentControlsKey ]: mayDisplayParentControls, + } ), + [ + name, + isSelected, + clientId, + layoutSupport, + layout, + __unstableLayoutClassNames, + mayDisplayControls, + mayDisplayParentControls, + ] + ); + + // Block is sometimes not mounted at the right time, causing it be + // undefined see issue for more info + // https://github.com/WordPress/gutenberg/issues/17013 + if ( ! selectedProps ) { + return null; + } + + // translators: %s: Type of block (i.e. Text, Image etc) + const blockLabel = sprintf( __( 'Block: %s' ), blockTitle ); + + // Determine whether the block has props to apply to the wrapper. + if ( blockType?.getEditWrapperProps ) { + wrapperProps = mergeWrapperProps( + wrapperProps, + blockType.getEditWrapperProps( attributes ) + ); + } + + const isAligned = + wrapperProps && + !! wrapperProps[ 'data-align' ] && + ! themeSupportsLayout; + + // Support for sticky position in classic themes with alignment wrappers. + const isSticky = className?.includes( 'is-position-sticky' ); + const { 'data-align': dataAlign, ...restWrapperProps } = wrapperProps ?? {}; + + className = classnames( + dataAlign && themeSupportsLayout && `align${ dataAlign }`, + ! ( dataAlign && isSticky ) && className + ); + + const blockProps = { + tabIndex: blockEditingMode === 'disabled' ? -1 : 0, + ...restWrapperProps, + ref: mergedRefs, + id: `block-${ clientId }`, + role: 'document', + 'aria-label': blockLabel, + 'data-block': clientId, + 'data-type': name, + 'data-title': blockTitle, + inert: isSubtreeDisabled ? 'true' : undefined, + className: classnames( + 'block-editor-block-list__block', + { + // The wp-block className is important for editor styles. + 'wp-block': ! isAligned, + 'has-block-overlay': hasOverlay, + }, + className, + restWrapperProps.className, + classNames + ), + }; + + const component = ( + + { /* To do: explain why it's ok to not memo */ } + + + + + ); + + // For aligned blocks, provide a wrapper element so the block can be + // positioned relative to the block column. + // This is only kept for classic themes that don't support layout + // Historically we used to rely on extra divs and data-align to + // provide the alignments styles in the editor. + // Due to the differences between frontend and backend, we migrated + // to the layout feature, and we're now aligning the markup of frontend + // and backend. + if ( isAligned ) { + return ( +
+ { component } +
+ ); + } + + return component; +} + +export default pure( BlockListBlockProvider ); 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 f76847f11aea16..04a53bd7507acb 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 @@ -11,6 +11,7 @@ import { __unstableGetBlockProps as getBlockProps, getBlockType, } from '@wordpress/blocks'; +import { useMergeRefs } from '@wordpress/compose'; import warning from '@wordpress/warning'; /** @@ -75,6 +76,7 @@ export function useBlockProps( props = {} ) { return { ...blockProps, ...props, + ref: useMergeRefs( [ blockProps.ref, props.ref ] ), className: classnames( props.className, blockProps.className ), style: { ...blockProps.style, ...props.style }, }; From 8aaf7eac0ab9e552a8bc496349c5dce2e53c9239 Mon Sep 17 00:00:00 2001 From: Ella Date: Wed, 13 Dec 2023 10:59:52 +0100 Subject: [PATCH 03/10] Fix order --- .../src/components/block-edit/index.js | 65 ++++- .../src/components/block-list/block.js | 245 ++++++++---------- .../block-list/use-block-props/index.js | 25 +- 3 files changed, 192 insertions(+), 143 deletions(-) diff --git a/packages/block-editor/src/components/block-edit/index.js b/packages/block-editor/src/components/block-edit/index.js index 2062d0d968fbdb..bbef47b27c5790 100644 --- a/packages/block-editor/src/components/block-edit/index.js +++ b/packages/block-editor/src/components/block-edit/index.js @@ -1,8 +1,19 @@ +/** + * WordPress dependencies + */ +import { useMemo } from '@wordpress/element'; + +import { hasBlockSupport } from '@wordpress/blocks'; /** * Internal dependencies */ import Edit from './edit'; -import { useBlockEditContext } from './context'; +import { + BlockEditContextProvider, + useBlockEditContext, + mayDisplayControlsKey, + mayDisplayParentControlsKey, +} from './context'; /** * The `useBlockEditContext` hook provides information about the block this hook is being used in. @@ -14,6 +25,54 @@ import { useBlockEditContext } from './context'; */ export { useBlockEditContext }; -export default function BlockEdit( props ) { - return ; +export default function BlockEdit( { + mayDisplayControls, + mayDisplayParentControls, + // The remaining props are passed through the BlockEdit filters and are thus + // public API! + ...props +} ) { + const { + name, + isSelected, + clientId, + attributes = {}, + __unstableLayoutClassNames, + } = props; + const { layout = null } = attributes; + const layoutSupport = + hasBlockSupport( name, 'layout', false ) || + hasBlockSupport( name, '__experimentalLayout', false ); + return ( + ( { + name, + isSelected, + clientId, + layout: layoutSupport ? layout : null, + __unstableLayoutClassNames, + // We use symbols in favour of an __unstable prefix to avoid + // usage outside of the package (this context is exposed). + [ mayDisplayControlsKey ]: mayDisplayControls, + [ mayDisplayParentControlsKey ]: mayDisplayParentControls, + } ), + [ + name, + isSelected, + clientId, + layoutSupport, + layout, + __unstableLayoutClassNames, + mayDisplayControls, + mayDisplayParentControls, + ] + ) } + > + + + ); } diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index 6e3a8376b56334..029d0f290d6116 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -6,7 +6,7 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { useMemo, useCallback, RawHTML, useContext } from '@wordpress/element'; +import { useCallback, RawHTML, useContext } from '@wordpress/element'; import { getBlockType, getSaveContent, @@ -17,7 +17,6 @@ import { isUnmodifiedBlock, isReusableBlock, getBlockDefaultClassName, - hasBlockSupport, store as blocksStore, } from '@wordpress/blocks'; import { withFilters } from '@wordpress/components'; @@ -30,11 +29,6 @@ import { __, sprintf } from '@wordpress/i18n'; * Internal dependencies */ import BlockEdit from '../block-edit'; -import { - BlockEditContextProvider, - mayDisplayControlsKey, - mayDisplayParentControlsKey, -} from '../block-edit/context'; import BlockInvalidWarning from './block-invalid-warning'; import BlockCrashWarning from './block-crash-warning'; import BlockCrashBoundary from './block-crash-boundary'; @@ -113,9 +107,12 @@ function BlockListBlock( { clientId, isSelected, isSelectionEnabled, + className, + __unstableLayoutClassNames: layoutClassNames, name, isValid, attributes, + wrapperProps, setAttributes, onReplace, onInsertBlocksAfter, @@ -125,12 +122,18 @@ function BlockListBlock( { const { removeBlock } = useDispatch( blockEditorStore ); const onRemove = useCallback( () => removeBlock( clientId ), [ clientId ] ); const parentLayout = useLayout() || {}; + const { + essentialProps, + mayDisplayControls, + mayDisplayParentControls, + themeSupportsLayout, + } = useContext( BlockListBlockContext ); // 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 // `BlockHTML`, even in HTML mode. - const blockEdit = ( + let blockEdit = ( ); const blockType = getBlockType( name ); + + // Determine whether the block has props to apply to the wrapper. + if ( blockType?.getEditWrapperProps ) { + wrapperProps = mergeWrapperProps( + wrapperProps, + blockType.getEditWrapperProps( attributes ) + ); + } + + const isAligned = + wrapperProps && + !! wrapperProps[ 'data-align' ] && + ! themeSupportsLayout; + + // Support for sticky position in classic themes with alignment wrappers. + const isSticky = className?.includes( 'is-position-sticky' ); + const { 'data-align': dataAlign, ...restWrapperProps } = wrapperProps ?? {}; + + restWrapperProps.className = classnames( + restWrapperProps.className, + dataAlign && themeSupportsLayout && `align${ dataAlign }`, + ! ( dataAlign && isSticky ) && className, + { + 'wp-block': ! isAligned, + } + ); + + // For aligned blocks, provide a wrapper element so the block can be + // positioned relative to the block column. + // This is only kept for classic themes that don't support layout + // Historically we used to rely on extra divs and data-align to + // provide the alignments styles in the editor. + // Due to the differences between frontend and backend, we migrated + // to the layout feature, and we're now aligning the markup of frontend + // and backend. + if ( isAligned ) { + blockEdit = ( +
+ { blockEdit } +
+ ); + } + let block; if ( ! isValid ) { @@ -181,15 +233,22 @@ function BlockListBlock( { } return ( - - - - } + - { block } - + + + + } + > + { block } + + ); } @@ -437,8 +496,7 @@ BlockListBlock = compose( )( BlockListBlock ); function BlockListBlockProvider( props ) { - const { clientId, rootClientId, __unstableLayoutClassNames } = props; - let { wrapperProps, className } = props; + const { clientId, rootClientId } = props; const selectedProps = useSelect( ( select ) => { const { @@ -509,6 +567,8 @@ function BlockListBlockProvider( props ) { const typing = isTyping(); const hasLightBlockWrapper = blockType?.apiVersion > 1; const movingClientId = hasBlockMovingClientId(); + const _hasOverlay = + __unstableHasActiveBlockOverlayActive( clientId ); // Do not add new properties here, use `useSelect` instead to avoid // leaking new props to the public API (editor.BlockListBlock filter). @@ -547,7 +607,6 @@ function BlockListBlockProvider( props ) { index: getBlockIndex( clientId ), blockTitle: match?.title || blockType?.title, - blockType, isPartOfSelection: _isSelected || isPartOfMultiSelection, adjustScrolling: _isSelected || isFirstMultiSelectedBlock( clientId ), @@ -556,12 +615,13 @@ function BlockListBlockProvider( props ) { getGlobalBlockCount() <= BLOCK_ANIMATION_THRESHOLD, isSubtreeDisabled: isBlockSubtreeDisabled( clientId ), isOutlineEnabled: outlineMode, - hasOverlay: __unstableHasActiveBlockOverlayActive( clientId ), + hasOverlay: _hasOverlay, initialPosition: _isSelected && __unstableGetEditorMode() === 'edit' ? getSelectedBlocksInitialCaretPosition() : undefined, classNames: classnames( + 'block-editor-block-list__block', { 'is-selected': _isSelected, 'is-highlighted': isBlockHighlighted( clientId ), @@ -581,6 +641,7 @@ function BlockListBlockProvider( props ) { getBlockName( movingClientId ), getBlockRootClientId( clientId ) ), + 'has-block-overlay': _hasOverlay, 'is-editing-disabled': getBlockEditingMode( clientId ) === 'disabled', 'is-content-locked-temporarily-editing-as-blocks': @@ -597,23 +658,6 @@ function BlockListBlockProvider( props ) { [ clientId, rootClientId ] ); - const publicProps = { - mode: selectedProps.mode, - isSelectionEnabled: selectedProps.isSelectionEnabled, - isLocked: selectedProps.isLocked, - canRemove: selectedProps.canRemove, - canMove: selectedProps.canMove, - // Users of the editor.BlockListBlock filter used to be able to - // access the block prop. - // Ideally these blocks would rely on the clientId prop only. - // This is kept for backward compatibility reasons. - block: selectedProps.block, - name: selectedProps.name, - attributes: selectedProps.attributes, - isValid: selectedProps.isValid, - isSelected: selectedProps.isSelected, - }; - const { index, name, @@ -628,11 +672,7 @@ function BlockListBlockProvider( props ) { initialPosition, classNames, themeSupportsLayout, - blockType, - attributes, blockEditingMode, - mayDisplayControls, - mayDisplayParentControls, } = selectedProps; const mergedRefs = useMergeRefs( [ @@ -653,34 +693,6 @@ function BlockListBlockProvider( props ) { useDisabled( { isDisabled: ! hasOverlay } ), ] ); - const { layout = null } = attributes; - const layoutSupport = - hasBlockSupport( name, 'layout', false ) || - hasBlockSupport( name, '__experimentalLayout', false ); - const blockEditContext = useMemo( - () => ( { - name, - isSelected, - clientId, - layout: layoutSupport ? layout : null, - __unstableLayoutClassNames, - // We use symbols in favour of an __unstable prefix to avoid - // usage outside of the package (this context is exposed). - [ mayDisplayControlsKey ]: mayDisplayControls, - [ mayDisplayParentControlsKey ]: mayDisplayParentControls, - } ), - [ - name, - isSelected, - clientId, - layoutSupport, - layout, - __unstableLayoutClassNames, - mayDisplayControls, - mayDisplayParentControls, - ] - ); - // Block is sometimes not mounted at the right time, causing it be // undefined see issue for more info // https://github.com/WordPress/gutenberg/issues/17013 @@ -691,31 +703,8 @@ function BlockListBlockProvider( props ) { // translators: %s: Type of block (i.e. Text, Image etc) const blockLabel = sprintf( __( 'Block: %s' ), blockTitle ); - // Determine whether the block has props to apply to the wrapper. - if ( blockType?.getEditWrapperProps ) { - wrapperProps = mergeWrapperProps( - wrapperProps, - blockType.getEditWrapperProps( attributes ) - ); - } - - const isAligned = - wrapperProps && - !! wrapperProps[ 'data-align' ] && - ! themeSupportsLayout; - - // Support for sticky position in classic themes with alignment wrappers. - const isSticky = className?.includes( 'is-position-sticky' ); - const { 'data-align': dataAlign, ...restWrapperProps } = wrapperProps ?? {}; - - className = classnames( - dataAlign && themeSupportsLayout && `align${ dataAlign }`, - ! ( dataAlign && isSticky ) && className - ); - const blockProps = { tabIndex: blockEditingMode === 'disabled' ? -1 : 0, - ...restWrapperProps, ref: mergedRefs, id: `block-${ clientId }`, role: 'document', @@ -724,53 +713,39 @@ function BlockListBlockProvider( props ) { 'data-type': name, 'data-title': blockTitle, inert: isSubtreeDisabled ? 'true' : undefined, - className: classnames( - 'block-editor-block-list__block', - { - // The wp-block className is important for editor styles. - 'wp-block': ! isAligned, - 'has-block-overlay': hasOverlay, - }, - className, - restWrapperProps.className, - classNames - ), + className: classNames, }; - const component = ( - - { /* To do: explain why it's ok to not memo */ } - - - - + + ); - - // For aligned blocks, provide a wrapper element so the block can be - // positioned relative to the block column. - // This is only kept for classic themes that don't support layout - // Historically we used to rely on extra divs and data-align to - // provide the alignments styles in the editor. - // Due to the differences between frontend and backend, we migrated - // to the layout feature, and we're now aligning the markup of frontend - // and backend. - if ( isAligned ) { - return ( -
- { component } -
- ); - } - - return component; } export default pure( BlockListBlockProvider ); 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 04a53bd7507acb..de4329ae6c5b31 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 @@ -61,7 +61,9 @@ import { useBlockEditContext } from '../../block-edit/context'; * @return {Object} Props to pass to the element to mark as a block. */ export function useBlockProps( props = {} ) { - const blockProps = useContext( BlockListBlockContext ); + const { essentialProps, wrapperProps } = useContext( + BlockListBlockContext + ); const { name } = useBlockEditContext(); const blockType = getBlockType( name ); const blockApiVersion = blockType?.apiVersion || 1; @@ -74,11 +76,24 @@ export function useBlockProps( props = {} ) { } return { - ...blockProps, + ...wrapperProps, + // Individual block props can override wrapper props. ...props, - ref: useMergeRefs( [ blockProps.ref, props.ref ] ), - className: classnames( props.className, blockProps.className ), - style: { ...blockProps.style, ...props.style }, + // Essential props are always passed through. + ...essentialProps, + // wrapperProps has never been able to pass a ref, so let's not add that + // since it's an API we're likely to deprecate in the future. + ref: useMergeRefs( [ props.ref, essentialProps.ref ] ), + className: classnames( + wrapperProps.className, + props.className, + essentialProps.className + ), + style: { + ...wrapperProps.style, + ...props.style, + ...essentialProps.style, + }, }; } From 5176ce2c70dadb18a8262dd811875b4d67d99dd8 Mon Sep 17 00:00:00 2001 From: Ella Date: Wed, 13 Dec 2023 13:35:24 +0100 Subject: [PATCH 04/10] Fix html view --- .../src/components/block-list/block.js | 22 +++++++++---------- .../block-list/use-block-props/index.js | 18 ++++++++------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index 029d0f290d6116..35c65337f627b8 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -21,7 +21,7 @@ import { } from '@wordpress/blocks'; import { withFilters } from '@wordpress/components'; import { withDispatch, useDispatch, useSelect } from '@wordpress/data'; -import { compose, pure, useMergeRefs, useDisabled } from '@wordpress/compose'; +import { compose, pure, useDisabled } from '@wordpress/compose'; import { safeHTML } from '@wordpress/dom'; import { __, sprintf } from '@wordpress/i18n'; @@ -33,6 +33,7 @@ import BlockInvalidWarning from './block-invalid-warning'; import BlockCrashWarning from './block-crash-warning'; import BlockCrashBoundary from './block-crash-boundary'; import BlockHtml from './block-html'; +import { useBlockProps } from './use-block-props'; import { store as blockEditorStore } from '../../store'; import { useLayout } from './layout'; import { BlockListBlockContext } from './block-list-block-context'; @@ -85,15 +86,11 @@ function mergeWrapperProps( propsA, propsB ) { return newProps; } -function Block( { children, mode, isHtml, className } ) { - const blockProps = useContext( BlockListBlockContext ); +function Block( { children, mode, isHtml, ...props } ) { + const blockProps = useBlockProps( props ); const htmlSuffix = mode === 'html' && ! isHtml ? '-visual' : ''; return ( -
+
{ children }
); @@ -127,6 +124,7 @@ function BlockListBlock( { mayDisplayControls, mayDisplayParentControls, themeSupportsLayout, + refs, } = useContext( BlockListBlockContext ); // We wrap the BlockEdit component in a div that hides it when editing in @@ -237,6 +235,7 @@ function BlockListBlock( { value={ { essentialProps, wrapperProps: restWrapperProps, + refs, } } > 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 de4329ae6c5b31..c87ae817c6a162 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 @@ -61,18 +61,20 @@ import { useBlockEditContext } from '../../block-edit/context'; * @return {Object} Props to pass to the element to mark as a block. */ export function useBlockProps( props = {} ) { - const { essentialProps, wrapperProps } = useContext( + const { essentialProps, wrapperProps, refs } = useContext( BlockListBlockContext ); const { name } = useBlockEditContext(); - const blockType = getBlockType( name ); - const blockApiVersion = blockType?.apiVersion || 1; // Ensures it warns only inside the `edit` implementation for the block. - if ( blockApiVersion < 2 ) { - warning( - `Block type "${ name }" must support API version 2 or higher to work correctly with "useBlockProps" method.` - ); + if ( name ) { + const blockType = getBlockType( name ); + const blockApiVersion = blockType?.apiVersion || 1; + if ( blockApiVersion < 2 ) { + warning( + `Block type "${ name }" must support API version 2 or higher to work correctly with "useBlockProps" method.` + ); + } } return { @@ -83,7 +85,7 @@ export function useBlockProps( props = {} ) { ...essentialProps, // wrapperProps has never been able to pass a ref, so let's not add that // since it's an API we're likely to deprecate in the future. - ref: useMergeRefs( [ props.ref, essentialProps.ref ] ), + ref: useMergeRefs( [ props.ref, ...refs ] ), className: classnames( wrapperProps.className, props.className, From 735151f94a36d4efed5610c736839e14ffcd066d Mon Sep 17 00:00:00 2001 From: Ella Date: Wed, 13 Dec 2023 15:12:31 +0100 Subject: [PATCH 05/10] debug error --- .../src/components/block-editing-mode/index.js | 6 +++--- .../src/components/block-list/block.js | 18 +++++++++--------- .../block-list/use-block-props/index.js | 4 ++-- 3 files changed, 14 insertions(+), 14 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 5d916d9816e606..20f93f6b36f908 100644 --- a/packages/block-editor/src/components/block-editing-mode/index.js +++ b/packages/block-editor/src/components/block-editing-mode/index.js @@ -2,13 +2,13 @@ * WordPress dependencies */ import { useSelect, useDispatch } from '@wordpress/data'; -import { useContext, useEffect } from '@wordpress/element'; +import { useEffect } from '@wordpress/element'; /** * Internal dependencies */ import { store as blockEditorStore } from '../../store'; -import { BlockListBlockContext } from '../block-list/block-list-block-context'; +import { useBlockEditContext } from '../block-edit/context'; /** * @typedef {'disabled'|'contentOnly'|'default'} BlockEditingMode @@ -45,7 +45,7 @@ import { BlockListBlockContext } from '../block-list/block-list-block-context'; * @return {BlockEditingMode} The current editing mode. */ export function useBlockEditingMode( mode ) { - const { clientId = '' } = useContext( BlockListBlockContext ) ?? {}; + const { clientId = '' } = useBlockEditContext(); const blockEditingMode = useSelect( ( select ) => select( blockEditorStore ).getBlockEditingMode( clientId ), diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index 35c65337f627b8..e5b12804c7ea80 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -153,13 +153,13 @@ function BlockListBlock( { /> ); - const blockType = getBlockType( name ); + const _blockType = getBlockType( name ); // Determine whether the block has props to apply to the wrapper. - if ( blockType?.getEditWrapperProps ) { + if ( _blockType?.getEditWrapperProps ) { wrapperProps = mergeWrapperProps( wrapperProps, - blockType.getEditWrapperProps( attributes ) + _blockType.getEditWrapperProps( attributes ) ); } @@ -205,7 +205,7 @@ function BlockListBlock( { if ( ! isValid ) { const saveContent = __unstableBlockSource ? serializeRawBlock( __unstableBlockSource ) - : getSaveContent( blockType, attributes ); + : getSaveContent( _blockType, attributes ); block = ( @@ -224,7 +224,7 @@ function BlockListBlock( { ); - } else if ( blockType?.apiVersion > 1 ) { + } else if ( _blockType?.apiVersion > 1 ) { block = blockEdit; } else { block = { blockEdit }; @@ -554,7 +554,7 @@ function BlockListBlockProvider( props ) { const isPartOfMultiSelection = isBlockMultiSelected( clientId ) || isAncestorMultiSelected( clientId ); - const blockType = getBlockType( blockName ); + const _blockType = getBlockType( blockName ); const match = getActiveBlockVariation( blockName, attributes ); const { outlineMode, supportsLayout } = getSettings(); const isMultiSelected = isBlockMultiSelected( clientId ); @@ -564,7 +564,7 @@ function BlockListBlockProvider( props ) { checkDeep ); const typing = isTyping(); - const hasLightBlockWrapper = blockType?.apiVersion > 1; + const hasLightBlockWrapper = _blockType?.apiVersion > 1; const movingClientId = hasBlockMovingClientId(); const _hasOverlay = __unstableHasActiveBlockOverlayActive( clientId ); @@ -605,7 +605,7 @@ function BlockListBlockProvider( props ) { ) && hasSelectedInnerBlock( clientId ), index: getBlockIndex( clientId ), - blockTitle: match?.title || blockType?.title, + blockTitle: match?.title || _blockType?.title, isPartOfSelection: _isSelected || isPartOfMultiSelection, adjustScrolling: _isSelected || isFirstMultiSelectedBlock( clientId ), @@ -629,7 +629,7 @@ function BlockListBlockProvider( props ) { isMultiSelected && ! __unstableIsFullySelected() && ! __unstableSelectionHasUnmergeableBlock(), - 'is-reusable': isReusableBlock( blockType ), + 'is-reusable': isReusableBlock( _blockType ), 'is-dragging': isBlockBeingDragged( clientId ), 'has-child-selected': isAncestorOfSelectedBlock, 'remove-outline': _isSelected && outlineMode && typing, 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 c87ae817c6a162..853a797a0bef6f 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 @@ -68,8 +68,8 @@ export function useBlockProps( props = {} ) { // Ensures it warns only inside the `edit` implementation for the block. if ( name ) { - const blockType = getBlockType( name ); - const blockApiVersion = blockType?.apiVersion || 1; + const _blockType = getBlockType( name ); + const blockApiVersion = _blockType?.apiVersion || 1; if ( blockApiVersion < 2 ) { warning( `Block type "${ name }" must support API version 2 or higher to work correctly with "useBlockProps" method.` From 97cda3c3b3aed46b10e25f01064adaf239c60f42 Mon Sep 17 00:00:00 2001 From: Ella Date: Wed, 13 Dec 2023 16:02:09 +0100 Subject: [PATCH 06/10] Try without warning --- .../block-list/use-block-props/index.js | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) 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 853a797a0bef6f..c81c92070e429e 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 @@ -7,18 +7,13 @@ import classnames from 'classnames'; * WordPress dependencies */ import { useContext } from '@wordpress/element'; -import { - __unstableGetBlockProps as getBlockProps, - getBlockType, -} from '@wordpress/blocks'; +import { __unstableGetBlockProps as getBlockProps } from '@wordpress/blocks'; import { useMergeRefs } from '@wordpress/compose'; -import warning from '@wordpress/warning'; /** * Internal dependencies */ import { BlockListBlockContext } from '../block-list-block-context'; -import { useBlockEditContext } from '../../block-edit/context'; /** * This hook is used to lightly mark an element as a block element. The element @@ -64,18 +59,6 @@ export function useBlockProps( props = {} ) { const { essentialProps, wrapperProps, refs } = useContext( BlockListBlockContext ); - const { name } = useBlockEditContext(); - - // Ensures it warns only inside the `edit` implementation for the block. - if ( name ) { - const _blockType = getBlockType( name ); - const blockApiVersion = _blockType?.apiVersion || 1; - if ( blockApiVersion < 2 ) { - warning( - `Block type "${ name }" must support API version 2 or higher to work correctly with "useBlockProps" method.` - ); - } - } return { ...wrapperProps, From f5382137eb57eb668894685eec5f46d7d4719551 Mon Sep 17 00:00:00 2001 From: Ella Date: Wed, 13 Dec 2023 17:30:48 +0100 Subject: [PATCH 07/10] Clean up --- .../src/components/block-list/block.js | 153 ++++++++++-------- 1 file changed, 88 insertions(+), 65 deletions(-) diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index e5b12804c7ea80..13ec4c26d90fed 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -116,9 +116,6 @@ function BlockListBlock( { onMerge, toggleSelection, } ) { - const { removeBlock } = useDispatch( blockEditorStore ); - const onRemove = useCallback( () => removeBlock( clientId ), [ clientId ] ); - const parentLayout = useLayout() || {}; const { essentialProps, mayDisplayControls, @@ -126,6 +123,10 @@ function BlockListBlock( { themeSupportsLayout, refs, } = useContext( BlockListBlockContext ); + const { removeBlock } = useDispatch( blockEditorStore ); + const onRemove = useCallback( () => removeBlock( clientId ), [ clientId ] ); + + const parentLayout = useLayout() || {}; // 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 @@ -153,13 +154,13 @@ function BlockListBlock( { /> ); - const _blockType = getBlockType( name ); + const blockType = getBlockType( name ); // Determine whether the block has props to apply to the wrapper. - if ( _blockType?.getEditWrapperProps ) { + if ( blockType?.getEditWrapperProps ) { wrapperProps = mergeWrapperProps( wrapperProps, - _blockType.getEditWrapperProps( attributes ) + blockType.getEditWrapperProps( attributes ) ); } @@ -169,17 +170,8 @@ function BlockListBlock( { ! themeSupportsLayout; // Support for sticky position in classic themes with alignment wrappers. - const isSticky = className?.includes( 'is-position-sticky' ); - const { 'data-align': dataAlign, ...restWrapperProps } = wrapperProps ?? {}; - restWrapperProps.className = classnames( - restWrapperProps.className, - dataAlign && themeSupportsLayout && `align${ dataAlign }`, - ! ( dataAlign && isSticky ) && className, - { - 'wp-block': ! isAligned, - } - ); + const isSticky = className?.includes( 'is-position-sticky' ); // For aligned blocks, provide a wrapper element so the block can be // positioned relative to the block column. @@ -205,7 +197,7 @@ function BlockListBlock( { if ( ! isValid ) { const saveContent = __unstableBlockSource ? serializeRawBlock( __unstableBlockSource ) - : getSaveContent( _blockType, attributes ); + : getSaveContent( blockType, attributes ); block = ( @@ -224,12 +216,23 @@ function BlockListBlock( { ); - } else if ( _blockType?.apiVersion > 1 ) { + } else if ( blockType?.apiVersion > 1 ) { block = blockEdit; } else { block = { blockEdit }; } + const { 'data-align': dataAlign, ...restWrapperProps } = wrapperProps ?? {}; + + restWrapperProps.className = classnames( + restWrapperProps.className, + dataAlign && themeSupportsLayout && `align${ dataAlign }`, + ! ( dataAlign && isSticky ) && className, + { + 'wp-block': ! isAligned, + } + ); + return ( 1; + const hasLightBlockWrapper = blockType?.apiVersion > 1; const movingClientId = hasBlockMovingClientId(); - const _hasOverlay = - __unstableHasActiveBlockOverlayActive( clientId ); // Do not add new properties here, use `useSelect` instead to avoid // leaking new props to the public API (editor.BlockListBlock filter). @@ -586,7 +587,6 @@ function BlockListBlockProvider( props ) { attributes, isValid, isSelected: _isSelected, - themeSupportsLayout: supportsLayout, isTemporarilyEditingAsBlocks: __unstableGetTemporarilyEditingAsBlocks() === clientId, @@ -603,9 +603,8 @@ function BlockListBlockProvider( props ) { '__experimentalExposeControlsToChildren', false ) && hasSelectedInnerBlock( clientId ), - index: getBlockIndex( clientId ), - blockTitle: match?.title || _blockType?.title, + blockTitle: match?.title || blockType?.title, isPartOfSelection: _isSelected || isPartOfMultiSelection, adjustScrolling: _isSelected || isFirstMultiSelectedBlock( clientId ), @@ -614,44 +613,36 @@ function BlockListBlockProvider( props ) { getGlobalBlockCount() <= BLOCK_ANIMATION_THRESHOLD, isSubtreeDisabled: isBlockSubtreeDisabled( clientId ), isOutlineEnabled: outlineMode, - hasOverlay: _hasOverlay, + hasOverlay: __unstableHasActiveBlockOverlayActive( clientId ), initialPosition: _isSelected && __unstableGetEditorMode() === 'edit' ? getSelectedBlocksInitialCaretPosition() : undefined, - classNames: classnames( - 'block-editor-block-list__block', - { - 'is-selected': _isSelected, - 'is-highlighted': isBlockHighlighted( clientId ), - 'is-multi-selected': isMultiSelected, - 'is-partially-selected': - isMultiSelected && - ! __unstableIsFullySelected() && - ! __unstableSelectionHasUnmergeableBlock(), - 'is-reusable': isReusableBlock( _blockType ), - 'is-dragging': isBlockBeingDragged( clientId ), - 'has-child-selected': isAncestorOfSelectedBlock, - 'remove-outline': _isSelected && outlineMode && typing, - 'is-block-moving-mode': !! movingClientId, - 'can-insert-moving-block': - movingClientId && - canInsertBlockType( - getBlockName( movingClientId ), - getBlockRootClientId( clientId ) - ), - 'has-block-overlay': _hasOverlay, - 'is-editing-disabled': - getBlockEditingMode( clientId ) === 'disabled', - 'is-content-locked-temporarily-editing-as-blocks': - __unstableGetTemporarilyEditingAsBlocks() === - clientId, - }, - hasLightBlockWrapper ? attributes.className : undefined, - hasLightBlockWrapper - ? getBlockDefaultClassName( blockName ) - : undefined - ), + isHighlighted: isBlockHighlighted( clientId ), + isMultiSelected, + isPartiallySelected: + isMultiSelected && + ! __unstableIsFullySelected() && + ! __unstableSelectionHasUnmergeableBlock(), + isReusable: isReusableBlock( blockType ), + isDragging: isBlockBeingDragged( clientId ), + hasChildSelected: isAncestorOfSelectedBlock, + removeOutline: _isSelected && outlineMode && typing, + isBlockMovingMode: !! movingClientId, + canInsertMovingBlock: + movingClientId && + canInsertBlockType( + getBlockName( movingClientId ), + getBlockRootClientId( clientId ) + ), + isEditingDisabled: + getBlockEditingMode( clientId ) === 'disabled', + className: hasLightBlockWrapper + ? attributes.className + : undefined, + defaultClassName: hasLightBlockWrapper + ? getBlockDefaultClassName( blockName ) + : undefined, }; }, [ clientId, rootClientId ] @@ -669,9 +660,21 @@ function BlockListBlockProvider( props ) { isOutlineEnabled, hasOverlay, initialPosition, - classNames, themeSupportsLayout, blockEditingMode, + isHighlighted, + isMultiSelected, + isPartiallySelected, + isReusable, + isDragging, + hasChildSelected, + removeOutline, + isBlockMovingMode, + canInsertMovingBlock, + isEditingDisabled, + isTemporarilyEditingAsBlocks, + className, + defaultClassName, } = selectedProps; const refs = [ @@ -710,7 +713,27 @@ function BlockListBlockProvider( props ) { 'data-type': name, 'data-title': blockTitle, inert: isSubtreeDisabled ? 'true' : undefined, - className: classNames, + className: classnames( + 'block-editor-block-list__block', + { + 'is-selected': isSelected, + 'is-highlighted': isHighlighted, + 'is-multi-selected': isMultiSelected, + 'is-partially-selected': isPartiallySelected, + 'is-reusable': isReusable, + 'is-dragging': isDragging, + 'has-child-selected': hasChildSelected, + 'remove-outline': removeOutline, + 'is-block-moving-mode': isBlockMovingMode, + 'can-insert-moving-block': canInsertMovingBlock, + 'has-block-overlay': hasOverlay, + 'is-editing-disabled': isEditingDisabled, + 'is-content-locked-temporarily-editing-as-blocks': + isTemporarilyEditingAsBlocks, + }, + className, + defaultClassName + ), }; const publicProps = { From 4d813f5fc0426121f34dcc083df52dc6d3d0325a Mon Sep 17 00:00:00 2001 From: Ella Date: Wed, 13 Dec 2023 19:22:35 +0100 Subject: [PATCH 08/10] minimize diff --- packages/block-editor/README.md | 2 + .../src/components/block-list/block.js | 172 ++++++++---------- .../block-list/use-block-props/index.js | 130 +++++++++++-- 3 files changed, 183 insertions(+), 121 deletions(-) diff --git a/packages/block-editor/README.md b/packages/block-editor/README.md index 8ba720b6cec6ba..56ab5f1bd94d93 100644 --- a/packages/block-editor/README.md +++ b/packages/block-editor/README.md @@ -928,6 +928,8 @@ export default function Edit() { _Parameters_ - _props_ `Object`: Optional. Props to pass to the element. Must contain the ref if one is defined. +- _options_ `Object`: Options for internal use only. +- _options.\_\_unstableIsHtml_ `boolean`: _Returns_ diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index 13ec4c26d90fed..17068e18699506 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -21,9 +21,8 @@ import { } from '@wordpress/blocks'; import { withFilters } from '@wordpress/components'; import { withDispatch, useDispatch, useSelect } from '@wordpress/data'; -import { compose, pure, useDisabled } from '@wordpress/compose'; +import { compose, pure } from '@wordpress/compose'; import { safeHTML } from '@wordpress/dom'; -import { __, sprintf } from '@wordpress/i18n'; /** * Internal dependencies @@ -38,14 +37,6 @@ import { store as blockEditorStore } from '../../store'; import { useLayout } from './layout'; import { BlockListBlockContext } from './block-list-block-context'; -import useMovingAnimation from '../use-moving-animation'; -import { useFocusFirstElement } from './use-block-props/use-focus-first-element'; -import { useIsHovered } from './use-block-props/use-is-hovered'; -import { useFocusHandler } from './use-block-props/use-focus-handler'; -import { useEventHandlers } from './use-block-props/use-selected-block-event-handlers'; -import { useNavModeExit } from './use-block-props/use-nav-mode-exit'; -import { useBlockRefProvider } from './use-block-props/use-block-refs'; -import { useIntersectionObserver } from './use-block-props/use-intersection-observer'; import { unlock } from '../../lock-unlock'; /** @@ -86,11 +77,9 @@ function mergeWrapperProps( propsA, propsB ) { return newProps; } -function Block( { children, mode, isHtml, ...props } ) { - const blockProps = useBlockProps( props ); - const htmlSuffix = mode === 'html' && ! isHtml ? '-visual' : ''; +function Block( { children, isHtml, ...props } ) { return ( -
+
{ children }
); @@ -117,11 +106,10 @@ function BlockListBlock( { toggleSelection, } ) { const { - essentialProps, mayDisplayControls, mayDisplayParentControls, themeSupportsLayout, - refs, + ...context } = useContext( BlockListBlockContext ); const { removeBlock } = useDispatch( blockEditorStore ); const onRemove = useCallback( () => removeBlock( clientId ), [ clientId ] ); @@ -227,18 +215,15 @@ function BlockListBlock( { restWrapperProps.className = classnames( restWrapperProps.className, dataAlign && themeSupportsLayout && `align${ dataAlign }`, - ! ( dataAlign && isSticky ) && className, - { - 'wp-block': ! isAligned, - } + ! ( dataAlign && isSticky ) && className ); return ( - + + ); } 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 c81c92070e429e..d3800d0d638ad1 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 @@ -7,13 +7,24 @@ import classnames from 'classnames'; * WordPress dependencies */ import { useContext } from '@wordpress/element'; +import { __, sprintf } from '@wordpress/i18n'; import { __unstableGetBlockProps as getBlockProps } from '@wordpress/blocks'; -import { useMergeRefs } from '@wordpress/compose'; +import { useMergeRefs, useDisabled } from '@wordpress/compose'; +import warning from '@wordpress/warning'; /** * Internal dependencies */ +import useMovingAnimation from '../../use-moving-animation'; 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'; +import { useFocusHandler } from './use-focus-handler'; +import { useEventHandlers } from './use-selected-block-event-handlers'; +import { useNavModeExit } from './use-nav-mode-exit'; +import { useBlockRefProvider } from './use-block-refs'; +import { useIntersectionObserver } from './use-intersection-observer'; /** * This hook is used to lightly mark an element as a block element. The element @@ -50,35 +61,114 @@ import { BlockListBlockContext } from '../block-list-block-context'; * ``` * * - * @param {Object} props Optional. Props to pass to the element. Must contain - * the ref if one is defined. + * @param {Object} props Optional. Props to pass to the element. Must contain + * the ref if one is defined. + * @param {Object} options Options for internal use only. + * @param {boolean} options.__unstableIsHtml * * @return {Object} Props to pass to the element to mark as a block. */ -export function useBlockProps( props = {} ) { - const { essentialProps, wrapperProps, refs } = useContext( - BlockListBlockContext - ); +export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) { + const { + clientId, + className, + wrapperProps = {}, + isAligned, + index, + mode, + name, + blockApiVersion, + blockTitle, + isSelected, + isPartOfSelection, + adjustScrolling, + enableAnimation, + isSubtreeDisabled, + isOutlineEnabled, + hasOverlay, + initialPosition, + blockEditingMode, + isHighlighted, + isMultiSelected, + isPartiallySelected, + isReusable, + isDragging, + hasChildSelected, + removeOutline, + isBlockMovingMode, + canInsertMovingBlock, + isEditingDisabled, + isTemporarilyEditingAsBlocks, + defaultClassName, + } = useContext( BlockListBlockContext ); + + // translators: %s: Type of block (i.e. Text, Image etc) + const blockLabel = sprintf( __( 'Block: %s' ), blockTitle ); + const htmlSuffix = mode === 'html' && ! __unstableIsHtml ? '-visual' : ''; + const mergedRefs = useMergeRefs( [ + props.ref, + useFocusFirstElement( { clientId, initialPosition } ), + useBlockRefProvider( clientId ), + useFocusHandler( clientId ), + useEventHandlers( { clientId, isSelected } ), + useNavModeExit( clientId ), + useIsHovered( { isEnabled: isOutlineEnabled } ), + useIntersectionObserver(), + useMovingAnimation( { + isSelected: isPartOfSelection, + adjustScrolling, + enableAnimation, + triggerAnimationOnChange: index, + } ), + useDisabled( { isDisabled: ! hasOverlay } ), + ] ); + + const blockEditContext = useBlockEditContext(); + // Ensures it warns only inside the `edit` implementation for the block. + if ( blockApiVersion < 2 && clientId === blockEditContext.clientId ) { + warning( + `Block type "${ name }" must support API version 2 or higher to work correctly with "useBlockProps" method.` + ); + } return { + tabIndex: blockEditingMode === 'disabled' ? -1 : 0, ...wrapperProps, - // Individual block props can override wrapper props. ...props, - // Essential props are always passed through. - ...essentialProps, - // wrapperProps has never been able to pass a ref, so let's not add that - // since it's an API we're likely to deprecate in the future. - ref: useMergeRefs( [ props.ref, ...refs ] ), + ref: mergedRefs, + id: `block-${ clientId }${ htmlSuffix }`, + role: 'document', + 'aria-label': blockLabel, + 'data-block': clientId, + 'data-type': name, + 'data-title': blockTitle, + inert: isSubtreeDisabled ? 'true' : undefined, className: classnames( - wrapperProps.className, + 'block-editor-block-list__block', + { + // The wp-block className is important for editor styles. + 'wp-block': ! isAligned, + 'has-block-overlay': hasOverlay, + 'is-selected': isSelected, + 'is-highlighted': isHighlighted, + 'is-multi-selected': isMultiSelected, + 'is-partially-selected': isPartiallySelected, + 'is-reusable': isReusable, + 'is-dragging': isDragging, + 'has-child-selected': hasChildSelected, + 'remove-outline': removeOutline, + 'is-block-moving-mode': isBlockMovingMode, + 'can-insert-moving-block': canInsertMovingBlock, + 'is-editing-disabled': isEditingDisabled, + 'is-content-locked-temporarily-editing-as-blocks': + isTemporarilyEditingAsBlocks, + }, + className, props.className, - essentialProps.className + wrapperProps.className, + defaultClassName ), - style: { - ...wrapperProps.style, - ...props.style, - ...essentialProps.style, - }, + style: { ...wrapperProps.style, ...props.style }, }; } From 3945c0de0eb0f386c1e9fd79365ea5997662a055 Mon Sep 17 00:00:00 2001 From: Ella Date: Wed, 13 Dec 2023 22:01:17 +0100 Subject: [PATCH 09/10] Add comments --- .../src/components/block-list/block.js | 72 ++++++++++++------- ...ck-context.js => private-block-context.js} | 2 +- .../block-list/use-block-props/index.js | 4 +- 3 files changed, 51 insertions(+), 27 deletions(-) rename packages/block-editor/src/components/block-list/{block-list-block-context.js => private-block-context.js} (59%) diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index 17068e18699506..1e050e3c71e62e 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -35,7 +35,7 @@ import BlockHtml from './block-html'; import { useBlockProps } from './use-block-props'; import { store as blockEditorStore } from '../../store'; import { useLayout } from './layout'; -import { BlockListBlockContext } from './block-list-block-context'; +import { PrivateBlockContext } from './private-block-context'; import { unlock } from '../../lock-unlock'; @@ -110,7 +110,7 @@ function BlockListBlock( { mayDisplayParentControls, themeSupportsLayout, ...context - } = useContext( BlockListBlockContext ); + } = useContext( PrivateBlockContext ); const { removeBlock } = useDispatch( blockEditorStore ); const onRemove = useCallback( () => removeBlock( clientId ), [ clientId ] ); @@ -218,8 +218,11 @@ function BlockListBlock( { ! ( dataAlign && isSticky ) && className ); + // We set a new context with the adjusted and filtered wrapperProps (through + // `editor.BlockListBlock`), which the `BlockListBlockProvider` did not have + // access to. return ( - { block } - + ); } @@ -477,11 +480,19 @@ const applyWithDispatch = withDispatch( ( dispatch, ownProps, registry ) => { }; } ); +// This component is used by the BlockListBlockProvider component below. It will +// add the props necessary for the `editor.BlockListBlock` filters. BlockListBlock = compose( applyWithDispatch, withFilters( 'editor.BlockListBlock' ) )( BlockListBlock ); +// This component provides all the information we need through a single store +// subscription (useSelect mapping). Only the necesssary props are passed down +// to the BlockListBlock component, which is a filtered component, so these +// props are public API. To avoid adding to the public API, we use a private +// context to pass the rest of the information to the filtered BlockListBlock +// component, and useBlockProps. function BlockListBlockProvider( props ) { const { clientId, rootClientId } = props; const selectedProps = useSelect( @@ -681,23 +692,6 @@ function BlockListBlockProvider( props ) { return null; } - const publicAPI = { - mode, - isSelectionEnabled, - isLocked, - canRemove, - canMove, - // Users of the editor.BlockListBlock filter used to be able to - // access the block prop. - // Ideally these blocks would rely on the clientId prop only. - // This is kept for backward compatibility reasons. - block, - name, - attributes, - isValid, - isSelected, - }; - const privateContext = { clientId, className, @@ -732,10 +726,40 @@ function BlockListBlockProvider( props ) { themeSupportsLayout, }; + // Here we separate between the props passed to BlockListBlock and any other + // information we selected for internal use. BlockListBlock is a filtered + // component and thus ALL the props are PUBLIC API. + + // Note that the context value doesn't have to be memoized in this case + // because when it changes, this component will be re-rendered anyway, and + // none of the consumers (BlockListBlock and useBlockProps) are memoized or + // "pure". This is different from the public BlockEditContext, where + // consumers might be memoized or "pure". return ( - - - + + + ); } diff --git a/packages/block-editor/src/components/block-list/block-list-block-context.js b/packages/block-editor/src/components/block-list/private-block-context.js similarity index 59% rename from packages/block-editor/src/components/block-list/block-list-block-context.js rename to packages/block-editor/src/components/block-list/private-block-context.js index 6fa09c6969ec59..14981058965019 100644 --- a/packages/block-editor/src/components/block-list/block-list-block-context.js +++ b/packages/block-editor/src/components/block-list/private-block-context.js @@ -3,4 +3,4 @@ */ import { createContext } from '@wordpress/element'; -export const BlockListBlockContext = createContext( null ); +export const PrivateBlockContext = createContext( null ); 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 d3800d0d638ad1..fea20506c28a1f 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 @@ -16,7 +16,7 @@ import warning from '@wordpress/warning'; * Internal dependencies */ import useMovingAnimation from '../../use-moving-animation'; -import { BlockListBlockContext } from '../block-list-block-context'; +import { PrivateBlockContext } from '../private-block-context'; import { useFocusFirstElement } from './use-focus-first-element'; import { useIsHovered } from './use-is-hovered'; import { useBlockEditContext } from '../../block-edit/context'; @@ -100,7 +100,7 @@ export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) { isEditingDisabled, isTemporarilyEditingAsBlocks, defaultClassName, - } = useContext( BlockListBlockContext ); + } = useContext( PrivateBlockContext ); // translators: %s: Type of block (i.e. Text, Image etc) const blockLabel = sprintf( __( 'Block: %s' ), blockTitle ); From 3e3d83a6a715834fd20a1af9a8e605aae7afddea Mon Sep 17 00:00:00 2001 From: Ella Date: Wed, 13 Dec 2023 22:19:23 +0100 Subject: [PATCH 10/10] Remove old comment --- packages/block-editor/src/components/block-list/block.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index 1e050e3c71e62e..0bd5d0b7e199f8 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -566,8 +566,6 @@ function BlockListBlockProvider( props ) { const hasLightBlockWrapper = blockType?.apiVersion > 1; const movingClientId = hasBlockMovingClientId(); - // Do not add new properties here, use `useSelect` instead to avoid - // leaking new props to the public API (editor.BlockListBlock filter). return { mode: getBlockMode( clientId ), isSelectionEnabled: isSelectionEnabled(),