diff --git a/packages/block-editor/src/components/block-toolbar/index.js b/packages/block-editor/src/components/block-toolbar/index.js index cffb46413c5bbb..6c6acd662ed962 100644 --- a/packages/block-editor/src/components/block-toolbar/index.js +++ b/packages/block-editor/src/components/block-toolbar/index.js @@ -35,9 +35,8 @@ import { store as blockEditorStore } from '../../store'; import __unstableBlockNameContext from './block-name-context'; import NavigableToolbar from '../navigable-toolbar'; import Shuffle from './shuffle'; -import PatternOverridesToolbarIndicator from '../pattern-overrides-toolbar-indicator'; import { useHasBlockToolbar } from './use-has-block-toolbar'; -import { canBindBlock } from '../../hooks/use-bindings-attributes'; + /** * Renders the block toolbar. * @@ -62,18 +61,15 @@ export function PrivateBlockToolbar( { blockClientIds, isDefaultEditingMode, blockType, - blockName, toolbarKey, shouldShowVisualToolbar, showParentSelector, isUsingBindings, - hasParentPattern, } = useSelect( ( select ) => { const { getBlockName, getBlockMode, getBlockParents, - getBlockParentsByBlockName, getSelectedBlockClientIds, isBlockValid, getBlockRootClientId, @@ -96,18 +92,14 @@ export function PrivateBlockToolbar( { const isVisual = selectedBlockClientIds.every( ( id ) => getBlockMode( id ) === 'visual' ); - const bindings = getBlockAttributes( selectedBlockClientId )?.metadata - ?.bindings; - const parentPatternClientId = getBlockParentsByBlockName( - selectedBlockClientId, - 'core/block', - true - )[ 0 ]; + const _isUsingBindings = selectedBlockClientIds.every( + ( clientId ) => + !! getBlockAttributes( clientId )?.metadata?.bindings + ); return { blockClientId: selectedBlockClientId, blockClientIds: selectedBlockClientIds, isDefaultEditingMode: _isDefaultEditingMode, - blockName: _blockName, blockType: selectedBlockClientId && getBlockType( _blockName ), shouldShowVisualToolbar: isValid && isVisual, rootClientId: blockRootClientId, @@ -122,8 +114,7 @@ export function PrivateBlockToolbar( { ) && selectedBlockClientIds.length === 1 && _isDefaultEditingMode, - isUsingBindings: !! bindings, - hasParentPattern: !! parentPatternClientId, + isUsingBindings: _isUsingBindings, }; }, [] ); @@ -176,13 +167,6 @@ export function PrivateBlockToolbar( { { ! isMultiToolbar && isLargeViewport && isDefaultEditingMode && } - { isUsingBindings && - hasParentPattern && - canBindBlock( blockName ) && ( - - ) } { ( shouldShowVisualToolbar || isMultiToolbar ) && ( isDefaultEditingMode || isSynced ) && (
{ - const { getBlockAttributes, getBlockNamesByClientId } = - select( blockEditorStore ); - const { getBlockType, getActiveBlockVariation } = - select( blocksStore ); - const blockTypeNames = getBlockNamesByClientId( clientIds ); - const _firstBlockTypeName = blockTypeNames[ 0 ]; - const firstBlockType = getBlockType( _firstBlockTypeName ); - let _icon; - if ( isSingleBlockSelected ) { - const match = getActiveBlockVariation( - _firstBlockTypeName, - getBlockAttributes( clientIds[ 0 ] ) - ); - // Take into account active block variations. - _icon = match?.icon || firstBlockType.icon; - } else { - const isSelectionOfSameType = - new Set( blockTypeNames ).size === 1; - // When selection consists of blocks of multiple types, display an - // appropriate icon to communicate the non-uniformity. - _icon = isSelectionOfSameType ? firstBlockType.icon : copy; - } - - return { - icon: _icon, - firstBlockName: getBlockAttributes( clientIds[ 0 ] ).metadata - .name, - }; - }, - [ clientIds, isSingleBlockSelected ] - ); - const firstBlockTitle = useBlockDisplayTitle( { - clientId: clientIds[ 0 ], - maximumLength: 35, - } ); - - const blockDescription = isSingleBlockSelected - ? sprintf( - /* translators: %1s: The block type's name; %2s: The block's user-provided name (the same as the override name). */ - __( 'This %1$s is editable using the "%2$s" override.' ), - firstBlockTitle.toLowerCase(), - firstBlockName - ) - : __( 'These blocks are editable using overrides.' ); - - const descriptionId = useId(); - - return ( - - - { ( toggleProps ) => ( - - - - } - toggleProps={ { - describedBy: blockDescription, - ...toggleProps, - } } - menuProps={ { - orientation: 'both', - 'aria-describedby': descriptionId, - } } - > - { () => ( - - { blockDescription } - - ) } - - ) } - - - ); -} diff --git a/packages/block-editor/src/components/pattern-overrides-toolbar-indicator/style.scss b/packages/block-editor/src/components/pattern-overrides-toolbar-indicator/style.scss deleted file mode 100644 index 90b2c1cdd79a5e..00000000000000 --- a/packages/block-editor/src/components/pattern-overrides-toolbar-indicator/style.scss +++ /dev/null @@ -1,12 +0,0 @@ -.block-editor-pattern-overrides-toolbar-indicator__popover .components-popover__content { - min-width: 260px; - padding: $grid-unit-20; -} - -.block-editor-pattern-overrides-toolbar-indicator .block-editor-pattern-overrides-toolbar-indicator-icon.has-colors svg { - fill: var(--wp-block-synced-color); -} - -.editor-collapsible-block-toolbar .block-editor-pattern-overrides-toolbar-indicator { - height: 32px; -} diff --git a/packages/block-editor/src/private-apis.js b/packages/block-editor/src/private-apis.js index 848a3ee49251bd..e6f3fc4cc39d6a 100644 --- a/packages/block-editor/src/private-apis.js +++ b/packages/block-editor/src/private-apis.js @@ -43,6 +43,7 @@ import { PrivateBlockPopover } from './components/block-popover'; import { PrivateInserterLibrary } from './components/inserter/library'; import { PrivatePublishDateTimePicker } from './components/publish-date-time-picker'; import useSpacingSizes from './components/spacing-sizes-control/hooks/use-spacing-sizes'; +import useBlockDisplayTitle from './components/block-title/use-block-display-title'; /** * Private @wordpress/block-editor APIs. @@ -86,4 +87,5 @@ lock( privateApis, { PrivateBlockPopover, PrivatePublishDateTimePicker, useSpacingSizes, + useBlockDisplayTitle, } ); diff --git a/packages/block-editor/src/style.scss b/packages/block-editor/src/style.scss index d22ea9b3d0a283..cf4683b02c707d 100644 --- a/packages/block-editor/src/style.scss +++ b/packages/block-editor/src/style.scss @@ -1,6 +1,5 @@ @import "./autocompleters/style.scss"; @import "./components/block-alignment-control/style.scss"; -@import "./components/pattern-overrides-toolbar-indicator/style.scss"; @import "./components/block-canvas/style.scss"; @import "./components/block-icon/style.scss"; @import "./components/block-inspector/style.scss"; diff --git a/packages/editor/src/hooks/pattern-overrides.js b/packages/editor/src/hooks/pattern-overrides.js index cd5f07aa8f48d1..485cc3725d8d71 100644 --- a/packages/editor/src/hooks/pattern-overrides.js +++ b/packages/editor/src/hooks/pattern-overrides.js @@ -17,6 +17,7 @@ import { unlock } from '../lock-unlock'; const { PatternOverridesControls, ResetOverridesControl, + PatternOverridesBlockControls, PATTERN_TYPES, PARTIAL_SYNCING_SUPPORTED_BLOCKS, PATTERN_SYNC_TYPES, @@ -43,6 +44,7 @@ const withPatternOverrideControls = createHigherOrderComponent( { props.isSelected && isSupportedBlock && ( ) } + { isSupportedBlock && } ); } diff --git a/packages/patterns/src/components/pattern-overrides-block-controls.js b/packages/patterns/src/components/pattern-overrides-block-controls.js new file mode 100644 index 00000000000000..ae8ef5e1bb7da9 --- /dev/null +++ b/packages/patterns/src/components/pattern-overrides-block-controls.js @@ -0,0 +1,155 @@ +/** + * WordPress dependencies + */ +import { useId } from '@wordpress/element'; +import { __, sprintf } from '@wordpress/i18n'; +import { + DropdownMenu, + ToolbarItem, + __experimentalText as Text, +} from '@wordpress/components'; +import { store as blocksStore } from '@wordpress/blocks'; +import { useSelect } from '@wordpress/data'; +import { copy } from '@wordpress/icons'; +import { + store as blockEditorStore, + BlockIcon, + privateApis as blockEditorPrivateApis, + BlockControls, +} from '@wordpress/block-editor'; + +/** + * Internal dependencies + */ +import { unlock } from '../lock-unlock'; +import { PATTERN_OVERRIDES_BINDING_SOURCE } from '../constants'; + +const { useBlockDisplayTitle } = unlock( blockEditorPrivateApis ); + +function PatternOverridesToolbarIndicator( { clientIds } ) { + const isSingleBlockSelected = clientIds.length === 1; + const { icon, firstBlockName } = useSelect( + ( select ) => { + const { getBlockAttributes, getBlockNamesByClientId } = + select( blockEditorStore ); + const { getBlockType, getActiveBlockVariation } = + select( blocksStore ); + const blockTypeNames = getBlockNamesByClientId( clientIds ); + const _firstBlockTypeName = blockTypeNames[ 0 ]; + const firstBlockType = getBlockType( _firstBlockTypeName ); + let _icon; + if ( isSingleBlockSelected ) { + const match = getActiveBlockVariation( + _firstBlockTypeName, + getBlockAttributes( clientIds[ 0 ] ) + ); + // Take into account active block variations. + _icon = match?.icon || firstBlockType.icon; + } else { + const isSelectionOfSameType = + new Set( blockTypeNames ).size === 1; + // When selection consists of blocks of multiple types, display an + // appropriate icon to communicate the non-uniformity. + _icon = isSelectionOfSameType ? firstBlockType.icon : copy; + } + + return { + icon: _icon, + firstBlockName: getBlockAttributes( clientIds[ 0 ] ).metadata + .name, + }; + }, + [ clientIds, isSingleBlockSelected ] + ); + const firstBlockTitle = useBlockDisplayTitle( { + clientId: clientIds[ 0 ], + maximumLength: 35, + } ); + + const blockDescription = isSingleBlockSelected + ? sprintf( + /* translators: %1s: The block type's name; %2s: The block's user-provided name (the same as the override name). */ + __( 'This %1$s is editable using the "%2$s" override.' ), + firstBlockTitle.toLowerCase(), + firstBlockName + ) + : __( 'These blocks are editable using overrides.' ); + + const descriptionId = useId(); + + return ( + + { ( toggleProps ) => ( + + + + } + toggleProps={ { + describedBy: blockDescription, + ...toggleProps, + } } + menuProps={ { + orientation: 'both', + 'aria-describedby': descriptionId, + } } + > + { () => ( + { blockDescription } + ) } + + ) } + + ); +} + +export default function PatternOverridesBlockControls() { + const { clientIds, hasPatternOverrides, hasParentPattern } = useSelect( + ( select ) => { + const { + getBlockAttributes, + getSelectedBlockClientIds, + getBlockParentsByBlockName, + } = select( blockEditorStore ); + const selectedClientIds = getSelectedBlockClientIds(); + const _hasPatternOverrides = selectedClientIds.every( + ( clientId ) => + Object.values( + getBlockAttributes( clientId )?.metadata?.bindings ?? {} + ).some( + ( binding ) => + binding?.source === PATTERN_OVERRIDES_BINDING_SOURCE + ) + ); + const _hasParentPattern = selectedClientIds.every( + ( clientId ) => + getBlockParentsByBlockName( clientId, 'core/block', true ) + .length > 0 + ); + return { + clientIds: selectedClientIds, + hasPatternOverrides: _hasPatternOverrides, + hasParentPattern: _hasParentPattern, + }; + }, + [] + ); + + return hasPatternOverrides && hasParentPattern ? ( + + + + ) : null; +} diff --git a/packages/patterns/src/components/style.scss b/packages/patterns/src/components/style.scss index 86af3df7ff3b90..30fe0300503c48 100644 --- a/packages/patterns/src/components/style.scss +++ b/packages/patterns/src/components/style.scss @@ -44,3 +44,16 @@ justify-content: center; } + +.patterns-pattern-overrides-toolbar-indicator__popover .components-popover__content { + min-width: 260px; + padding: $grid-unit-20; +} + +.patterns-pattern-overrides-toolbar-indicator .patterns-pattern-overrides-toolbar-indicator-icon.has-colors svg { + fill: var(--wp-block-synced-color); +} + +.editor-collapsible-block-toolbar .patterns-pattern-overrides-toolbar-indicator { + height: 32px; +} diff --git a/packages/patterns/src/private-apis.js b/packages/patterns/src/private-apis.js index 0553378cb56043..8893b3c57d7360 100644 --- a/packages/patterns/src/private-apis.js +++ b/packages/patterns/src/private-apis.js @@ -17,6 +17,7 @@ import PatternsMenuItems from './components'; import RenamePatternCategoryModal from './components/rename-pattern-category-modal'; import PatternOverridesControls from './components/pattern-overrides-controls'; import ResetOverridesControl from './components/reset-overrides-control'; +import PatternOverridesBlockControls from './components/pattern-overrides-block-controls'; import { useAddPatternCategory } from './private-hooks'; import { PATTERN_TYPES, @@ -41,6 +42,7 @@ lock( privateApis, { RenamePatternCategoryModal, PatternOverridesControls, ResetOverridesControl, + PatternOverridesBlockControls, useAddPatternCategory, PATTERN_TYPES, PATTERN_DEFAULT_CATEGORY,