diff --git a/packages/block-editor/src/components/block-controls/hook.js b/packages/block-editor/src/components/block-controls/hook.js index 18a38e245e58a..e3f69c8bec3b2 100644 --- a/packages/block-editor/src/components/block-controls/hook.js +++ b/packages/block-editor/src/components/block-controls/hook.js @@ -1,45 +1,19 @@ /** * WordPress dependencies */ -import { store as blocksStore } from '@wordpress/blocks'; -import { useSelect } from '@wordpress/data'; /** * Internal dependencies */ import groups from './groups'; -import { store as blockEditorStore } from '../../store'; -import { useBlockEditContext } from '../block-edit/context'; import useDisplayBlockControls from '../use-display-block-controls'; export default function useBlockControlsFill( group, shareWithChildBlocks ) { - const isDisplayed = useDisplayBlockControls(); - const { clientId } = useBlockEditContext(); - const isParentDisplayed = useSelect( - ( select ) => { - if ( ! shareWithChildBlocks ) { - return false; - } - - const { getBlockName, hasSelectedInnerBlock } = - select( blockEditorStore ); - const { hasBlockSupport } = select( blocksStore ); - - return ( - hasBlockSupport( - getBlockName( clientId ), - '__experimentalExposeControlsToChildren', - false - ) && hasSelectedInnerBlock( clientId ) - ); - }, - [ shareWithChildBlocks, clientId ] - ); - + const { isDisplayed, isParentDisplayed } = useDisplayBlockControls(); if ( isDisplayed ) { return groups[ group ]?.Fill; } - if ( isParentDisplayed ) { + if ( isParentDisplayed && shareWithChildBlocks ) { return groups.parent.Fill; } return null; diff --git a/packages/block-editor/src/components/block-info-slot-fill/index.js b/packages/block-editor/src/components/block-info-slot-fill/index.js index db7919b6ef5ea..8e16757f3ebbc 100644 --- a/packages/block-editor/src/components/block-info-slot-fill/index.js +++ b/packages/block-editor/src/components/block-info-slot-fill/index.js @@ -13,7 +13,7 @@ const { createPrivateSlotFill } = unlock( componentsPrivateApis ); const { Fill, Slot } = createPrivateSlotFill( 'BlockInformation' ); const BlockInfo = ( props ) => { - const isDisplayed = useDisplayBlockControls(); + const { isDisplayed } = useDisplayBlockControls(); if ( ! isDisplayed ) { return null; } diff --git a/packages/block-editor/src/components/inspector-controls/fill.js b/packages/block-editor/src/components/inspector-controls/fill.js index f0640a9d31ddc..fdb0d44f0eccb 100644 --- a/packages/block-editor/src/components/inspector-controls/fill.js +++ b/packages/block-editor/src/components/inspector-controls/fill.js @@ -33,7 +33,7 @@ export default function InspectorControlsFill( { group = __experimentalGroup; } - const isDisplayed = useDisplayBlockControls(); + const { isDisplayed } = useDisplayBlockControls(); const Fill = groups[ group ]?.Fill; if ( ! Fill ) { warning( `Unknown InspectorControls group "${ group }" provided.` ); diff --git a/packages/block-editor/src/components/inspector-controls/fill.native.js b/packages/block-editor/src/components/inspector-controls/fill.native.js index d38d865cd15cc..f1ee5a14cd18e 100644 --- a/packages/block-editor/src/components/inspector-controls/fill.native.js +++ b/packages/block-editor/src/components/inspector-controls/fill.native.js @@ -35,7 +35,7 @@ export default function InspectorControlsFill( { ); group = __experimentalGroup; } - const isDisplayed = useDisplayBlockControls(); + const { isDisplayed } = useDisplayBlockControls(); const Fill = groups[ group ]?.Fill; if ( ! Fill ) { diff --git a/packages/block-editor/src/components/use-display-block-controls/index.js b/packages/block-editor/src/components/use-display-block-controls/index.js index 605556f295b96..ef27479593a73 100644 --- a/packages/block-editor/src/components/use-display-block-controls/index.js +++ b/packages/block-editor/src/components/use-display-block-controls/index.js @@ -2,6 +2,7 @@ * WordPress dependencies */ import { useSelect } from '@wordpress/data'; +import { store as blocksStore } from '@wordpress/blocks'; /** * Internal dependencies @@ -13,23 +14,28 @@ export default function useDisplayBlockControls() { const { isSelected, clientId, name } = useBlockEditContext(); return useSelect( ( select ) => { - if ( isSelected ) { - return true; - } - const { getBlockName, isFirstMultiSelectedBlock, getMultiSelectedBlockClientIds, + hasSelectedInnerBlock, } = select( blockEditorStore ); + const { hasBlockSupport } = select( blocksStore ); - if ( isFirstMultiSelectedBlock( clientId ) ) { - return getMultiSelectedBlockClientIds().every( - ( id ) => getBlockName( id ) === name - ); - } - - return false; + return { + isDisplayed: + isSelected || + ( isFirstMultiSelectedBlock( clientId ) && + getMultiSelectedBlockClientIds().every( + ( id ) => getBlockName( id ) === name + ) ), + isParentDisplayed: + hasBlockSupport( + getBlockName( clientId ), + '__experimentalExposeControlsToChildren', + false + ) && hasSelectedInnerBlock( clientId ), + }; }, [ clientId, isSelected, name ] ); diff --git a/packages/block-editor/src/components/use-display-block-controls/index.native.js b/packages/block-editor/src/components/use-display-block-controls/index.native.js index e8a198e1592e8..d865ed6d9d7b2 100644 --- a/packages/block-editor/src/components/use-display-block-controls/index.native.js +++ b/packages/block-editor/src/components/use-display-block-controls/index.native.js @@ -26,11 +26,7 @@ export default function useDisplayBlockControls() { false ); - if ( ! hideControls && isSelected ) { - return true; - } - - return false; + return { isDisplayed: ! hideControls && isSelected }; }, [ clientId, isSelected, name ] ); diff --git a/packages/block-editor/src/hooks/align.js b/packages/block-editor/src/hooks/align.js index 3b916d9577f1a..2019228cf2d3e 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, pure } from '@wordpress/compose'; +import { createHigherOrderComponent } from '@wordpress/compose'; import { addFilter } from '@wordpress/hooks'; import { getBlockSupport, @@ -109,7 +109,7 @@ export function addAttribute( settings ) { } function BlockEditAlignmentToolbarControlsPure( { - blockName, + name: blockName, align, setAttributes, } ) { @@ -152,45 +152,14 @@ function BlockEditAlignmentToolbarControlsPure( { ); } -// We don't want block controls to re-render when typing inside a block. `pure` -// will prevent re-renders unless props change, so only pass the needed props -// and not the whole attributes object. -const BlockEditAlignmentToolbarControls = pure( - BlockEditAlignmentToolbarControlsPure -); - -/** - * 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. - */ -export const withAlignmentControls = createHigherOrderComponent( - ( BlockEdit ) => ( props ) => { - const hasAlignmentSupport = hasBlockSupport( - props.name, - 'align', - false - ); - - return ( - <> - { hasAlignmentSupport && ( - - ) } - - - ); +export default { + shareWithChildBlocks: true, + edit: BlockEditAlignmentToolbarControlsPure, + attributeKeys: [ 'align' ], + hasSupport( name ) { + return hasBlockSupport( name, 'align', false ); }, - 'withAlignmentControls' -); +}; function BlockListBlockWithDataAlign( { block: BlockListBlock, props } ) { const { name, attributes } = props; @@ -273,11 +242,6 @@ addFilter( 'core/editor/align/with-data-align', withDataAlign ); -addFilter( - 'editor.BlockEdit', - 'core/editor/align/with-toolbar-controls', - withAlignmentControls -); addFilter( 'blocks.getSaveContent.extraProps', 'core/editor/align/addAssignedAlign', diff --git a/packages/block-editor/src/hooks/align.native.js b/packages/block-editor/src/hooks/align.native.js index 1bf375b654ad4..7a229e79870a8 100644 --- a/packages/block-editor/src/hooks/align.native.js +++ b/packages/block-editor/src/hooks/align.native.js @@ -8,6 +8,7 @@ import { WIDE_ALIGNMENTS } from '@wordpress/components'; const ALIGNMENTS = [ 'left', 'center', 'right' ]; export * from './align.js'; +export { default } from './align.js'; // Used to filter out blocks that don't support wide/full alignment on mobile addFilter( diff --git a/packages/block-editor/src/hooks/anchor.js b/packages/block-editor/src/hooks/anchor.js index 9902ed479531c..882820678aa87 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, pure } from '@wordpress/compose'; import { Platform } from '@wordpress/element'; /** @@ -52,7 +51,11 @@ export function addAttribute( settings ) { return settings; } -function BlockEditAnchorControlPure( { blockName, anchor, setAttributes } ) { +function BlockEditAnchorControlPure( { + name: blockName, + anchor, + setAttributes, +} ) { const blockEditingMode = useBlockEditingMode(); const isWeb = Platform.OS === 'web'; @@ -116,38 +119,13 @@ function BlockEditAnchorControlPure( { blockName, anchor, setAttributes } ) { ); } -// We don't want block controls to re-render when typing inside a block. `pure` -// will prevent re-renders unless props change, so only pass the needed props -// and not the whole attributes object. -const BlockEditAnchorControl = pure( BlockEditAnchorControlPure ); - -/** - * Override the default edit UI to include a new block inspector control for - * assigning the anchor ID, if block supports anchor. - * - * @param {Component} BlockEdit Original component. - * - * @return {Component} Wrapped component. - */ -export const withAnchorControls = createHigherOrderComponent( ( BlockEdit ) => { - return ( props ) => { - return ( - <> - - { props.isSelected && - hasBlockSupport( props.name, 'anchor' ) && ( - - ) } - - ); - }; -}, 'withAnchorControls' ); +export default { + edit: BlockEditAnchorControlPure, + attributeKeys: [ 'anchor' ], + hasSupport( name ) { + return hasBlockSupport( name, 'anchor' ); + }, +}; /** * Override props assigned to save component to inject anchor ID, if block @@ -169,11 +147,6 @@ export function addSaveProps( extraProps, blockType, attributes ) { } addFilter( 'blocks.registerBlockType', 'core/anchor/attribute', addAttribute ); -addFilter( - 'editor.BlockEdit', - 'core/editor/anchor/with-inspector-controls', - withAnchorControls -); addFilter( 'blocks.getSaveContent.extraProps', 'core/editor/anchor/save-props', diff --git a/packages/block-editor/src/hooks/block-hooks.js b/packages/block-editor/src/hooks/block-hooks.js index 59c0e3c85486f..a1640c72f4b2b 100644 --- a/packages/block-editor/src/hooks/block-hooks.js +++ b/packages/block-editor/src/hooks/block-hooks.js @@ -2,14 +2,12 @@ * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { addFilter } from '@wordpress/hooks'; import { Fragment, useMemo } from '@wordpress/element'; import { __experimentalHStack as HStack, PanelBody, ToggleControl, } from '@wordpress/components'; -import { createHigherOrderComponent, pure } from '@wordpress/compose'; import { createBlock, store as blocksStore } from '@wordpress/blocks'; import { useDispatch, useSelect } from '@wordpress/data'; @@ -21,7 +19,7 @@ import { store as blockEditorStore } from '../store'; const EMPTY_OBJECT = {}; -function BlockHooksControlPure( props ) { +function BlockHooksControlPure( { name, clientId } ) { const blockTypes = useSelect( ( select ) => select( blocksStore ).getBlockTypes(), [] @@ -30,10 +28,9 @@ function BlockHooksControlPure( props ) { const hookedBlocksForCurrentBlock = useMemo( () => blockTypes?.filter( - ( { blockHooks } ) => - blockHooks && props.blockName in blockHooks + ( { blockHooks } ) => blockHooks && name in blockHooks ), - [ blockTypes, props.blockName ] + [ blockTypes, name ] ); const { blockIndex, rootClientId, innerBlocksLength } = useSelect( @@ -42,13 +39,12 @@ function BlockHooksControlPure( props ) { select( blockEditorStore ); return { - blockIndex: getBlockIndex( props.clientId ), - innerBlocksLength: getBlock( props.clientId )?.innerBlocks - ?.length, - rootClientId: getBlockRootClientId( props.clientId ), + blockIndex: getBlockIndex( clientId ), + innerBlocksLength: getBlock( clientId )?.innerBlocks?.length, + rootClientId: getBlockRootClientId( clientId ), }; }, - [ props.clientId ] + [ clientId ] ); const hookedBlockClientIds = useSelect( @@ -65,8 +61,7 @@ function BlockHooksControlPure( props ) { return clientIds; } - const relativePosition = - block?.blockHooks?.[ props.blockName ]; + const relativePosition = block?.blockHooks?.[ name ]; let candidates; switch ( relativePosition ) { @@ -83,12 +78,12 @@ function BlockHooksControlPure( props ) { // Any of the current block's child blocks (with the right block type) qualifies // as a hooked first or last child block, as the block might've been automatically // inserted and then moved around a bit by the user. - candidates = getBlock( props.clientId ).innerBlocks; + candidates = getBlock( clientId ).innerBlocks; break; } const hookedBlock = candidates?.find( - ( { name } ) => name === block.name + ( candidate ) => name === candidate.name ); // If the block exists in the designated location, we consider it hooked @@ -118,12 +113,7 @@ function BlockHooksControlPure( props ) { return EMPTY_OBJECT; }, - [ - hookedBlocksForCurrentBlock, - props.blockName, - props.clientId, - rootClientId, - ] + [ hookedBlocksForCurrentBlock, name, clientId, rootClientId ] ); const { insertBlock, removeBlock } = useDispatch( blockEditorStore ); @@ -169,7 +159,7 @@ function BlockHooksControlPure( props ) { block, // TODO: It'd be great if insertBlock() would accept negative indices for insertion. relativePosition === 'first_child' ? 0 : innerBlocksLength, - props.clientId, // Insert as a child of the current block. + clientId, // Insert as a child of the current block. false ); break; @@ -207,9 +197,7 @@ function BlockHooksControlPure( props ) { if ( ! checked ) { // Create and insert block. const relativePosition = - block.blockHooks[ - props.blockName - ]; + block.blockHooks[ name ]; insertBlockIntoDesignatedLocation( createBlock( block.name ), relativePosition @@ -218,11 +206,12 @@ function BlockHooksControlPure( props ) { } // Remove block. - const clientId = + removeBlock( hookedBlockClientIds[ block.name - ]; - removeBlock( clientId, false ); + ], + false + ); } } /> ); @@ -235,32 +224,9 @@ function BlockHooksControlPure( props ) { ); } -// We don't want block controls to re-render when typing inside a block. `pure` -// will prevent re-renders unless props change, so only pass the needed props -// and not the whole attributes object. -const BlockHooksControl = pure( BlockHooksControlPure ); - -export const withBlockHooksControls = createHigherOrderComponent( - ( BlockEdit ) => { - return ( props ) => { - return ( - <> - - { props.isSelected && ( - - ) } - - ); - }; +export default { + edit: BlockHooksControlPure, + hasSupport() { + return true; }, - 'withBlockHooksControls' -); - -addFilter( - 'editor.BlockEdit', - 'core/editor/block-hooks/with-inspector-controls', - withBlockHooksControls -); +}; diff --git a/packages/block-editor/src/hooks/block-renaming.js b/packages/block-editor/src/hooks/block-renaming.js index 452be6e686dbf..26ada6ba73281 100644 --- a/packages/block-editor/src/hooks/block-renaming.js +++ b/packages/block-editor/src/hooks/block-renaming.js @@ -3,7 +3,6 @@ */ import { addFilter } from '@wordpress/hooks'; import { hasBlockSupport } from '@wordpress/blocks'; -import { createHigherOrderComponent, pure } from '@wordpress/compose'; import { __ } from '@wordpress/i18n'; import { TextControl } from '@wordpress/components'; @@ -11,7 +10,6 @@ import { TextControl } from '@wordpress/components'; * Internal dependencies */ import { InspectorControls } from '../components'; -import { useBlockRename } from '../components/block-rename'; /** * Filters registered block settings, adding an `__experimentalLabel` callback if one does not already exist. @@ -47,13 +45,7 @@ export function addLabelCallback( settings ) { return settings; } -function BlockRenameControlPure( { name, metadata, setAttributes } ) { - const { canRename } = useBlockRename( name ); - - if ( ! canRename ) { - return null; - } - +function BlockRenameControlPure( { metadata, setAttributes } ) { return ( ( props ) => { - const { name, attributes, setAttributes, isSelected } = props; - return ( - <> - { isSelected && ( - - ) } - - - ); +export default { + edit: BlockRenameControlPure, + attributeKeys: [ 'metadata' ], + hasSupport( name ) { + return hasBlockSupport( name, 'renaming', true ); }, - 'withToolbarControls' -); - -addFilter( - 'editor.BlockEdit', - 'core/block-rename-ui/with-block-rename-control', - withBlockRenameControl -); +}; addFilter( 'blocks.registerBlockType', diff --git a/packages/block-editor/src/hooks/custom-class-name.js b/packages/block-editor/src/hooks/custom-class-name.js index 8c0f58ddda682..331edd9ef214a 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, pure } from '@wordpress/compose'; /** * Internal dependencies @@ -64,46 +63,13 @@ function CustomClassNameControlsPure( { className, setAttributes } ) { ); } -// We don't want block controls to re-render when typing inside a block. `pure` -// will prevent re-renders unless props change, so only pass the needed props -// and not the whole attributes object. -const CustomClassNameControls = pure( CustomClassNameControlsPure ); - -/** - * Override the default edit UI to include a new block inspector control for - * assigning the custom class name, if block supports custom class name. - * The control is displayed within the Advanced panel in the block inspector. - * - * @param {Component} BlockEdit Original component. - * - * @return {Component} Wrapped component. - */ -export const withCustomClassNameControls = createHigherOrderComponent( - ( BlockEdit ) => { - return ( props ) => { - const hasCustomClassName = hasBlockSupport( - props.name, - 'customClassName', - true - ); - - return ( - <> - - { hasCustomClassName && props.isSelected && ( - - ) } - - ); - }; +export default { + edit: CustomClassNameControlsPure, + attributeKeys: [ 'className' ], + hasSupport( name ) { + return hasBlockSupport( name, 'customClassName', true ); }, - 'withCustomClassNameControls' -); +}; /** * Override props assigned to save component to inject the className, if block @@ -174,11 +140,6 @@ addFilter( 'core/editor/custom-class-name/attribute', addAttribute ); -addFilter( - 'editor.BlockEdit', - 'core/editor/custom-class-name/with-inspector-controls', - withCustomClassNameControls -); addFilter( 'blocks.getSaveContent.extraProps', 'core/editor/custom-class-name/save-props', diff --git a/packages/block-editor/src/hooks/custom-fields.js b/packages/block-editor/src/hooks/custom-fields.js index 19729d00ad61a..9b677933adc13 100644 --- a/packages/block-editor/src/hooks/custom-fields.js +++ b/packages/block-editor/src/hooks/custom-fields.js @@ -5,7 +5,6 @@ import { addFilter } from '@wordpress/hooks'; import { PanelBody, TextControl } from '@wordpress/components'; import { __, sprintf } from '@wordpress/i18n'; import { hasBlockSupport } from '@wordpress/blocks'; -import { createHigherOrderComponent, pure } from '@wordpress/compose'; /** * Internal dependencies @@ -91,50 +90,18 @@ function CustomFieldsControlPure( { name, connections, setAttributes } ) { ); } -// We don't want block controls to re-render when typing inside a block. `pure` -// will prevent re-renders unless props change, so only pass the needed props -// and not the whole attributes object. -const CustomFieldsControl = pure( CustomFieldsControlPure ); - -/** - * Override the default edit UI to include a new block inspector control for - * assigning a connection to blocks that has support for connections. - * Currently, only the `core/paragraph` block is supported and there is only a relation - * between paragraph content and a custom field. - * - * @param {Component} BlockEdit Original component. - * - * @return {Component} Wrapped component. - */ -const withCustomFieldsControls = createHigherOrderComponent( ( BlockEdit ) => { - return ( props ) => { - const hasCustomFieldsSupport = hasBlockSupport( - props.name, - '__experimentalConnections', - false - ); - - // Check if the current block is a paragraph or image block. - // Currently, only these two blocks are supported. - if ( ! [ 'core/paragraph', 'core/image' ].includes( props.name ) ) { - return ; - } - +export default { + edit: CustomFieldsControlPure, + attributeKeys: [ 'connections' ], + hasSupport( name ) { return ( - <> - - { hasCustomFieldsSupport && props.isSelected && ( - - ) } - + hasBlockSupport( name, '__experimentalConnections', false ) && + // Check if the current block is a paragraph or image block. + // Currently, only these two blocks are supported. + [ 'core/paragraph', 'core/image' ].includes( name ) ); - }; -}, 'withCustomFieldsControls' ); + }, +}; if ( window.__experimentalConnections || @@ -146,10 +113,3 @@ if ( addAttribute ); } -if ( window.__experimentalConnections ) { - addFilter( - 'editor.BlockEdit', - 'core/editor/connections/with-inspector-controls', - withCustomFieldsControls - ); -} diff --git a/packages/block-editor/src/hooks/duotone.js b/packages/block-editor/src/hooks/duotone.js index 6e18b44cef163..c0b76d12cb370 100644 --- a/packages/block-editor/src/hooks/duotone.js +++ b/packages/block-editor/src/hooks/duotone.js @@ -13,11 +13,7 @@ import { getBlockType, hasBlockSupport, } from '@wordpress/blocks'; -import { - createHigherOrderComponent, - useInstanceId, - pure, -} from '@wordpress/compose'; +import { createHigherOrderComponent, useInstanceId } from '@wordpress/compose'; import { addFilter } from '@wordpress/hooks'; import { useMemo, useEffect } from '@wordpress/element'; @@ -179,10 +175,14 @@ function DuotonePanelPure( { style, setAttributes, name } ) { ); } -// We don't want block controls to re-render when typing inside a block. `pure` -// will prevent re-renders unless props change, so only pass the needed props -// and not the whole attributes object. -const DuotonePanel = pure( DuotonePanelPure ); +export default { + shareWithChildBlocks: true, + edit: DuotonePanelPure, + attributeKeys: [ 'style' ], + hasSupport( name ) { + return hasBlockSupport( name, 'filter.duotone' ); + }, +}; /** * Filters registered block settings, extending attributes to include @@ -212,44 +212,6 @@ function addDuotoneAttributes( settings ) { return 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. - */ -const withDuotoneControls = createHigherOrderComponent( - ( BlockEdit ) => ( props ) => { - // Previous `color.__experimentalDuotone` support flag is migrated via - // block_type_metadata_settings filter in `lib/block-supports/duotone.php`. - const hasDuotoneSupport = hasBlockSupport( - props.name, - 'filter.duotone' - ); - - // 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 && ( - - ) } - - - ); - }, - 'withDuotoneControls' -); - function DuotoneStyles( { clientId, id: filterId, @@ -438,11 +400,6 @@ addFilter( 'core/editor/duotone/add-attributes', addDuotoneAttributes ); -addFilter( - 'editor.BlockEdit', - 'core/editor/duotone/with-editor-controls', - withDuotoneControls -); addFilter( 'editor.BlockListBlock', 'core/editor/duotone/with-styles', diff --git a/packages/block-editor/src/hooks/index.js b/packages/block-editor/src/hooks/index.js index c088216c0645c..6ae589dd672bf 100644 --- a/packages/block-editor/src/hooks/index.js +++ b/packages/block-editor/src/hooks/index.js @@ -1,27 +1,43 @@ /** * Internal dependencies */ +import { createBlockEditFilter } from './utils'; import './compat'; -import './align'; +import align from './align'; import './lock'; -import './anchor'; +import anchor from './anchor'; import './aria-label'; -import './custom-class-name'; +import customClassName from './custom-class-name'; import './generated-class-name'; -import './style'; +import style from './style'; import './settings'; import './color'; -import './duotone'; +import duotone from './duotone'; import './font-family'; import './font-size'; import './border'; -import './position'; -import './layout'; +import position from './position'; +import layout from './layout'; import './content-lock-ui'; import './metadata'; -import './custom-fields'; -import './block-hooks'; -import './block-renaming'; +import customFields from './custom-fields'; +import blockHooks from './block-hooks'; +import blockRenaming from './block-renaming'; + +createBlockEditFilter( + [ + align, + anchor, + customClassName, + style, + duotone, + position, + layout, + window.__experimentalConnections ? customFields : null, + blockHooks, + blockRenaming, + ].filter( Boolean ) +); export { useCustomSides } from './dimensions'; export { useLayoutClasses, useLayoutStyles } from './layout'; diff --git a/packages/block-editor/src/hooks/index.native.js b/packages/block-editor/src/hooks/index.native.js index 42bda25bfe1cc..3f1a4473c1389 100644 --- a/packages/block-editor/src/hooks/index.native.js +++ b/packages/block-editor/src/hooks/index.native.js @@ -1,16 +1,19 @@ /** * Internal dependencies */ +import { createBlockEditFilter } from './utils'; import './compat'; -import './align'; -import './anchor'; +import align from './align'; +import anchor from './anchor'; import './custom-class-name'; import './generated-class-name'; -import './style'; +import style from './style'; import './color'; import './font-size'; import './layout'; +createBlockEditFilter( [ align, anchor, style ] ); + export { getBorderClassesAndStyles, useBorderProps } from './use-border-props'; export { getColorClassesAndStyles, useColorProps } from './use-color-props'; export { getSpacingClassesAndStyles } from './use-spacing-props'; diff --git a/packages/block-editor/src/hooks/layout.js b/packages/block-editor/src/hooks/layout.js index 3ea5c56da8e77..46239e1de0703 100644 --- a/packages/block-editor/src/hooks/layout.js +++ b/packages/block-editor/src/hooks/layout.js @@ -6,11 +6,7 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { - createHigherOrderComponent, - pure, - useInstanceId, -} from '@wordpress/compose'; +import { createHigherOrderComponent, useInstanceId } from '@wordpress/compose'; import { addFilter } from '@wordpress/hooks'; import { getBlockSupport, hasBlockSupport } from '@wordpress/blocks'; import { useSelect } from '@wordpress/data'; @@ -290,10 +286,14 @@ function LayoutPanelPure( { layout, setAttributes, name: blockName } ) { ); } -// We don't want block controls to re-render when typing inside a block. `pure` -// will prevent re-renders unless props change, so only pass the needed props -// and not the whole attributes object. -const LayoutPanel = pure( LayoutPanelPure ); +export default { + shareWithChildBlocks: true, + edit: LayoutPanelPure, + attributeKeys: [ 'layout' ], + hasSupport( name ) { + return hasLayoutBlockSupport( name ); + }, +}; function LayoutTypeSwitcher( { type, onChange } ) { return ( @@ -336,33 +336,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 withLayoutControls = createHigherOrderComponent( - ( BlockEdit ) => ( props ) => { - const supportLayout = hasLayoutBlockSupport( props.name ); - - return [ - supportLayout && ( - - ), - , - ]; - }, - 'withLayoutControls' -); - function BlockWithLayoutStyles( { block: BlockListBlock, props } ) { const { name, attributes } = props; const id = useInstanceId( BlockListBlock ); @@ -516,8 +489,3 @@ addFilter( 'core/editor/layout/with-child-layout-styles', withChildLayoutStyles ); -addFilter( - 'editor.BlockEdit', - 'core/editor/layout/with-inspector-controls', - withLayoutControls -); diff --git a/packages/block-editor/src/hooks/position.js b/packages/block-editor/src/hooks/position.js index 32d4f6582969e..cdeb90822f0ac 100644 --- a/packages/block-editor/src/hooks/position.js +++ b/packages/block-editor/src/hooks/position.js @@ -12,11 +12,7 @@ import { BaseControl, privateApis as componentsPrivateApis, } from '@wordpress/components'; -import { - createHigherOrderComponent, - pure, - useInstanceId, -} from '@wordpress/compose'; +import { createHigherOrderComponent, useInstanceId } from '@wordpress/compose'; import { useSelect } from '@wordpress/data'; import { useMemo, Platform } from '@wordpress/element'; import { addFilter } from '@wordpress/hooks'; @@ -318,44 +314,19 @@ export function PositionPanelPure( { } ); } -// We don't want block controls to re-render when typing inside a block. `pure` -// will prevent re-renders unless props change, so only pass the needed props -// and not the whole attributes object. -const PositionPanel = pure( PositionPanelPure ); - -/** - * Override the default edit UI to include position controls. - * - * @param {Function} BlockEdit Original component. - * - * @return {Function} Wrapped component. - */ -export const withPositionControls = createHigherOrderComponent( - ( BlockEdit ) => ( props ) => { - const { name: blockName } = props; - const positionSupport = hasBlockSupport( - blockName, - POSITION_SUPPORT_KEY - ); +export default { + edit: function Edit( props ) { const isPositionDisabled = useIsPositionDisabled( props ); - const showPositionControls = positionSupport && ! isPositionDisabled; - - return [ - showPositionControls && ( - - ), - , - ]; + if ( isPositionDisabled ) { + return null; + } + return ; }, - 'withPositionControls' -); + attributeKeys: [ 'style' ], + hasSupport( name ) { + return hasBlockSupport( name, POSITION_SUPPORT_KEY ); + }, +}; /** * Override the default block element to add the position styles. @@ -411,8 +382,3 @@ addFilter( 'core/editor/position/with-position-styles', withPositionStyles ); -addFilter( - 'editor.BlockEdit', - 'core/editor/position/with-inspector-controls', - withPositionControls -); diff --git a/packages/block-editor/src/hooks/style.js b/packages/block-editor/src/hooks/style.js index 1acb2cda3ac01..4036342316887 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, useStyleOverride, @@ -356,12 +355,16 @@ function BlockStyleControls( { __unstableParentLayout, } ) { const settings = useBlockSettings( name, __unstableParentLayout ); + const blockEditingMode = useBlockEditingMode(); const passedProps = { clientId, name, setAttributes, settings, }; + if ( blockEditingMode !== 'default' ) { + return null; + } return ( <> @@ -373,34 +376,10 @@ function BlockStyleControls( { ); } -/** - * 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. - */ -export const withBlockStyleControls = createHigherOrderComponent( - ( BlockEdit ) => ( props ) => { - if ( ! hasStyleSupport( props.name ) ) { - return ; - } - - const shouldDisplayControls = useDisplayBlockControls(); - const blockEditingMode = useBlockEditingMode(); - - return ( - <> - { shouldDisplayControls && blockEditingMode === 'default' && ( - - ) } - - - ); - }, - 'withBlockStyleControls' -); +export default { + edit: BlockStyleControls, + hasSupport: hasStyleSupport, +}; // Defines which element types are supported, including their hover styles or // any other elements that have been included under a single element type @@ -542,12 +521,6 @@ addFilter( addEditProps ); -addFilter( - 'editor.BlockEdit', - 'core/style/with-block-controls', - withBlockStyleControls -); - addFilter( 'editor.BlockListBlock', 'core/editor/with-elements-styles', diff --git a/packages/block-editor/src/hooks/test/align.js b/packages/block-editor/src/hooks/test/align.js index b928e6eafc8b2..c695399e993b0 100644 --- a/packages/block-editor/src/hooks/test/align.js +++ b/packages/block-editor/src/hooks/test/align.js @@ -12,20 +12,12 @@ import { registerBlockType, unregisterBlockType, } from '@wordpress/blocks'; -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, - withAlignmentControls, - withDataAlign, - addAssignedAlign, -} from '../align'; +import { getValidAlignments, withDataAlign, addAssignedAlign } from '../align'; const noop = () => {}; @@ -157,68 +149,6 @@ describe( 'align', () => { } ); } ); - describe( 'withAlignControls', () => { - const componentProps = { - name: 'core/foo', - attributes: {}, - isSelected: true, - }; - - it( 'should do nothing if no valid alignments', () => { - registerBlockType( 'core/foo', blockSettings ); - - const EnhancedComponent = withAlignmentControls( - ( { wrapperProps } ) =>
- ); - - render( - - - - - - - ); - - expect( - screen.queryByRole( 'button', { - name: 'Align', - expanded: false, - } ) - ).not.toBeInTheDocument(); - } ); - - it( 'should render toolbar controls if valid alignments', () => { - registerBlockType( 'core/foo', { - ...blockSettings, - supports: { - align: true, - alignWide: false, - }, - } ); - - const EnhancedComponent = withAlignmentControls( - ( { wrapperProps } ) =>
- ); - - render( - - - - - - - ); - - expect( - screen.getAllByRole( 'button', { - name: 'Align', - expanded: false, - } ) - ).toHaveLength( 2 ); - } ); - } ); - describe( 'withDataAlign', () => { it( 'should render with wrapper props', () => { registerBlockType( 'core/foo', { diff --git a/packages/block-editor/src/hooks/utils.js b/packages/block-editor/src/hooks/utils.js index 5985b821d00a8..98638ae5dabf5 100644 --- a/packages/block-editor/src/hooks/utils.js +++ b/packages/block-editor/src/hooks/utils.js @@ -4,10 +4,13 @@ import { getBlockSupport } from '@wordpress/blocks'; import { useMemo, useEffect, useId } from '@wordpress/element'; import { useDispatch } from '@wordpress/data'; +import { createHigherOrderComponent, pure } from '@wordpress/compose'; +import { addFilter } from '@wordpress/hooks'; /** * Internal dependencies */ +import useDisplayBlockControls from '../components/use-display-block-controls'; import { useSettings } from '../components'; import { useSettingsForBlockElement } from '../components/global-styles/hooks'; import { getValueFromObjectPath, setImmutably } from '../utils/object'; @@ -362,3 +365,68 @@ export function useBlockSettings( name, parentLayout ) { return useSettingsForBlockElement( rawSettings, name ); } + +export function createBlockEditFilter( features ) { + // We don't want block controls to re-render when typing inside a block. + // `pure` will prevent re-renders unless props change, so only pass the + // needed props and not the whole attributes object. + features = features.map( ( settings ) => { + return { ...settings, Edit: pure( settings.edit ) }; + } ); + const withBlockEditHooks = createHigherOrderComponent( + ( OriginalBlockEdit ) => ( props ) => { + const { isDisplayed, isParentDisplayed } = + useDisplayBlockControls(); + // CAUTION: code added before this line will be executed for all + // blocks, not just those that support the feature! Code added + // above this line should be carefully evaluated for its impact on + // performance. + return [ + ...features.map( ( feature, i ) => { + const { + Edit, + hasSupport, + attributeKeys = [], + shareWithChildBlocks, + } = feature; + const shouldDisplayControls = + isDisplayed || + ( isParentDisplayed && shareWithChildBlocks ); + + if ( + ! shouldDisplayControls || + ! hasSupport( props.name ) + ) { + return null; + } + + const neededProps = {}; + for ( const key of attributeKeys ) { + if ( props.attributes[ key ] ) { + neededProps[ key ] = props.attributes[ key ]; + } + } + return ( + + ); + } ), + , + ]; + }, + 'withBlockEditHooks' + ); + addFilter( 'editor.BlockEdit', 'core/editor/hooks', withBlockEditHooks ); +}