diff --git a/packages/block-editor/src/components/block-bindings-toolbar-indicator/index.js b/packages/block-editor/src/components/block-bindings-toolbar-indicator/index.js index 1c9b0fd8a7cc7..d6450b1839dc4 100644 --- a/packages/block-editor/src/components/block-bindings-toolbar-indicator/index.js +++ b/packages/block-editor/src/components/block-bindings-toolbar-indicator/index.js @@ -1,19 +1,135 @@ /** * WordPress dependencies */ -import { ToolbarItem, ToolbarGroup, Icon } from '@wordpress/components'; -import { connection } from '@wordpress/icons'; -import { _x } from '@wordpress/i18n'; +import { useId } from '@wordpress/element'; +import { __, sprintf, _x } from '@wordpress/i18n'; +import { DropdownMenu, ToolbarGroup, ToolbarItem } from '@wordpress/components'; +import { store as blocksStore } from '@wordpress/blocks'; +import { useSelect } from '@wordpress/data'; +import { copy } from '@wordpress/icons'; + +/** + * Internal dependencies + */ +import { store as blockEditorStore } from '../../store'; +import BlockIcon from '../block-icon'; +import useBlockDisplayTitle from '../block-title/use-block-display-title'; + +export default function BlockBindingsToolbarIndicator( { clientIds } ) { + const isSingleBlockSelected = clientIds.length === 1; + const { icon, firstBlockName, isConnectedToPatternOverrides } = useSelect( + ( select ) => { + const { + getBlockAttributes, + getBlockNamesByClientId, + getBlocksByClientId, + } = 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, + isConnectedToPatternOverrides: getBlocksByClientId( + clientIds + ).some( ( block ) => + Object.values( block?.attributes.metadata?.bindings ).some( + ( binding ) => + binding.source === 'core/pattern-overrides' + ) + ), + }; + }, + [ clientIds, isSingleBlockSelected ] + ); + const firstBlockTitle = useBlockDisplayTitle( { + clientId: clientIds[ 0 ], + maximumLength: 35, + } ); + + let blockDescription = isSingleBlockSelected + ? _x( + 'This block is connected.', + 'block toolbar button label and description' + ) + : _x( + 'These blocks are connected.', + 'block toolbar button label and description' + ); + if ( isConnectedToPatternOverrides && firstBlockName ) { + blockDescription = isSingleBlockSelected + ? sprintf( + /* translators: %1s: The block type's name; %2s: The block's user-provided name. */ + __( 'This %1$s is using the "%2$s" override.' ), + firstBlockTitle, + firstBlockName + ) + : __( 'These blocks are using the multiple overrides.' ); + } + const descriptionId = useId(); -export default function BlockBindingsToolbarIndicator() { return ( - - + + { ( toggleProps ) => ( + + + { isSingleBlockSelected && + !! firstBlockName && ( + + { firstBlockName } + + ) } + + } + toggleProps={ { + describedBy: blockDescription, + ...toggleProps, + } } + menuProps={ { + orientation: 'both', + 'aria-describedby': descriptionId, + } } + > + { () => ( + + { blockDescription } + + ) } + + ) } ); diff --git a/packages/block-editor/src/components/block-bindings-toolbar-indicator/style.scss b/packages/block-editor/src/components/block-bindings-toolbar-indicator/style.scss index 4565473ec95eb..bbe1ff4caabdc 100644 --- a/packages/block-editor/src/components/block-bindings-toolbar-indicator/style.scss +++ b/packages/block-editor/src/components/block-bindings-toolbar-indicator/style.scss @@ -1,11 +1,9 @@ -.block-editor-block-bindings-toolbar-indicator { - display: inline-flex; - align-items: center; - justify-content: center; - padding: 6px; - svg { - fill: var(--wp-block-synced-color); - } +.block-editor-block-bindings-toolbar-indicator__popover .components-popover__content { + min-width: 300px; +} + +.block-editor-block-bindings-toolbar-indicator .block-editor-block-bindings-toolbar-indicator-icon.has-colors svg { + fill: var(--wp-block-synced-color); } .editor-collapsible-block-toolbar .block-editor-block-bindings-toolbar-indicator { diff --git a/packages/block-editor/src/components/block-toolbar/index.js b/packages/block-editor/src/components/block-toolbar/index.js index c3570c4a007f1..0e341d3216395 100644 --- a/packages/block-editor/src/components/block-toolbar/index.js +++ b/packages/block-editor/src/components/block-toolbar/index.js @@ -168,7 +168,7 @@ export function PrivateBlockToolbar( { isLargeViewport && isDefaultEditingMode && } { isUsingBindings && canBindBlock( blockName ) && ( - + ) } { ( shouldShowVisualToolbar || isMultiToolbar ) && ( isDefaultEditingMode || isSynced ) && (