diff --git a/packages/block-editor/src/components/block-tools/block-selection-button.js b/packages/block-editor/src/components/block-tools/block-selection-button.js index 9c6c22181ef2ac..358f88cc2e7291 100644 --- a/packages/block-editor/src/components/block-tools/block-selection-button.js +++ b/packages/block-editor/src/components/block-tools/block-selection-button.js @@ -8,8 +8,8 @@ import clsx from 'clsx'; */ import { dragHandle } from '@wordpress/icons'; import { Button, Flex, FlexItem } from '@wordpress/components'; -import { useSelect, useDispatch } from '@wordpress/data'; -import { forwardRef, useEffect } from '@wordpress/element'; +import { useSelect, useDispatch, useRegistry } from '@wordpress/data'; +import { forwardRef, useEffect, useContext } from '@wordpress/element'; import { BACKSPACE, DELETE, @@ -38,6 +38,9 @@ import BlockIcon from '../block-icon'; import { store as blockEditorStore } from '../../store'; import BlockDraggable from '../block-draggable'; import { useBlockElement } from '../block-list/use-block-props/use-block-refs'; +import { unlock } from '../../lock-unlock'; +import { getBindingsValues } from '../../hooks/use-bindings-attributes'; +import BlockContext from '../block-context'; /** * Block selection button component, displaying the label of the block. If the block @@ -51,6 +54,12 @@ import { useBlockElement } from '../block-list/use-block-props/use-block-refs'; * @return {Component} The component to be rendered. */ function BlockSelectionButton( { clientId, rootClientId }, ref ) { + const blockContext = useContext( BlockContext ); + const registry = useRegistry(); + const sources = useSelect( ( select ) => + unlock( select( blocksStore ) ).getAllBlockBindingsSources() + ); + const selected = useSelect( ( select ) => { const { @@ -62,7 +71,7 @@ function BlockSelectionButton( { clientId, rootClientId }, ref ) { getNextBlockClientId, getPreviousBlockClientId, canMoveBlock, - } = select( blockEditorStore ); + } = unlock( select( blockEditorStore ) ); const { getActiveBlockVariation, getBlockType } = select( blocksStore ); const index = getBlockIndex( clientId ); @@ -72,13 +81,28 @@ function BlockSelectionButton( { clientId, rootClientId }, ref ) { getBlockListSettings( rootClientId )?.orientation; const match = getActiveBlockVariation( name, attributes ); + const blockBindings = attributes?.metadata?.bindings; + const boundAttributes = getBindingsValues( + blockBindings, + name, + sources, + registry, + blockContext, + clientId + ); + + const newAttributes = { + ...attributes, + ...boundAttributes, + }; + return { blockMovingMode: hasBlockMovingClientId(), editorMode: __unstableGetEditorMode(), icon: match?.icon || blockType.icon, label: getAccessibleBlockLabel( blockType, - attributes, + newAttributes, index + 1, orientation ), @@ -87,7 +111,7 @@ function BlockSelectionButton( { clientId, rootClientId }, ref ) { getPreviousBlockClientId, }; }, - [ clientId, rootClientId ] + [ clientId, rootClientId, sources, registry, blockContext ] ); const { label, icon, blockMovingMode, editorMode, canMove } = selected; const { setNavigationMode, removeBlock } = useDispatch( blockEditorStore ); diff --git a/packages/block-editor/src/hooks/use-bindings-attributes.js b/packages/block-editor/src/hooks/use-bindings-attributes.js index e1ebf5fda6b8ee..ee65c13ac853cd 100644 --- a/packages/block-editor/src/hooks/use-bindings-attributes.js +++ b/packages/block-editor/src/hooks/use-bindings-attributes.js @@ -96,6 +96,82 @@ export function getBindableAttributes( blockName ) { return BLOCK_BINDINGS_ALLOWED_BLOCKS[ blockName ]; } +export function getBindingsValues( + blockBindings, + name, + sources, + registry, + blockContext, + clientId +) { + if ( ! blockBindings ) { + return {}; + } + + const attributes = {}; + + const blockBindingsBySource = new Map(); + + for ( const [ attributeName, binding ] of Object.entries( + blockBindings + ) ) { + const { source: sourceName, args: sourceArgs } = binding; + const source = sources[ sourceName ]; + if ( ! source || ! canBindAttribute( name, attributeName ) ) { + continue; + } + + blockBindingsBySource.set( source, { + ...blockBindingsBySource.get( source ), + [ attributeName ]: { + args: sourceArgs, + }, + } ); + } + + if ( blockBindingsBySource.size ) { + for ( const [ source, bindings ] of blockBindingsBySource ) { + // Populate context. + const context = {}; + + if ( source.usesContext?.length ) { + for ( const key of source.usesContext ) { + context[ key ] = blockContext[ key ]; + } + } + + // Get values in batch if the source supports it. + let values = {}; + if ( ! source.getValues ) { + Object.keys( bindings ).forEach( ( attr ) => { + // Default to the `key` or the source label when `getValues` doesn't exist + values[ attr ] = bindings[ attr ].args?.key || source.label; + } ); + } else { + values = source.getValues( { + registry, + context, + clientId, + bindings, + } ); + } + for ( const [ attributeName, value ] of Object.entries( values ) ) { + if ( + attributeName === 'url' && + ( ! value || ! isURLLike( value ) ) + ) { + // Return null if value is not a valid URL. + attributes[ attributeName ] = null; + } else { + attributes[ attributeName ] = value; + } + } + } + } + + return attributes; +} + export const withBlockBindingSupport = createHigherOrderComponent( ( BlockEdit ) => ( props ) => { const registry = useRegistry(); @@ -122,76 +198,15 @@ export const withBlockBindingSupport = createHigherOrderComponent( // there are attribute updates. // `source.getValues` may also call a selector via `registry.select`. const boundAttributes = useSelect( () => { - if ( ! blockBindings ) { - return; - } - - const attributes = {}; - - const blockBindingsBySource = new Map(); - - for ( const [ attributeName, binding ] of Object.entries( - blockBindings - ) ) { - const { source: sourceName, args: sourceArgs } = binding; - const source = sources[ sourceName ]; - if ( ! source || ! canBindAttribute( name, attributeName ) ) { - continue; - } - - blockBindingsBySource.set( source, { - ...blockBindingsBySource.get( source ), - [ attributeName ]: { - args: sourceArgs, - }, - } ); - } - - if ( blockBindingsBySource.size ) { - for ( const [ source, bindings ] of blockBindingsBySource ) { - // Populate context. - const context = {}; - - if ( source.usesContext?.length ) { - for ( const key of source.usesContext ) { - context[ key ] = blockContext[ key ]; - } - } - - // Get values in batch if the source supports it. - let values = {}; - if ( ! source.getValues ) { - Object.keys( bindings ).forEach( ( attr ) => { - // Default to the `key` or the source label when `getValues` doesn't exist - values[ attr ] = - bindings[ attr ].args?.key || source.label; - } ); - } else { - values = source.getValues( { - registry, - context, - clientId, - bindings, - } ); - } - for ( const [ attributeName, value ] of Object.entries( - values - ) ) { - if ( - attributeName === 'url' && - ( ! value || ! isURLLike( value ) ) - ) { - // Return null if value is not a valid URL. - attributes[ attributeName ] = null; - } else { - attributes[ attributeName ] = value; - } - } - } - } - - return attributes; - }, [ blockBindings, name, clientId, blockContext, registry, sources ] ); + return getBindingsValues( + blockBindings, + name, + sources, + registry, + blockContext, + clientId + ); + }, [ blockBindings, name, sources, registry, blockContext, clientId ] ); const { setAttributes } = props;