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 9c6c22181ef2a..43a6922e1e428 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,10 @@ 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 { canBindAttribute } from '../../hooks/use-bindings-attributes'; +import BlockContext from '../block-context'; +import isURLLike from '../link-control/is-url-like'; /** * Block selection button component, displaying the label of the block. If the block @@ -51,6 +55,13 @@ 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 +73,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 +83,91 @@ function BlockSelectionButton( { clientId, rootClientId }, ref ) { getBlockListSettings( rootClientId )?.orientation; const match = getActiveBlockVariation( name, attributes ); + const boundAttributes = {}; + const blockBindings = attributes?.metadata?.bindings; + + if ( blockBindings ) { + 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. + boundAttributes[ attributeName ] = null; + } else { + boundAttributes[ attributeName ] = value; + } + } + } + } + } + + const newAttributes = { + ...attributes, + ...boundAttributes, + }; + return { blockMovingMode: hasBlockMovingClientId(), editorMode: __unstableGetEditorMode(), icon: match?.icon || blockType.icon, label: getAccessibleBlockLabel( blockType, - attributes, + newAttributes, index + 1, orientation ),