From c5abcef7135fa30b539667d740c134591e7003d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20van=C2=A0Durpe?= Date: Tue, 7 Mar 2023 00:10:21 +0200 Subject: [PATCH 1/7] Block editor: dedicated block controls filter --- .../src/components/block-edit/index.js | 39 +++ packages/block-editor/src/hooks/align.js | 105 ++++---- packages/block-editor/src/hooks/anchor.js | 137 +++++------ .../block-editor/src/hooks/content-lock-ui.js | 231 ++++++++---------- .../src/hooks/custom-class-name.js | 74 +++--- packages/block-editor/src/hooks/duotone.js | 58 ++--- packages/block-editor/src/hooks/layout.js | 31 +-- packages/block-editor/src/hooks/position.js | 39 ++- packages/block-editor/src/hooks/style.js | 42 ++-- packages/block-library/src/query/hooks.js | 32 +-- packages/block-library/src/query/index.js | 2 +- 11 files changed, 367 insertions(+), 423 deletions(-) diff --git a/packages/block-editor/src/components/block-edit/index.js b/packages/block-editor/src/components/block-edit/index.js index d24f8301c85fb8..fe2f8554f18e31 100644 --- a/packages/block-editor/src/components/block-edit/index.js +++ b/packages/block-editor/src/components/block-edit/index.js @@ -4,11 +4,15 @@ import { useMemo } from '@wordpress/element'; import { hasBlockSupport } from '@wordpress/blocks'; +import { filters } from '@wordpress/hooks'; +import { useSelect } from '@wordpress/data'; + /** * Internal dependencies */ import Edit from './edit'; import { BlockEditContextProvider, useBlockEditContext } from './context'; +import { store as blockEditorStore } from '../../store'; /** * The `useBlockEditContext` hook provides information about the block this hook is being used in. @@ -41,6 +45,35 @@ export default function BlockEdit( props ) { layout: layoutSupport ? layout : null, __unstableLayoutClassNames, }; + const shouldDisplayControls = useSelect( + ( select ) => { + if ( isSelected ) { + return true; + } + + const { + getBlockName, + isFirstMultiSelectedBlock, + getMultiSelectedBlockClientIds, + hasSelectedInnerBlock, + } = select( blockEditorStore ); + + if ( isFirstMultiSelectedBlock( clientId ) ) { + return getMultiSelectedBlockClientIds().every( + ( id ) => getBlockName( id ) === name + ); + } + + return ( + hasBlockSupport( + getBlockName( clientId ), + '__experimentalExposeControlsToChildren', + false + ) && hasSelectedInnerBlock( clientId ) + ); + }, + [ clientId, isSelected, name ] + ); return ( context, Object.values( context ) ) } > + { shouldDisplayControls && + filters[ 'editor.BlockControls' ].handlers.map( + ( { callback: Controls, namespace } ) => ( + + ) + ) } ); diff --git a/packages/block-editor/src/hooks/align.js b/packages/block-editor/src/hooks/align.js index 8d5c7f850e89b5..14dcbafceffbaa 100644 --- a/packages/block-editor/src/hooks/align.js +++ b/packages/block-editor/src/hooks/align.js @@ -113,64 +113,55 @@ export function addAttribute( settings ) { * Override the default edit UI to include new toolbar controls for block * alignment, if block defines support. * - * @param {Function} BlockEdit Original component. - * - * @return {Function} Wrapped component. + * @param {Object} props */ -export const withToolbarControls = createHigherOrderComponent( - ( BlockEdit ) => ( props ) => { - const blockEdit = ; - const { name: blockName } = props; - // Compute the block valid alignments by taking into account, - // if the theme supports wide alignments or not and the layout's - // availble alignments. We do that for conditionally rendering - // Slot. - const blockAllowedAlignments = getValidAlignments( - getBlockSupport( blockName, 'align' ), - hasBlockSupport( blockName, 'alignWide', true ) - ); - - const validAlignments = useAvailableAlignments( - blockAllowedAlignments - ).map( ( { name } ) => name ); - const isContentLocked = useSelect( - ( select ) => { - return select( - blockEditorStore - ).__unstableGetContentLockingParent( props.clientId ); - }, - [ props.clientId ] - ); - if ( ! validAlignments.length || isContentLocked ) { - return blockEdit; - } +export const ToolbarControls = ( props ) => { + const { name: blockName } = props; + // Compute the block valid alignments by taking into account, + // if the theme supports wide alignments or not and the layout's + // availble alignments. We do that for conditionally rendering + // Slot. + const blockAllowedAlignments = getValidAlignments( + getBlockSupport( blockName, 'align' ), + hasBlockSupport( blockName, 'alignWide', true ) + ); + + const validAlignments = useAvailableAlignments( + blockAllowedAlignments + ).map( ( { name } ) => name ); + const isContentLocked = useSelect( + ( select ) => { + return select( blockEditorStore ).__unstableGetContentLockingParent( + props.clientId + ); + }, + [ props.clientId ] + ); + if ( ! validAlignments.length || isContentLocked ) { + return null; + } - const updateAlignment = ( nextAlign ) => { - if ( ! nextAlign ) { - const blockType = getBlockType( props.name ); - const blockDefaultAlign = blockType?.attributes?.align?.default; - if ( blockDefaultAlign ) { - nextAlign = ''; - } + const updateAlignment = ( nextAlign ) => { + if ( ! nextAlign ) { + const blockType = getBlockType( props.name ); + const blockDefaultAlign = blockType?.attributes?.align?.default; + if ( blockDefaultAlign ) { + nextAlign = ''; } - props.setAttributes( { align: nextAlign } ); - }; - - return ( - <> - - - - { blockEdit } - - ); - }, - 'withToolbarControls' -); + } + props.setAttributes( { align: nextAlign } ); + }; + + return ( + + + + ); +}; /** * Override the default block element to add alignment wrapper props. @@ -248,9 +239,9 @@ addFilter( withDataAlign ); addFilter( - 'editor.BlockEdit', + 'editor.BlockControls', 'core/editor/align/with-toolbar-controls', - withToolbarControls + ToolbarControls ); addFilter( 'blocks.getSaveContent.extraProps', diff --git a/packages/block-editor/src/hooks/anchor.js b/packages/block-editor/src/hooks/anchor.js index 65e227ab107ebf..f35e060aaf772a 100644 --- a/packages/block-editor/src/hooks/anchor.js +++ b/packages/block-editor/src/hooks/anchor.js @@ -5,7 +5,6 @@ import { addFilter } from '@wordpress/hooks'; import { PanelBody, TextControl, ExternalLink } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { hasBlockSupport } from '@wordpress/blocks'; -import { createHigherOrderComponent } from '@wordpress/compose'; import { Platform } from '@wordpress/element'; /** @@ -55,82 +54,74 @@ export function addAttribute( settings ) { * Override the default edit UI to include a new block inspector control for * assigning the anchor ID, if block supports anchor. * - * @param {WPComponent} BlockEdit Original component. - * - * @return {WPComponent} Wrapped component. + * @param {Object} props */ -export const withInspectorControl = createHigherOrderComponent( - ( BlockEdit ) => { - return ( props ) => { - const hasAnchor = hasBlockSupport( props.name, 'anchor' ); +export const InspectorControl = ( props ) => { + const hasAnchor = hasBlockSupport( props.name, 'anchor' ); - if ( hasAnchor && props.isSelected ) { - const isWeb = Platform.OS === 'web'; - const textControl = ( - - { __( - 'Enter a word or two — without spaces — to make a unique web address just for this block, called an “anchor.” Then, you’ll be able to link directly to this section of your page.' - ) } + if ( ! hasAnchor || ! props.isSelected ) { + return null; + } - { isWeb && ( - - { __( 'Learn more about anchors' ) } - - ) } - - } - value={ props.attributes.anchor || '' } - placeholder={ ! isWeb ? __( 'Add an anchor' ) : null } - onChange={ ( nextValue ) => { - nextValue = nextValue.replace( ANCHOR_REGEX, '-' ); - props.setAttributes( { - anchor: nextValue, - } ); - } } - autoCapitalize="none" - autoComplete="off" - /> - ); + const isWeb = Platform.OS === 'web'; + const textControl = ( + + { __( + 'Enter a word or two — without spaces — to make a unique web address just for this block, called an “anchor.” Then, you’ll be able to link directly to this section of your page.' + ) } - return ( - <> - - { isWeb && ( - - { textControl } - - ) } - { /* - * We plan to remove scoping anchors to 'core/heading' to support - * anchors for all eligble blocks. Additionally we plan to explore - * leveraging InspectorAdvancedControls instead of a custom - * PanelBody title. https://github.com/WordPress/gutenberg/issues/28363 - */ } - { ! isWeb && props.name === 'core/heading' && ( - - - { textControl } - - - ) } - - ); + { isWeb && ( + + { __( 'Learn more about anchors' ) } + + ) } + } + value={ props.attributes.anchor || '' } + placeholder={ ! isWeb ? __( 'Add an anchor' ) : null } + onChange={ ( nextValue ) => { + nextValue = nextValue.replace( ANCHOR_REGEX, '-' ); + props.setAttributes( { + anchor: nextValue, + } ); + } } + autoCapitalize="none" + autoComplete="off" + /> + ); - return ; - }; - }, - 'withInspectorControl' -); + return ( + <> + { isWeb && ( + + { textControl } + + ) } + { /* + * We plan to remove scoping anchors to 'core/heading' to support + * anchors for all eligble blocks. Additionally we plan to explore + * leveraging InspectorAdvancedControls instead of a custom + * PanelBody title. https://github.com/WordPress/gutenberg/issues/28363 + */ } + { ! isWeb && props.name === 'core/heading' && ( + + + { textControl } + + + ) } + + ); +}; /** * Override props assigned to save component to inject anchor ID, if block @@ -153,9 +144,9 @@ export function addSaveProps( extraProps, blockType, attributes ) { addFilter( 'blocks.registerBlockType', 'core/anchor/attribute', addAttribute ); addFilter( - 'editor.BlockEdit', + 'editor.BlockControls', 'core/editor/anchor/with-inspector-control', - withInspectorControl + InspectorControl ); addFilter( 'blocks.getSaveContent.extraProps', diff --git a/packages/block-editor/src/hooks/content-lock-ui.js b/packages/block-editor/src/hooks/content-lock-ui.js index 1fa8ffc29c8586..9a31d3a9b16568 100644 --- a/packages/block-editor/src/hooks/content-lock-ui.js +++ b/packages/block-editor/src/hooks/content-lock-ui.js @@ -2,7 +2,6 @@ * WordPress dependencies */ import { ToolbarButton, MenuItem } from '@wordpress/components'; -import { createHigherOrderComponent } from '@wordpress/compose'; import { useDispatch, useSelect } from '@wordpress/data'; import { addFilter } from '@wordpress/hooks'; import { __ } from '@wordpress/i18n'; @@ -13,10 +12,6 @@ import { useEffect, useRef, useCallback } from '@wordpress/element'; */ import { store as blockEditorStore } from '../store'; import { BlockControls, BlockSettingsMenuControls } from '../components'; -/** - * External dependencies - */ -import classnames from 'classnames'; function StopEditingAsBlocksOnOutsideSelect( { clientId, @@ -41,133 +36,117 @@ function StopEditingAsBlocksOnOutsideSelect( { return null; } -export const withBlockControls = createHigherOrderComponent( - ( BlockEdit ) => ( props ) => { - const { getBlockListSettings, getSettings } = - useSelect( blockEditorStore ); - const focusModeToRevert = useRef(); - const { templateLock, isLockedByParent, isEditingAsBlocks } = useSelect( - ( select ) => { - const { - __unstableGetContentLockingParent, - getTemplateLock, - __unstableGetTemporarilyEditingAsBlocks, - } = select( blockEditorStore ); - return { - templateLock: getTemplateLock( props.clientId ), - isLockedByParent: !! __unstableGetContentLockingParent( - props.clientId - ), - isEditingAsBlocks: - __unstableGetTemporarilyEditingAsBlocks() === - props.clientId, - }; - }, - [ props.clientId ] - ); +export const LockUIBlockControls = ( props ) => { + const { getBlockListSettings, getSettings } = useSelect( blockEditorStore ); + const focusModeToRevert = useRef(); + const { templateLock, isLockedByParent, isEditingAsBlocks } = useSelect( + ( select ) => { + const { + __unstableGetContentLockingParent, + getTemplateLock, + __unstableGetTemporarilyEditingAsBlocks, + } = select( blockEditorStore ); + return { + templateLock: getTemplateLock( props.clientId ), + isLockedByParent: !! __unstableGetContentLockingParent( + props.clientId + ), + isEditingAsBlocks: + __unstableGetTemporarilyEditingAsBlocks() === + props.clientId, + }; + }, + [ props.clientId ] + ); - const { - updateSettings, - updateBlockListSettings, - __unstableSetTemporarilyEditingAsBlocks, - } = useDispatch( blockEditorStore ); - const isContentLocked = - ! isLockedByParent && templateLock === 'contentOnly'; - const { - __unstableMarkNextChangeAsNotPersistent, - updateBlockAttributes, - } = useDispatch( blockEditorStore ); + const { + updateSettings, + updateBlockListSettings, + __unstableSetTemporarilyEditingAsBlocks, + } = useDispatch( blockEditorStore ); + const isContentLocked = + ! isLockedByParent && templateLock === 'contentOnly'; + const { __unstableMarkNextChangeAsNotPersistent, updateBlockAttributes } = + useDispatch( blockEditorStore ); - const stopEditingAsBlock = useCallback( () => { - __unstableMarkNextChangeAsNotPersistent(); - updateBlockAttributes( props.clientId, { - templateLock: 'contentOnly', - } ); - updateBlockListSettings( props.clientId, { - ...getBlockListSettings( props.clientId ), - templateLock: 'contentOnly', - } ); - updateSettings( { focusMode: focusModeToRevert.current } ); - __unstableSetTemporarilyEditingAsBlocks(); - }, [ - props.clientId, - focusModeToRevert, - updateSettings, - updateBlockListSettings, - getBlockListSettings, - __unstableMarkNextChangeAsNotPersistent, - updateBlockAttributes, - __unstableSetTemporarilyEditingAsBlocks, - ] ); + const stopEditingAsBlock = useCallback( () => { + __unstableMarkNextChangeAsNotPersistent(); + updateBlockAttributes( props.clientId, { + templateLock: 'contentOnly', + } ); + updateBlockListSettings( props.clientId, { + ...getBlockListSettings( props.clientId ), + templateLock: 'contentOnly', + } ); + updateSettings( { focusMode: focusModeToRevert.current } ); + __unstableSetTemporarilyEditingAsBlocks(); + }, [ + props.clientId, + focusModeToRevert, + updateSettings, + updateBlockListSettings, + getBlockListSettings, + __unstableMarkNextChangeAsNotPersistent, + updateBlockAttributes, + __unstableSetTemporarilyEditingAsBlocks, + ] ); - if ( ! isContentLocked && ! isEditingAsBlocks ) { - return ; - } + if ( ! isContentLocked && ! isEditingAsBlocks ) { + return null; + } - return ( - <> - { isEditingAsBlocks && ! isContentLocked && ( - <> - - - { - stopEditingAsBlock(); - } } - > - { __( 'Done' ) } - - - - ) } - { ! isEditingAsBlocks && isContentLocked && props.isSelected && ( - - { ( { onClose } ) => ( - { - __unstableMarkNextChangeAsNotPersistent(); - updateBlockAttributes( props.clientId, { - templateLock: undefined, - } ); - updateBlockListSettings( props.clientId, { - ...getBlockListSettings( - props.clientId - ), - templateLock: false, - } ); - focusModeToRevert.current = - getSettings().focusMode; - updateSettings( { focusMode: true } ); - __unstableSetTemporarilyEditingAsBlocks( - props.clientId - ); - onClose(); - } } - > - { __( 'Modify' ) } - - ) } - - ) } - + { isEditingAsBlocks && ! isContentLocked && ( + <> + + + { + stopEditingAsBlock(); + } } + > + { __( 'Done' ) } + + + + ) } + { ! isEditingAsBlocks && isContentLocked && props.isSelected && ( + + { ( { onClose } ) => ( + { + __unstableMarkNextChangeAsNotPersistent(); + updateBlockAttributes( props.clientId, { + templateLock: undefined, + } ); + updateBlockListSettings( props.clientId, { + ...getBlockListSettings( props.clientId ), + templateLock: false, + } ); + focusModeToRevert.current = + getSettings().focusMode; + updateSettings( { focusMode: true } ); + __unstableSetTemporarilyEditingAsBlocks( + props.clientId + ); + onClose(); + } } + > + { __( 'Modify' ) } + ) } - /> - - ); - }, - 'withToolbarControls' -); + + ) } + + ); +}; addFilter( - 'editor.BlockEdit', + 'editor.BlockControls', 'core/content-lock-ui/with-block-controls', - withBlockControls + LockUIBlockControls ); diff --git a/packages/block-editor/src/hooks/custom-class-name.js b/packages/block-editor/src/hooks/custom-class-name.js index fa1a1cadc5712a..4c60c24ce20b45 100644 --- a/packages/block-editor/src/hooks/custom-class-name.js +++ b/packages/block-editor/src/hooks/custom-class-name.js @@ -10,7 +10,6 @@ import { addFilter } from '@wordpress/hooks'; import { TextControl } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { hasBlockSupport } from '@wordpress/blocks'; -import { createHigherOrderComponent } from '@wordpress/compose'; /** * Internal dependencies @@ -43,50 +42,35 @@ export function addAttribute( settings ) { * assigning the custom class name, if block supports custom class name. * The control is displayed within the Advanced panel in the block inspector. * - * @param {WPComponent} BlockEdit Original component. - * - * @return {WPComponent} Wrapped component. + * @param {Object} props */ -export const withInspectorControl = createHigherOrderComponent( - ( BlockEdit ) => { - return ( props ) => { - const hasCustomClassName = hasBlockSupport( - props.name, - 'customClassName', - true - ); - if ( hasCustomClassName && props.isSelected ) { - return ( - <> - - - { - props.setAttributes( { - className: - nextValue !== '' - ? nextValue - : undefined, - } ); - } } - help={ __( - 'Separate multiple classes with spaces.' - ) } - /> - - - ); - } +export const InspectorControl = ( props ) => { + const hasCustomClassName = hasBlockSupport( + props.name, + 'customClassName', + true + ); + if ( ! hasCustomClassName || ! props.isSelected ) { + return null; + } - return ; - }; - }, - 'withInspectorControl' -); + return ( + + { + props.setAttributes( { + className: nextValue !== '' ? nextValue : undefined, + } ); + } } + help={ __( 'Separate multiple classes with spaces.' ) } + /> + + ); +}; /** * Override props assigned to save component to inject the className, if block @@ -158,9 +142,9 @@ addFilter( addAttribute ); addFilter( - 'editor.BlockEdit', + 'editor.BlockControls', 'core/editor/custom-class-name/with-inspector-control', - withInspectorControl + InspectorControl ); addFilter( 'blocks.getSaveContent.extraProps', diff --git a/packages/block-editor/src/hooks/duotone.js b/packages/block-editor/src/hooks/duotone.js index b56d9f64b4e832..278c89570f411a 100644 --- a/packages/block-editor/src/hooks/duotone.js +++ b/packages/block-editor/src/hooks/duotone.js @@ -183,40 +183,30 @@ function addDuotoneAttributes( settings ) { * Override the default edit UI to include toolbar controls for duotone if the * block supports duotone. * - * @param {Function} BlockEdit Original component. - * - * @return {Function} Wrapped component. + * @param {Object} props */ -const withDuotoneControls = createHigherOrderComponent( - ( BlockEdit ) => ( props ) => { - const hasDuotoneSupport = hasBlockSupport( - props.name, - 'color.__experimentalDuotone' - ); - const isContentLocked = useSelect( - ( select ) => { - return select( - blockEditorStore - ).__unstableGetContentLockingParent( props.clientId ); - }, - [ props.clientId ] - ); +const DuotoneControls = ( props ) => { + const hasDuotoneSupport = hasBlockSupport( + props.name, + 'color.__experimentalDuotone' + ); + const isContentLocked = useSelect( + ( select ) => { + return select( blockEditorStore ).__unstableGetContentLockingParent( + props.clientId + ); + }, + [ props.clientId ] + ); - // CAUTION: code added before this line will be executed - // for all blocks, not just those that support duotone. Code added - // above this line should be carefully evaluated for its impact on - // performance. - return ( - <> - { hasDuotoneSupport && ! isContentLocked && ( - - ) } - - - ); - }, - 'withDuotoneControls' -); + // CAUTION: code added before this line will be executed + // for all blocks, not just those that support duotone. Code added + // above this line should be carefully evaluated for its impact on + // performance. + return ( + hasDuotoneSupport && ! isContentLocked && + ); +}; /** * Function that scopes a selector with another one. This works a bit like @@ -338,9 +328,9 @@ addFilter( addDuotoneAttributes ); addFilter( - 'editor.BlockEdit', + 'editor.BlockControls', 'core/editor/duotone/with-editor-controls', - withDuotoneControls + DuotoneControls ); addFilter( 'editor.BlockListBlock', diff --git a/packages/block-editor/src/hooks/layout.js b/packages/block-editor/src/hooks/layout.js index aa2d278aee5826..9328d71cf2dafa 100644 --- a/packages/block-editor/src/hooks/layout.js +++ b/packages/block-editor/src/hooks/layout.js @@ -322,25 +322,18 @@ export function addAttribute( settings ) { /** * Override the default edit UI to include layout controls * - * @param {Function} BlockEdit Original component. - * - * @return {Function} Wrapped component. + * @param {Object} props */ -export const withInspectorControls = createHigherOrderComponent( - ( BlockEdit ) => ( props ) => { - const { name: blockName } = props; - const supportLayout = hasBlockSupport( - blockName, - layoutBlockSupportKey - ); +export const LayoutInspectorControls = ( props ) => { + const { name: blockName } = props; + const supportLayout = hasBlockSupport( blockName, layoutBlockSupportKey ); - return [ - supportLayout && , - , - ]; - }, - 'withInspectorControls' -); + if ( ! supportLayout ) { + return null; + } + + return ; +}; /** * Override the default block element to add the layout styles. @@ -500,7 +493,7 @@ addFilter( withChildLayoutStyles ); addFilter( - 'editor.BlockEdit', + 'editor.BlockControls', 'core/editor/layout/with-inspector-controls', - withInspectorControls + LayoutInspectorControls ); diff --git a/packages/block-editor/src/hooks/position.js b/packages/block-editor/src/hooks/position.js index 2c5589c1920bbd..6f87d8716ea694 100644 --- a/packages/block-editor/src/hooks/position.js +++ b/packages/block-editor/src/hooks/position.js @@ -311,29 +311,20 @@ export function PositionPanel( props ) { /** * Override the default edit UI to include position controls. * - * @param {Function} BlockEdit Original component. - * - * @return {Function} Wrapped component. + * @param {Object} props */ -export const withInspectorControls = createHigherOrderComponent( - ( BlockEdit ) => ( props ) => { - const { name: blockName } = props; - const positionSupport = hasBlockSupport( - blockName, - POSITION_SUPPORT_KEY - ); - const showPositionControls = - positionSupport && ! useIsPositionDisabled( props ); - - return [ - showPositionControls && ( - - ), - , - ]; - }, - 'withInspectorControls' -); +export const PositionInspectorControls = ( props ) => { + const { name: blockName } = props; + const positionSupport = hasBlockSupport( blockName, POSITION_SUPPORT_KEY ); + const isPositionDisabled = useIsPositionDisabled( props ); + const showPositionControls = positionSupport && ! isPositionDisabled; + + if ( ! showPositionControls ) { + return null; + } + + return ; +}; /** * Override the default block element to add the position styles. @@ -395,7 +386,7 @@ addFilter( withPositionStyles ); addFilter( - 'editor.BlockEdit', + 'editor.BlockControls', 'core/editor/position/with-inspector-controls', - withInspectorControls + PositionInspectorControls ); diff --git a/packages/block-editor/src/hooks/style.js b/packages/block-editor/src/hooks/style.js index b6fe7b8188c2be..b1f050b942ff6b 100644 --- a/packages/block-editor/src/hooks/style.js +++ b/packages/block-editor/src/hooks/style.js @@ -340,30 +340,24 @@ export function addEditProps( settings ) { * Override the default edit UI to include new inspector controls for * all the custom styles configs. * - * @param {Function} BlockEdit Original component. - * - * @return {Function} Wrapped component. + * @param {Object} props */ -export const withBlockControls = createHigherOrderComponent( - ( BlockEdit ) => ( props ) => { - const shouldDisplayControls = useDisplayBlockControls(); +export const StyleBlockControls = ( props ) => { + const shouldDisplayControls = useDisplayBlockControls(); - return ( - <> - { shouldDisplayControls && ( - <> - - - - - - ) } - - - ); - }, - 'withToolbarControls' -); + if ( ! shouldDisplayControls ) { + return null; + } + + return ( + <> + + + + + + ); +}; /** * Override the default block element to include elements styles. @@ -468,9 +462,9 @@ addFilter( ); addFilter( - 'editor.BlockEdit', + 'editor.BlockControls', 'core/style/with-block-controls', - withBlockControls + StyleBlockControls ); addFilter( diff --git a/packages/block-library/src/query/hooks.js b/packages/block-library/src/query/hooks.js index b2bb32a7be7b4e..a09b13e925ac02 100644 --- a/packages/block-library/src/query/hooks.js +++ b/packages/block-library/src/query/hooks.js @@ -4,7 +4,6 @@ import { __ } from '@wordpress/i18n'; import { createInterpolateElement } from '@wordpress/element'; import { addQueryArgs } from '@wordpress/url'; -import { createHigherOrderComponent } from '@wordpress/compose'; import { InspectorControls } from '@wordpress/block-editor'; const CreateNewPostLink = ( { @@ -28,26 +27,19 @@ const CreateNewPostLink = ( { /** * Override the default edit UI to include layout controls * - * @param {Function} BlockEdit Original component - * @return {Function} Wrapped component + * @param {Object} props */ -const queryTopInspectorControls = createHigherOrderComponent( - ( BlockEdit ) => ( props ) => { - const { name, isSelected } = props; - if ( name !== 'core/query' || ! isSelected ) { - return ; - } +const queryTopInspectorControls = ( props ) => { + const { name, isSelected } = props; + if ( name !== 'core/query' || ! isSelected ) { + return null; + } - return ( - <> - - - - - - ); - }, - 'withInspectorControls' -); + return ( + + + + ); +}; export default queryTopInspectorControls; diff --git a/packages/block-library/src/query/index.js b/packages/block-library/src/query/index.js index baf58470b76ac0..7e01894ce5b607 100644 --- a/packages/block-library/src/query/index.js +++ b/packages/block-library/src/query/index.js @@ -27,7 +27,7 @@ export const settings = { }; export const init = () => { - addFilter( 'editor.BlockEdit', 'core/query', queryInspectorControls ); + addFilter( 'editor.BlockControls', 'core/query', queryInspectorControls ); return initBlock( { name, metadata, settings } ); }; From 56c6679c91231a94784b65401cd5d761cab8436b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20van=C2=A0Durpe?= Date: Tue, 7 Mar 2023 00:40:42 +0200 Subject: [PATCH 2/7] Rerender on hook add/remove --- .../src/components/block-edit/index.js | 94 +++++++++++++------ packages/block-editor/src/hooks/style.js | 7 -- 2 files changed, 65 insertions(+), 36 deletions(-) diff --git a/packages/block-editor/src/components/block-edit/index.js b/packages/block-editor/src/components/block-edit/index.js index fe2f8554f18e31..75b88ac9560f63 100644 --- a/packages/block-editor/src/components/block-edit/index.js +++ b/packages/block-editor/src/components/block-edit/index.js @@ -1,10 +1,10 @@ /** * WordPress dependencies */ -import { useMemo } from '@wordpress/element'; +import { useMemo, useEffect, useReducer } from '@wordpress/element'; import { hasBlockSupport } from '@wordpress/blocks'; -import { filters } from '@wordpress/hooks'; +import { filters, addAction, removeAction } from '@wordpress/hooks'; import { useSelect } from '@wordpress/data'; /** @@ -24,27 +24,8 @@ import { store as blockEditorStore } from '../../store'; */ export { useBlockEditContext }; -export default function BlockEdit( props ) { - const { - name, - isSelected, - clientId, - attributes = {}, - __unstableLayoutClassNames, - } = props; - const { layout = null } = attributes; - const layoutSupport = hasBlockSupport( - name, - '__experimentalLayout', - false - ); - const context = { - name, - isSelected, - clientId, - layout: layoutSupport ? layout : null, - __unstableLayoutClassNames, - }; +function BlockControlFilters( props ) { + const { name, isSelected, clientId } = props; const shouldDisplayControls = useSelect( ( select ) => { if ( isSelected ) { @@ -74,6 +55,66 @@ export default function BlockEdit( props ) { }, [ clientId, isSelected, name ] ); + + const hookName = 'editor.BlockControls'; + const [ , forceRender ] = useReducer( () => [] ); + + useEffect( () => { + const namespace = 'core/block-edit/block-controls'; + + function onHooksUpdated( updatedHookName ) { + if ( updatedHookName === hookName ) { + forceRender(); + } + } + + addAction( 'hookRemoved', namespace, onHooksUpdated ); + addAction( 'hookAdded', namespace, onHooksUpdated ); + + return () => { + removeAction( 'hookRemoved', namespace ); + removeAction( 'hookAdded', namespace ); + }; + } ); + + if ( ! shouldDisplayControls ) { + return; + } + + const blockControlFilters = filters[ hookName ]; + + if ( ! blockControlFilters ) { + return; + } + + return blockControlFilters.handlers.map( + ( { callback: Controls, namespace } ) => ( + + ) + ); +} + +export default function BlockEdit( props ) { + const { + name, + isSelected, + clientId, + attributes = {}, + __unstableLayoutClassNames, + } = props; + const { layout = null } = attributes; + const layoutSupport = hasBlockSupport( + name, + '__experimentalLayout', + false + ); + const context = { + name, + isSelected, + clientId, + layout: layoutSupport ? layout : null, + __unstableLayoutClassNames, + }; return ( context, Object.values( context ) ) } > - { shouldDisplayControls && - filters[ 'editor.BlockControls' ].handlers.map( - ( { callback: Controls, namespace } ) => ( - - ) - ) } + ); diff --git a/packages/block-editor/src/hooks/style.js b/packages/block-editor/src/hooks/style.js index b1f050b942ff6b..cec6be71e7e65e 100644 --- a/packages/block-editor/src/hooks/style.js +++ b/packages/block-editor/src/hooks/style.js @@ -32,7 +32,6 @@ import { SPACING_SUPPORT_KEY, DimensionsPanel, } from './dimensions'; -import useDisplayBlockControls from '../components/use-display-block-controls'; import { shouldSkipSerialization } from './utils'; const styleSupportKeys = [ @@ -343,12 +342,6 @@ export function addEditProps( settings ) { * @param {Object} props */ export const StyleBlockControls = ( props ) => { - const shouldDisplayControls = useDisplayBlockControls(); - - if ( ! shouldDisplayControls ) { - return null; - } - return ( <> From 2b6f49effa537da6dd4cdca0431b794f0d0e6b18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20van=C2=A0Durpe?= Date: Tue, 7 Mar 2023 10:08:02 +0200 Subject: [PATCH 3/7] Add support key conditions --- packages/block-editor/src/hooks/align.js | 6 +++-- packages/block-editor/src/hooks/anchor.js | 9 ++++--- .../src/hooks/custom-class-name.js | 12 ++++----- packages/block-editor/src/hooks/duotone.js | 18 ++++++------- packages/block-editor/src/hooks/layout.js | 26 ++++++------------- packages/block-editor/src/hooks/position.js | 15 ++++++----- packages/block-editor/src/hooks/test/align.js | 21 +++------------ 7 files changed, 44 insertions(+), 63 deletions(-) diff --git a/packages/block-editor/src/hooks/align.js b/packages/block-editor/src/hooks/align.js index 14dcbafceffbaa..fa2d7b94c68ae5 100644 --- a/packages/block-editor/src/hooks/align.js +++ b/packages/block-editor/src/hooks/align.js @@ -6,7 +6,7 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { createHigherOrderComponent } from '@wordpress/compose'; +import { createHigherOrderComponent, ifCondition } from '@wordpress/compose'; import { addFilter } from '@wordpress/hooks'; import { getBlockSupport, @@ -241,7 +241,9 @@ addFilter( addFilter( 'editor.BlockControls', 'core/editor/align/with-toolbar-controls', - ToolbarControls + ifCondition( ( { name } ) => hasBlockSupport( name, 'align' ) )( + ToolbarControls + ) ); addFilter( 'blocks.getSaveContent.extraProps', diff --git a/packages/block-editor/src/hooks/anchor.js b/packages/block-editor/src/hooks/anchor.js index f35e060aaf772a..841bfae58b8ee4 100644 --- a/packages/block-editor/src/hooks/anchor.js +++ b/packages/block-editor/src/hooks/anchor.js @@ -6,6 +6,7 @@ import { PanelBody, TextControl, ExternalLink } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { hasBlockSupport } from '@wordpress/blocks'; import { Platform } from '@wordpress/element'; +import { ifCondition } from '@wordpress/compose'; /** * Internal dependencies @@ -57,9 +58,7 @@ export function addAttribute( settings ) { * @param {Object} props */ export const InspectorControl = ( props ) => { - const hasAnchor = hasBlockSupport( props.name, 'anchor' ); - - if ( ! hasAnchor || ! props.isSelected ) { + if ( ! props.isSelected ) { return null; } @@ -146,7 +145,9 @@ addFilter( 'blocks.registerBlockType', 'core/anchor/attribute', addAttribute ); addFilter( 'editor.BlockControls', 'core/editor/anchor/with-inspector-control', - InspectorControl + ifCondition( ( { name } ) => hasBlockSupport( name, 'anchor' ) )( + InspectorControl + ) ); addFilter( 'blocks.getSaveContent.extraProps', diff --git a/packages/block-editor/src/hooks/custom-class-name.js b/packages/block-editor/src/hooks/custom-class-name.js index 4c60c24ce20b45..fcdfd2bcc781c9 100644 --- a/packages/block-editor/src/hooks/custom-class-name.js +++ b/packages/block-editor/src/hooks/custom-class-name.js @@ -10,6 +10,7 @@ import { addFilter } from '@wordpress/hooks'; import { TextControl } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { hasBlockSupport } from '@wordpress/blocks'; +import { ifCondition } from '@wordpress/compose'; /** * Internal dependencies @@ -45,12 +46,7 @@ export function addAttribute( settings ) { * @param {Object} props */ export const InspectorControl = ( props ) => { - const hasCustomClassName = hasBlockSupport( - props.name, - 'customClassName', - true - ); - if ( ! hasCustomClassName || ! props.isSelected ) { + if ( ! props.isSelected ) { return null; } @@ -144,7 +140,9 @@ addFilter( addFilter( 'editor.BlockControls', 'core/editor/custom-class-name/with-inspector-control', - InspectorControl + ifCondition( ( { name } ) => + hasBlockSupport( name, 'customClassName', true ) + )( InspectorControl ) ); addFilter( 'blocks.getSaveContent.extraProps', diff --git a/packages/block-editor/src/hooks/duotone.js b/packages/block-editor/src/hooks/duotone.js index 278c89570f411a..2288b229649b74 100644 --- a/packages/block-editor/src/hooks/duotone.js +++ b/packages/block-editor/src/hooks/duotone.js @@ -9,7 +9,11 @@ import namesPlugin from 'colord/plugins/names'; * WordPress dependencies */ import { getBlockSupport, hasBlockSupport } from '@wordpress/blocks'; -import { createHigherOrderComponent, useInstanceId } from '@wordpress/compose'; +import { + createHigherOrderComponent, + ifCondition, + useInstanceId, +} from '@wordpress/compose'; import { addFilter } from '@wordpress/hooks'; import { useMemo, useContext, createPortal } from '@wordpress/element'; import { useSelect } from '@wordpress/data'; @@ -186,10 +190,6 @@ function addDuotoneAttributes( settings ) { * @param {Object} props */ const DuotoneControls = ( props ) => { - const hasDuotoneSupport = hasBlockSupport( - props.name, - 'color.__experimentalDuotone' - ); const isContentLocked = useSelect( ( select ) => { return select( blockEditorStore ).__unstableGetContentLockingParent( @@ -203,9 +203,7 @@ const DuotoneControls = ( props ) => { // for all blocks, not just those that support duotone. Code added // above this line should be carefully evaluated for its impact on // performance. - return ( - hasDuotoneSupport && ! isContentLocked && - ); + return ! isContentLocked && ; }; /** @@ -330,7 +328,9 @@ addFilter( addFilter( 'editor.BlockControls', 'core/editor/duotone/with-editor-controls', - DuotoneControls + ifCondition( ( { name } ) => + hasBlockSupport( name, 'color.__experimentalDuotone' ) + )( DuotoneControls ) ); addFilter( 'editor.BlockListBlock', diff --git a/packages/block-editor/src/hooks/layout.js b/packages/block-editor/src/hooks/layout.js index 9328d71cf2dafa..c7373d14e5589e 100644 --- a/packages/block-editor/src/hooks/layout.js +++ b/packages/block-editor/src/hooks/layout.js @@ -7,7 +7,11 @@ import { kebabCase } from 'lodash'; /** * WordPress dependencies */ -import { createHigherOrderComponent, useInstanceId } from '@wordpress/compose'; +import { + createHigherOrderComponent, + ifCondition, + useInstanceId, +} from '@wordpress/compose'; import { addFilter } from '@wordpress/hooks'; import { getBlockSupport, hasBlockSupport } from '@wordpress/blocks'; import { useSelect } from '@wordpress/data'; @@ -319,22 +323,6 @@ export function addAttribute( settings ) { return settings; } -/** - * Override the default edit UI to include layout controls - * - * @param {Object} props - */ -export const LayoutInspectorControls = ( props ) => { - const { name: blockName } = props; - const supportLayout = hasBlockSupport( blockName, layoutBlockSupportKey ); - - if ( ! supportLayout ) { - return null; - } - - return ; -}; - /** * Override the default block element to add the layout styles. * @@ -495,5 +483,7 @@ addFilter( addFilter( 'editor.BlockControls', 'core/editor/layout/with-inspector-controls', - LayoutInspectorControls + ifCondition( ( { name } ) => + hasBlockSupport( name, layoutBlockSupportKey ) + )( LayoutPanel ) ); diff --git a/packages/block-editor/src/hooks/position.js b/packages/block-editor/src/hooks/position.js index 6f87d8716ea694..4779c8e4179ebb 100644 --- a/packages/block-editor/src/hooks/position.js +++ b/packages/block-editor/src/hooks/position.js @@ -12,7 +12,11 @@ import { BaseControl, privateApis as componentsPrivateApis, } from '@wordpress/components'; -import { createHigherOrderComponent, useInstanceId } from '@wordpress/compose'; +import { + createHigherOrderComponent, + ifCondition, + useInstanceId, +} from '@wordpress/compose'; import { useSelect } from '@wordpress/data'; import { useContext, @@ -314,12 +318,9 @@ export function PositionPanel( props ) { * @param {Object} props */ export const PositionInspectorControls = ( props ) => { - const { name: blockName } = props; - const positionSupport = hasBlockSupport( blockName, POSITION_SUPPORT_KEY ); const isPositionDisabled = useIsPositionDisabled( props ); - const showPositionControls = positionSupport && ! isPositionDisabled; - if ( ! showPositionControls ) { + if ( isPositionDisabled ) { return null; } @@ -388,5 +389,7 @@ addFilter( addFilter( 'editor.BlockControls', 'core/editor/position/with-inspector-controls', - PositionInspectorControls + ifCondition( ( { name } ) => + hasBlockSupport( name, POSITION_SUPPORT_KEY ) + )( PositionInspectorControls ) ); diff --git a/packages/block-editor/src/hooks/test/align.js b/packages/block-editor/src/hooks/test/align.js index d6a9b3aba65ce4..9f16839d8cd542 100644 --- a/packages/block-editor/src/hooks/test/align.js +++ b/packages/block-editor/src/hooks/test/align.js @@ -18,11 +18,10 @@ import { SlotFillProvider } from '@wordpress/components'; * Internal dependencies */ import BlockControls from '../../components/block-controls'; -import BlockEdit from '../../components/block-edit'; import BlockEditorProvider from '../../components/provider'; import { getValidAlignments, - withToolbarControls, + ToolbarControls, withDataAlign, addAssignedAlign, } from '../align'; @@ -157,7 +156,7 @@ describe( 'align', () => { } ); } ); - describe( 'withToolbarControls', () => { + describe( 'ToolbarControls', () => { const componentProps = { name: 'core/foo', attributes: {}, @@ -167,15 +166,9 @@ describe( 'align', () => { it( 'should do nothing if no valid alignments', () => { registerBlockType( 'core/foo', blockSettings ); - const EnhancedComponent = withToolbarControls( - ( { wrapperProps } ) =>
- ); - render( - - - + ); @@ -197,15 +190,9 @@ describe( 'align', () => { }, } ); - const EnhancedComponent = withToolbarControls( - ( { wrapperProps } ) =>
- ); - render( - - - + ); From b2f240a530387099cede9ab38b8e33065b93af04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20van=C2=A0Durpe?= Date: Tue, 7 Mar 2023 10:21:54 +0200 Subject: [PATCH 4/7] Forgot dependencies --- packages/block-editor/src/components/block-edit/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/block-edit/index.js b/packages/block-editor/src/components/block-edit/index.js index 75b88ac9560f63..edcc094f4373fd 100644 --- a/packages/block-editor/src/components/block-edit/index.js +++ b/packages/block-editor/src/components/block-edit/index.js @@ -75,7 +75,7 @@ function BlockControlFilters( props ) { removeAction( 'hookRemoved', namespace ); removeAction( 'hookAdded', namespace ); }; - } ); + }, [] ); if ( ! shouldDisplayControls ) { return; From 724a1514e2a197c44589f4d8dbf2d97a26605658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20van=C2=A0Durpe?= Date: Tue, 7 Mar 2023 13:19:05 +0200 Subject: [PATCH 5/7] Make filter key private --- package-lock.json | 3 +- packages/block-editor/package.json | 3 +- .../src/components/block-edit/index.js | 19 +++++++---- packages/block-editor/src/hooks/align.js | 3 +- packages/block-editor/src/hooks/anchor.js | 3 +- .../block-editor/src/hooks/content-lock-ui.js | 3 +- .../src/hooks/custom-class-name.js | 3 +- packages/block-editor/src/hooks/duotone.js | 3 +- packages/block-editor/src/hooks/layout.js | 3 +- packages/block-editor/src/hooks/style.js | 3 +- packages/block-library/src/query/hooks.js | 32 ++++++++++++------- packages/block-library/src/query/index.js | 4 ++- 12 files changed, 54 insertions(+), 28 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5f314106697431..ed407df5473a70 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17338,7 +17338,8 @@ "react-easy-crop": "^4.5.1", "rememo": "^4.0.0", "remove-accents": "^0.4.2", - "traverse": "^0.6.6" + "traverse": "^0.6.6", + "uuid": "8.3.0" } }, "@wordpress/block-library": { diff --git a/packages/block-editor/package.json b/packages/block-editor/package.json index 9874171ffc95cf..bb676342562775 100644 --- a/packages/block-editor/package.json +++ b/packages/block-editor/package.json @@ -74,7 +74,8 @@ "react-easy-crop": "^4.5.1", "rememo": "^4.0.0", "remove-accents": "^0.4.2", - "traverse": "^0.6.6" + "traverse": "^0.6.6", + "uuid": "8.3.0" }, "peerDependencies": { "react": "^18.0.0", diff --git a/packages/block-editor/src/components/block-edit/index.js b/packages/block-editor/src/components/block-edit/index.js index edcc094f4373fd..553c467783f727 100644 --- a/packages/block-editor/src/components/block-edit/index.js +++ b/packages/block-editor/src/components/block-edit/index.js @@ -1,3 +1,8 @@ +/** + * External dependencies + */ +import { v4 as uuid } from 'uuid'; + /** * WordPress dependencies */ @@ -24,6 +29,9 @@ import { store as blockEditorStore } from '../../store'; */ export { useBlockEditContext }; +// Please do not export this at the package level until we have a stable API. +export const blockControlsFilterName = uuid(); + function BlockControlFilters( props ) { const { name, isSelected, clientId } = props; const shouldDisplayControls = useSelect( @@ -56,14 +64,13 @@ function BlockControlFilters( props ) { [ clientId, isSelected, name ] ); - const hookName = 'editor.BlockControls'; const [ , forceRender ] = useReducer( () => [] ); useEffect( () => { const namespace = 'core/block-edit/block-controls'; function onHooksUpdated( updatedHookName ) { - if ( updatedHookName === hookName ) { + if ( updatedHookName === blockControlsFilterName ) { forceRender(); } } @@ -81,16 +88,16 @@ function BlockControlFilters( props ) { return; } - const blockControlFilters = filters[ hookName ]; + const blockControlFilters = filters[ blockControlsFilterName ]; if ( ! blockControlFilters ) { return; } return blockControlFilters.handlers.map( - ( { callback: Controls, namespace } ) => ( - - ) + ( { callback: Controls, namespace } ) => { + return ; + } ); } diff --git a/packages/block-editor/src/hooks/align.js b/packages/block-editor/src/hooks/align.js index fa2d7b94c68ae5..e3804d4c9cd8fb 100644 --- a/packages/block-editor/src/hooks/align.js +++ b/packages/block-editor/src/hooks/align.js @@ -21,6 +21,7 @@ import { useSelect } from '@wordpress/data'; import { BlockControls, BlockAlignmentControl } from '../components'; import useAvailableAlignments from '../components/block-alignment-control/use-available-alignments'; import { store as blockEditorStore } from '../store'; +import { blockControlsFilterName } from '../components/block-edit'; /** * An array which includes all possible valid alignments, @@ -239,7 +240,7 @@ addFilter( withDataAlign ); addFilter( - 'editor.BlockControls', + blockControlsFilterName, 'core/editor/align/with-toolbar-controls', ifCondition( ( { name } ) => hasBlockSupport( name, 'align' ) )( ToolbarControls diff --git a/packages/block-editor/src/hooks/anchor.js b/packages/block-editor/src/hooks/anchor.js index 841bfae58b8ee4..0035d821a8f428 100644 --- a/packages/block-editor/src/hooks/anchor.js +++ b/packages/block-editor/src/hooks/anchor.js @@ -12,6 +12,7 @@ import { ifCondition } from '@wordpress/compose'; * Internal dependencies */ import { InspectorControls } from '../components'; +import { blockControlsFilterName } from '../components/block-edit'; /** * Regular expression matching invalid anchor characters for replacement. @@ -143,7 +144,7 @@ export function addSaveProps( extraProps, blockType, attributes ) { addFilter( 'blocks.registerBlockType', 'core/anchor/attribute', addAttribute ); addFilter( - 'editor.BlockControls', + blockControlsFilterName, 'core/editor/anchor/with-inspector-control', ifCondition( ( { name } ) => hasBlockSupport( name, 'anchor' ) )( InspectorControl diff --git a/packages/block-editor/src/hooks/content-lock-ui.js b/packages/block-editor/src/hooks/content-lock-ui.js index 9a31d3a9b16568..463ab9f25ef4a1 100644 --- a/packages/block-editor/src/hooks/content-lock-ui.js +++ b/packages/block-editor/src/hooks/content-lock-ui.js @@ -12,6 +12,7 @@ import { useEffect, useRef, useCallback } from '@wordpress/element'; */ import { store as blockEditorStore } from '../store'; import { BlockControls, BlockSettingsMenuControls } from '../components'; +import { blockControlsFilterName } from '../components/block-edit'; function StopEditingAsBlocksOnOutsideSelect( { clientId, @@ -146,7 +147,7 @@ export const LockUIBlockControls = ( props ) => { }; addFilter( - 'editor.BlockControls', + blockControlsFilterName, 'core/content-lock-ui/with-block-controls', LockUIBlockControls ); diff --git a/packages/block-editor/src/hooks/custom-class-name.js b/packages/block-editor/src/hooks/custom-class-name.js index fcdfd2bcc781c9..58b7f4b450614c 100644 --- a/packages/block-editor/src/hooks/custom-class-name.js +++ b/packages/block-editor/src/hooks/custom-class-name.js @@ -16,6 +16,7 @@ import { ifCondition } from '@wordpress/compose'; * Internal dependencies */ import { InspectorControls } from '../components'; +import { blockControlsFilterName } from '../components/block-edit'; /** * Filters registered block settings, extending attributes to include `className`. @@ -138,7 +139,7 @@ addFilter( addAttribute ); addFilter( - 'editor.BlockControls', + blockControlsFilterName, 'core/editor/custom-class-name/with-inspector-control', ifCondition( ( { name } ) => hasBlockSupport( name, 'customClassName', true ) diff --git a/packages/block-editor/src/hooks/duotone.js b/packages/block-editor/src/hooks/duotone.js index 2288b229649b74..c73351469b3433 100644 --- a/packages/block-editor/src/hooks/duotone.js +++ b/packages/block-editor/src/hooks/duotone.js @@ -33,6 +33,7 @@ import { __unstableDuotoneUnsetStylesheet as DuotoneUnsetStylesheet, } from '../components/duotone'; import { store as blockEditorStore } from '../store'; +import { blockControlsFilterName } from '../components/block-edit'; const EMPTY_ARRAY = []; @@ -326,7 +327,7 @@ addFilter( addDuotoneAttributes ); addFilter( - 'editor.BlockControls', + blockControlsFilterName, 'core/editor/duotone/with-editor-controls', ifCondition( ( { name } ) => hasBlockSupport( name, 'color.__experimentalDuotone' ) diff --git a/packages/block-editor/src/hooks/layout.js b/packages/block-editor/src/hooks/layout.js index c7373d14e5589e..b45964c087e6bd 100644 --- a/packages/block-editor/src/hooks/layout.js +++ b/packages/block-editor/src/hooks/layout.js @@ -33,6 +33,7 @@ import useSetting from '../components/use-setting'; import { LayoutStyle } from '../components/block-list/layout'; import BlockList from '../components/block-list'; import { getLayoutType, getLayoutTypes } from '../layouts'; +import { blockControlsFilterName } from '../components/block-edit'; const layoutBlockSupportKey = '__experimentalLayout'; @@ -481,7 +482,7 @@ addFilter( withChildLayoutStyles ); addFilter( - 'editor.BlockControls', + blockControlsFilterName, 'core/editor/layout/with-inspector-controls', ifCondition( ( { name } ) => hasBlockSupport( name, layoutBlockSupportKey ) diff --git a/packages/block-editor/src/hooks/style.js b/packages/block-editor/src/hooks/style.js index cec6be71e7e65e..5e264121c036b0 100644 --- a/packages/block-editor/src/hooks/style.js +++ b/packages/block-editor/src/hooks/style.js @@ -33,6 +33,7 @@ import { DimensionsPanel, } from './dimensions'; import { shouldSkipSerialization } from './utils'; +import { blockControlsFilterName } from '../components/block-edit'; const styleSupportKeys = [ ...TYPOGRAPHY_SUPPORT_KEYS, @@ -455,7 +456,7 @@ addFilter( ); addFilter( - 'editor.BlockControls', + blockControlsFilterName, 'core/style/with-block-controls', StyleBlockControls ); diff --git a/packages/block-library/src/query/hooks.js b/packages/block-library/src/query/hooks.js index a09b13e925ac02..b2bb32a7be7b4e 100644 --- a/packages/block-library/src/query/hooks.js +++ b/packages/block-library/src/query/hooks.js @@ -4,6 +4,7 @@ import { __ } from '@wordpress/i18n'; import { createInterpolateElement } from '@wordpress/element'; import { addQueryArgs } from '@wordpress/url'; +import { createHigherOrderComponent } from '@wordpress/compose'; import { InspectorControls } from '@wordpress/block-editor'; const CreateNewPostLink = ( { @@ -27,19 +28,26 @@ const CreateNewPostLink = ( { /** * Override the default edit UI to include layout controls * - * @param {Object} props + * @param {Function} BlockEdit Original component + * @return {Function} Wrapped component */ -const queryTopInspectorControls = ( props ) => { - const { name, isSelected } = props; - if ( name !== 'core/query' || ! isSelected ) { - return null; - } +const queryTopInspectorControls = createHigherOrderComponent( + ( BlockEdit ) => ( props ) => { + const { name, isSelected } = props; + if ( name !== 'core/query' || ! isSelected ) { + return ; + } - return ( - - - - ); -}; + return ( + <> + + + + + + ); + }, + 'withInspectorControls' +); export default queryTopInspectorControls; diff --git a/packages/block-library/src/query/index.js b/packages/block-library/src/query/index.js index 7e01894ce5b607..e3682edf506ddb 100644 --- a/packages/block-library/src/query/index.js +++ b/packages/block-library/src/query/index.js @@ -27,7 +27,9 @@ export const settings = { }; export const init = () => { - addFilter( 'editor.BlockControls', 'core/query', queryInspectorControls ); + // This is a temporary solution so the link is displayed at the top. + // See https://github.com/WordPress/gutenberg/pull/31833/files#r634291993. + addFilter( 'editor.BlockEdit', 'core/query', queryInspectorControls ); return initBlock( { name, metadata, settings } ); }; From 49e6aa623356fc47ef444a63b5075c8985dc592e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20van=C2=A0Durpe?= Date: Tue, 7 Mar 2023 14:59:26 +0200 Subject: [PATCH 6/7] Make sure the hook name starts with a letter --- packages/block-editor/src/components/block-edit/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/block-edit/index.js b/packages/block-editor/src/components/block-edit/index.js index 553c467783f727..311ac80a3a4070 100644 --- a/packages/block-editor/src/components/block-edit/index.js +++ b/packages/block-editor/src/components/block-edit/index.js @@ -30,7 +30,8 @@ import { store as blockEditorStore } from '../../store'; export { useBlockEditContext }; // Please do not export this at the package level until we have a stable API. -export const blockControlsFilterName = uuid(); +// Hook names must start with a letter. +export const blockControlsFilterName = 'a' + uuid(); function BlockControlFilters( props ) { const { name, isSelected, clientId } = props; From afd49e873f7623ab1b93f9d07755f91469915bac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20van=C2=A0Durpe?= Date: Tue, 7 Mar 2023 20:45:17 +0200 Subject: [PATCH 7/7] Fix unit tests --- packages/block-editor/src/hooks/layout.native.js | 3 ++- packages/block-editor/src/hooks/test/align.js | 9 +++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/block-editor/src/hooks/layout.native.js b/packages/block-editor/src/hooks/layout.native.js index 2e9a873bdd1ecf..46ea0eb8bf96ad 100644 --- a/packages/block-editor/src/hooks/layout.native.js +++ b/packages/block-editor/src/hooks/layout.native.js @@ -7,6 +7,7 @@ import { removeFilter } from '@wordpress/hooks'; * Internal dependencies */ import './layout.js'; +import { blockControlsFilterName } from '../components/block-edit'; // This filter is removed because layout styles shouldn't be added // until layout types are supported in the native version. @@ -18,6 +19,6 @@ removeFilter( // This filter is removed because the layout controls shouldn't be // enabled until layout types are supported in the native version. removeFilter( - 'editor.BlockEdit', + blockControlsFilterName, 'core/editor/layout/with-inspector-controls' ); diff --git a/packages/block-editor/src/hooks/test/align.js b/packages/block-editor/src/hooks/test/align.js index 9f16839d8cd542..35cda29bf90afd 100644 --- a/packages/block-editor/src/hooks/test/align.js +++ b/packages/block-editor/src/hooks/test/align.js @@ -18,6 +18,7 @@ import { SlotFillProvider } from '@wordpress/components'; * Internal dependencies */ import BlockControls from '../../components/block-controls'; +import BlockEdit from '../../components/block-edit'; import BlockEditorProvider from '../../components/provider'; import { getValidAlignments, @@ -168,7 +169,9 @@ describe( 'align', () => { render( - + + + ); @@ -192,7 +195,9 @@ describe( 'align', () => { render( - + + + );