From e02a367f1c2bcbb26eaffd9666b1c676566e4909 Mon Sep 17 00:00:00 2001 From: Ricardo Artemio Morales Date: Fri, 6 Sep 2024 04:09:36 -0400 Subject: [PATCH 1/7] Modify label for connected paragraphs --- packages/block-library/src/paragraph/index.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/paragraph/index.js b/packages/block-library/src/paragraph/index.js index 715fb35ec05ab1..612339eb3c20b4 100644 --- a/packages/block-library/src/paragraph/index.js +++ b/packages/block-library/src/paragraph/index.js @@ -39,7 +39,11 @@ export const settings = { return customName; } - const { content } = attributes; + const { content, metadata: currentMetadata } = attributes; + + if ( currentMetadata?.bindings?.content ) { + return __( 'Paragraph with dynamic content' ); + } return ! content || content.length === 0 ? __( 'Empty' ) : content; } }, From 5f62c916787a59377d30ba8db3262cd7d844f8f5 Mon Sep 17 00:00:00 2001 From: Ricardo Artemio Morales Date: Mon, 9 Sep 2024 01:53:08 -0400 Subject: [PATCH 2/7] Revert "Modify label for connected paragraphs" This reverts commit e02a367f1c2bcbb26eaffd9666b1c676566e4909. --- packages/block-library/src/paragraph/index.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/block-library/src/paragraph/index.js b/packages/block-library/src/paragraph/index.js index 612339eb3c20b4..715fb35ec05ab1 100644 --- a/packages/block-library/src/paragraph/index.js +++ b/packages/block-library/src/paragraph/index.js @@ -39,11 +39,7 @@ export const settings = { return customName; } - const { content, metadata: currentMetadata } = attributes; - - if ( currentMetadata?.bindings?.content ) { - return __( 'Paragraph with dynamic content' ); - } + const { content } = attributes; return ! content || content.length === 0 ? __( 'Empty' ) : content; } }, From 08649191b27f013bc8e8b6d889478dbc339714a7 Mon Sep 17 00:00:00 2001 From: Ricardo Artemio Morales Date: Mon, 9 Sep 2024 01:54:54 -0400 Subject: [PATCH 3/7] Add general override for accessibility label --- .../src/hooks/use-bindings-attributes.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/block-editor/src/hooks/use-bindings-attributes.js b/packages/block-editor/src/hooks/use-bindings-attributes.js index e1ebf5fda6b8ee..037a63a92bd9e9 100644 --- a/packages/block-editor/src/hooks/use-bindings-attributes.js +++ b/packages/block-editor/src/hooks/use-bindings-attributes.js @@ -96,7 +96,7 @@ export function getBindableAttributes( blockName ) { return BLOCK_BINDINGS_ALLOWED_BLOCKS[ blockName ]; } -export const withBlockBindingSupport = createHigherOrderComponent( +export const editWithBlockBindings = createHigherOrderComponent( ( BlockEdit ) => ( props ) => { const registry = useRegistry(); const blockContext = useContext( BlockContext ); @@ -296,9 +296,18 @@ export const withBlockBindingSupport = createHigherOrderComponent( ); }, - 'withBlockBindingSupport' + 'editWithBlockBindings' ); +function labelWithBlockBindings( settings ) { + return ( attributes, { context } ) => { + if ( attributes?.metadata?.bindings && context === 'accessibility' ) { + return 'Overriding label'; + } + return settings.__experimentalLabel?.( attributes, { context } ); + }; +} + /** * Filters a registered block's settings to enhance a block's `edit` component * to upgrade bound attributes. @@ -314,7 +323,8 @@ function shimAttributeSource( settings, name ) { return { ...settings, - edit: withBlockBindingSupport( settings.edit ), + edit: editWithBlockBindings( settings.edit ), + __experimentalLabel: labelWithBlockBindings( settings ), }; } From 565b179dfe1c73d2e36b7a262dd81109e57bbd32 Mon Sep 17 00:00:00 2001 From: Ricardo Artemio Morales Date: Tue, 10 Sep 2024 02:17:15 -0400 Subject: [PATCH 4/7] Revert "Add general override for accessibility label" This reverts commit 08649191b27f013bc8e8b6d889478dbc339714a7. --- .../src/hooks/use-bindings-attributes.js | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/packages/block-editor/src/hooks/use-bindings-attributes.js b/packages/block-editor/src/hooks/use-bindings-attributes.js index 037a63a92bd9e9..e1ebf5fda6b8ee 100644 --- a/packages/block-editor/src/hooks/use-bindings-attributes.js +++ b/packages/block-editor/src/hooks/use-bindings-attributes.js @@ -96,7 +96,7 @@ export function getBindableAttributes( blockName ) { return BLOCK_BINDINGS_ALLOWED_BLOCKS[ blockName ]; } -export const editWithBlockBindings = createHigherOrderComponent( +export const withBlockBindingSupport = createHigherOrderComponent( ( BlockEdit ) => ( props ) => { const registry = useRegistry(); const blockContext = useContext( BlockContext ); @@ -296,18 +296,9 @@ export const editWithBlockBindings = createHigherOrderComponent( ); }, - 'editWithBlockBindings' + 'withBlockBindingSupport' ); -function labelWithBlockBindings( settings ) { - return ( attributes, { context } ) => { - if ( attributes?.metadata?.bindings && context === 'accessibility' ) { - return 'Overriding label'; - } - return settings.__experimentalLabel?.( attributes, { context } ); - }; -} - /** * Filters a registered block's settings to enhance a block's `edit` component * to upgrade bound attributes. @@ -323,8 +314,7 @@ function shimAttributeSource( settings, name ) { return { ...settings, - edit: editWithBlockBindings( settings.edit ), - __experimentalLabel: labelWithBlockBindings( settings ), + edit: withBlockBindingSupport( settings.edit ), }; } From 38eb29c6e60395dc091b943863882f0333eb15c0 Mon Sep 17 00:00:00 2001 From: Ricardo Artemio Morales Date: Tue, 10 Sep 2024 02:19:25 -0400 Subject: [PATCH 5/7] Implement bindings lookup in block selection button --- .../block-tools/block-selection-button.js | 97 ++++++++++++++++++- 1 file changed, 93 insertions(+), 4 deletions(-) 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..43a6922e1e428a 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 ), From 1796a454a8eb1ae496fdc43003f084ee05e709f9 Mon Sep 17 00:00:00 2001 From: Ricardo Artemio Morales Date: Tue, 10 Sep 2024 14:13:05 -0400 Subject: [PATCH 6/7] Move logic to get values to a separate function --- .../block-tools/block-selection-button.js | 85 ++-------- .../src/hooks/use-bindings-attributes.js | 151 ++++++++++-------- 2 files changed, 91 insertions(+), 145 deletions(-) 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 43a6922e1e428a..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 @@ -39,9 +39,8 @@ 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 { getBindingsValues } 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 @@ -57,7 +56,6 @@ import isURLLike from '../link-control/is-url-like'; function BlockSelectionButton( { clientId, rootClientId }, ref ) { const blockContext = useContext( BlockContext ); const registry = useRegistry(); - const sources = useSelect( ( select ) => unlock( select( blocksStore ) ).getAllBlockBindingsSources() ); @@ -83,78 +81,15 @@ 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 boundAttributes = getBindingsValues( + blockBindings, + name, + sources, + registry, + blockContext, + clientId + ); const newAttributes = { ...attributes, @@ -176,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..82f1978185fd1b 100644 --- a/packages/block-editor/src/hooks/use-bindings-attributes.js +++ b/packages/block-editor/src/hooks/use-bindings-attributes.js @@ -96,6 +96,78 @@ export function getBindableAttributes( blockName ) { return BLOCK_BINDINGS_ALLOWED_BLOCKS[ blockName ]; } +export function getBindingsValues( + blockBindings, + name, + sources, + registry, + blockContext, + clientId +) { + 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 +194,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; From b7c326c9f989452fd75ca5f6f55ad6fc031519fe Mon Sep 17 00:00:00 2001 From: Ricardo Artemio Morales Date: Thu, 12 Sep 2024 22:50:05 -0400 Subject: [PATCH 7/7] Add check so editor doesn't break --- packages/block-editor/src/hooks/use-bindings-attributes.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/block-editor/src/hooks/use-bindings-attributes.js b/packages/block-editor/src/hooks/use-bindings-attributes.js index 82f1978185fd1b..ee65c13ac853cd 100644 --- a/packages/block-editor/src/hooks/use-bindings-attributes.js +++ b/packages/block-editor/src/hooks/use-bindings-attributes.js @@ -104,6 +104,10 @@ export function getBindingsValues( blockContext, clientId ) { + if ( ! blockBindings ) { + return {}; + } + const attributes = {}; const blockBindingsBySource = new Map();