diff --git a/package-lock.json b/package-lock.json index 5f31410669743..ed407df5473a7 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 9874171ffc95c..bb67634256277 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 d24f8301c85fb..311ac80a3a407 100644 --- a/packages/block-editor/src/components/block-edit/index.js +++ b/packages/block-editor/src/components/block-edit/index.js @@ -1,14 +1,23 @@ +/** + * External dependencies + */ +import { v4 as uuid } from 'uuid'; + /** * WordPress dependencies */ -import { useMemo } from '@wordpress/element'; +import { useMemo, useEffect, useReducer } from '@wordpress/element'; import { hasBlockSupport } from '@wordpress/blocks'; +import { filters, addAction, removeAction } 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. @@ -20,6 +29,79 @@ import { BlockEditContextProvider, useBlockEditContext } from './context'; */ export { useBlockEditContext }; +// Please do not export this at the package level until we have a stable API. +// Hook names must start with a letter. +export const blockControlsFilterName = 'a' + uuid(); + +function BlockControlFilters( props ) { + const { name, isSelected, clientId } = props; + 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 ] + ); + + const [ , forceRender ] = useReducer( () => [] ); + + useEffect( () => { + const namespace = 'core/block-edit/block-controls'; + + function onHooksUpdated( updatedHookName ) { + if ( updatedHookName === blockControlsFilterName ) { + forceRender(); + } + } + + addAction( 'hookRemoved', namespace, onHooksUpdated ); + addAction( 'hookAdded', namespace, onHooksUpdated ); + + return () => { + removeAction( 'hookRemoved', namespace ); + removeAction( 'hookAdded', namespace ); + }; + }, [] ); + + if ( ! shouldDisplayControls ) { + return; + } + + const blockControlFilters = filters[ blockControlsFilterName ]; + + if ( ! blockControlFilters ) { + return; + } + + return blockControlFilters.handlers.map( + ( { callback: Controls, namespace } ) => { + return ; + } + ); +} + export default function BlockEdit( props ) { const { name, @@ -48,6 +130,7 @@ export default function BlockEdit( props ) { // See https://reactjs.org/docs/context.html#caveats. value={ useMemo( () => context, Object.values( context ) ) } > + ); diff --git a/packages/block-editor/src/hooks/align.js b/packages/block-editor/src/hooks/align.js index 8d5c7f850e89b..e3804d4c9cd8f 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, @@ -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, @@ -113,64 +114,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 +240,11 @@ addFilter( withDataAlign ); addFilter( - 'editor.BlockEdit', + blockControlsFilterName, 'core/editor/align/with-toolbar-controls', - withToolbarControls + 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 65e227ab107eb..0035d821a8f42 100644 --- a/packages/block-editor/src/hooks/anchor.js +++ b/packages/block-editor/src/hooks/anchor.js @@ -5,13 +5,14 @@ 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'; +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. @@ -55,82 +56,72 @@ 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' ); - - 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.' - ) } +export const InspectorControl = ( props ) => { + if ( ! 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,11 @@ export function addSaveProps( extraProps, blockType, attributes ) { addFilter( 'blocks.registerBlockType', 'core/anchor/attribute', addAttribute ); addFilter( - 'editor.BlockEdit', + blockControlsFilterName, 'core/editor/anchor/with-inspector-control', - withInspectorControl + ifCondition( ( { name } ) => hasBlockSupport( name, 'anchor' ) )( + 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 1fa8ffc29c858..463ab9f25ef4a 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,7 @@ import { useEffect, useRef, useCallback } from '@wordpress/element'; */ import { store as blockEditorStore } from '../store'; import { BlockControls, BlockSettingsMenuControls } from '../components'; -/** - * External dependencies - */ -import classnames from 'classnames'; +import { blockControlsFilterName } from '../components/block-edit'; function StopEditingAsBlocksOnOutsideSelect( { clientId, @@ -41,133 +37,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', + blockControlsFilterName, '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 fa1a1cadc5712..58b7f4b450614 100644 --- a/packages/block-editor/src/hooks/custom-class-name.js +++ b/packages/block-editor/src/hooks/custom-class-name.js @@ -10,12 +10,13 @@ import { addFilter } from '@wordpress/hooks'; import { TextControl } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { hasBlockSupport } from '@wordpress/blocks'; -import { createHigherOrderComponent } from '@wordpress/compose'; +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`. @@ -43,50 +44,30 @@ 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 ) => { + if ( ! 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 +139,11 @@ addFilter( addAttribute ); addFilter( - 'editor.BlockEdit', + blockControlsFilterName, 'core/editor/custom-class-name/with-inspector-control', - withInspectorControl + 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 b56d9f64b4e83..c73351469b343 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'; @@ -29,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 = []; @@ -183,40 +188,24 @@ 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 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 ! isContentLocked && ; +}; /** * Function that scopes a selector with another one. This works a bit like @@ -338,9 +327,11 @@ addFilter( addDuotoneAttributes ); addFilter( - 'editor.BlockEdit', + blockControlsFilterName, 'core/editor/duotone/with-editor-controls', - withDuotoneControls + 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 aa2d278aee582..b45964c087e6b 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'; @@ -29,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'; @@ -319,29 +324,6 @@ export function addAttribute( settings ) { return settings; } -/** - * Override the default edit UI to include layout controls - * - * @param {Function} BlockEdit Original component. - * - * @return {Function} Wrapped component. - */ -export const withInspectorControls = createHigherOrderComponent( - ( BlockEdit ) => ( props ) => { - const { name: blockName } = props; - const supportLayout = hasBlockSupport( - blockName, - layoutBlockSupportKey - ); - - return [ - supportLayout && , - , - ]; - }, - 'withInspectorControls' -); - /** * Override the default block element to add the layout styles. * @@ -500,7 +482,9 @@ addFilter( withChildLayoutStyles ); addFilter( - 'editor.BlockEdit', + blockControlsFilterName, 'core/editor/layout/with-inspector-controls', - withInspectorControls + ifCondition( ( { name } ) => + hasBlockSupport( name, layoutBlockSupportKey ) + )( LayoutPanel ) ); diff --git a/packages/block-editor/src/hooks/layout.native.js b/packages/block-editor/src/hooks/layout.native.js index 2e9a873bdd1ec..46ea0eb8bf96a 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/position.js b/packages/block-editor/src/hooks/position.js index 2c5589c1920bb..4779c8e4179eb 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, @@ -311,29 +315,17 @@ 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 isPositionDisabled = useIsPositionDisabled( props ); + + if ( isPositionDisabled ) { + return null; + } + + return ; +}; /** * Override the default block element to add the position styles. @@ -395,7 +387,9 @@ addFilter( withPositionStyles ); addFilter( - 'editor.BlockEdit', + 'editor.BlockControls', 'core/editor/position/with-inspector-controls', - withInspectorControls + ifCondition( ( { name } ) => + hasBlockSupport( name, POSITION_SUPPORT_KEY ) + )( PositionInspectorControls ) ); diff --git a/packages/block-editor/src/hooks/style.js b/packages/block-editor/src/hooks/style.js index b6fe7b8188c2b..5e264121c036b 100644 --- a/packages/block-editor/src/hooks/style.js +++ b/packages/block-editor/src/hooks/style.js @@ -32,8 +32,8 @@ import { SPACING_SUPPORT_KEY, DimensionsPanel, } from './dimensions'; -import useDisplayBlockControls from '../components/use-display-block-controls'; import { shouldSkipSerialization } from './utils'; +import { blockControlsFilterName } from '../components/block-edit'; const styleSupportKeys = [ ...TYPOGRAPHY_SUPPORT_KEYS, @@ -340,30 +340,18 @@ 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(); - - return ( - <> - { shouldDisplayControls && ( - <> - - - - - - ) } - - - ); - }, - 'withToolbarControls' -); +export const StyleBlockControls = ( props ) => { + return ( + <> + + + + + + ); +}; /** * Override the default block element to include elements styles. @@ -468,9 +456,9 @@ addFilter( ); addFilter( - 'editor.BlockEdit', + blockControlsFilterName, 'core/style/with-block-controls', - withBlockControls + StyleBlockControls ); addFilter( diff --git a/packages/block-editor/src/hooks/test/align.js b/packages/block-editor/src/hooks/test/align.js index d6a9b3aba65ce..35cda29bf90af 100644 --- a/packages/block-editor/src/hooks/test/align.js +++ b/packages/block-editor/src/hooks/test/align.js @@ -22,7 +22,7 @@ import BlockEdit from '../../components/block-edit'; import BlockEditorProvider from '../../components/provider'; import { getValidAlignments, - withToolbarControls, + ToolbarControls, withDataAlign, addAssignedAlign, } from '../align'; @@ -157,7 +157,7 @@ describe( 'align', () => { } ); } ); - describe( 'withToolbarControls', () => { + describe( 'ToolbarControls', () => { const componentProps = { name: 'core/foo', attributes: {}, @@ -167,14 +167,10 @@ describe( 'align', () => { it( 'should do nothing if no valid alignments', () => { registerBlockType( 'core/foo', blockSettings ); - const EnhancedComponent = withToolbarControls( - ( { wrapperProps } ) =>
- ); - render( - + @@ -197,14 +193,10 @@ describe( 'align', () => { }, } ); - const EnhancedComponent = withToolbarControls( - ( { wrapperProps } ) =>
- ); - render( - + diff --git a/packages/block-library/src/query/index.js b/packages/block-library/src/query/index.js index baf58470b76ac..e3682edf506dd 100644 --- a/packages/block-library/src/query/index.js +++ b/packages/block-library/src/query/index.js @@ -27,6 +27,8 @@ export const settings = { }; export const init = () => { + // 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 } );