Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Block Bindings: Accept client ID as parameter for useBlockBindingsUtils #65818

Merged
merged 3 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/block-editor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -877,6 +877,10 @@ updateBlockBindings( { url: undefined } );
removeAllBlockBindings();
```

_Parameters_

- _clientId_ `?string`: Optional block client ID. If not set, it will use the current block client ID from the context.

_Returns_

- `?WPBlockBindingsUtils`: Object containing the block bindings utils.
Expand Down
15 changes: 9 additions & 6 deletions packages/block-editor/src/utils/block-bindings.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ function isObjectEmpty( object ) {
*
* @since 6.7.0 Introduced in WordPress core.
*
* @param {?string} clientId Optional block client ID. If not set, it will use the current block client ID from the context.
*
* @return {?WPBlockBindingsUtils} Object containing the block bindings utils.
*
* @example
Expand Down Expand Up @@ -62,8 +64,9 @@ function isObjectEmpty( object ) {
* removeAllBlockBindings();
* ```
*/
export function useBlockBindingsUtils() {
const { clientId } = useBlockEditContext();
export function useBlockBindingsUtils( clientId ) {
const { clientId: contextClientId } = useBlockEditContext();
const blockClientId = clientId || contextClientId;
const { updateBlockAttributes } = useDispatch( blockEditorStore );
const { getBlockAttributes } = useRegistry().select( blockEditorStore );

Expand Down Expand Up @@ -98,7 +101,7 @@ export function useBlockBindingsUtils() {
*/
const updateBlockBindings = ( bindings ) => {
const { metadata: { bindings: currentBindings, ...metadata } = {} } =
getBlockAttributes( clientId );
getBlockAttributes( blockClientId );
const newBindings = { ...currentBindings };

Object.entries( bindings ).forEach( ( [ attribute, binding ] ) => {
Expand All @@ -118,7 +121,7 @@ export function useBlockBindingsUtils() {
delete newMetadata.bindings;
}

updateBlockAttributes( clientId, {
updateBlockAttributes( blockClientId, {
metadata: isObjectEmpty( newMetadata ) ? undefined : newMetadata,
} );
};
Expand All @@ -136,8 +139,8 @@ export function useBlockBindingsUtils() {
*/
const removeAllBlockBindings = () => {
const { metadata: { bindings, ...metadata } = {} } =
getBlockAttributes( clientId );
updateBlockAttributes( clientId, {
getBlockAttributes( blockClientId );
updateBlockAttributes( blockClientId, {
metadata: isObjectEmpty( metadata ) ? undefined : metadata,
} );
};
Expand Down
174 changes: 174 additions & 0 deletions packages/block-editor/src/utils/test/use-block-bindings-utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/**
* External dependencies
*/
import { renderHook } from '@testing-library/react';

/**
* WordPress dependencies
*/
import { store as blockEditorStore } from '@wordpress/block-editor';
import { dispatch, select } from '@wordpress/data';
import {
createBlock,
getBlockTypes,
unregisterBlockType,
} from '@wordpress/blocks';
import { registerCoreBlocks } from '@wordpress/block-library';

/**
* Internal dependencies
*/
import { useBlockBindingsUtils } from '../';

describe( 'useBlockBindingsUtils', () => {
beforeAll( () => {
// Register all core blocks
registerCoreBlocks();
} );

let clientId;
beforeEach( async () => {
const block = createBlock( 'core/paragraph', {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super nuanced nit. I believe that you can use here dispatch( blockEditorStore ).resetBlocks( [ block ] ); instead of insertBlocks.

This way dispatch( blockEditorStore ).resetBlocks( [] ); could be run only once in afterAll instead of afterEach.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good one 🙂 If I understood you correctly, it has been addressed in this commit: e52bab2

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, exactly that 👍🏻

metadata: {
name: 'Block name',
bindings: {
prop1: {
source: 'core/post-meta',
args: {
key: 'initial_key',
},
},
prop2: {
source: 'core/post-meta',
args: {
key: 'initial_key',
},
},
},
},
} );
await dispatch( blockEditorStore ).resetBlocks( [ block ] );
clientId = block.clientId;
} );

afterAll( () => {
// Remove blocks after all tests.
dispatch( blockEditorStore ).resetBlocks( [] );

// Clean up registered blocks
getBlockTypes().forEach( ( block ) => {
unregisterBlockType( block.name );
} );
} );

it( 'should be possible to update just one connection', async () => {
renderHook( () => {
const { updateBlockBindings } = useBlockBindingsUtils( clientId );
updateBlockBindings( {
prop1: {
source: 'core/post-meta',
args: {
key: 'new_key',
},
},
} );
} );
const { metadata } =
await select( blockEditorStore ).getBlockAttributes( clientId );
expect( metadata ).toMatchObject( {
// Other metadata properties shouldn't change.
name: 'Block name',
bindings: {
prop1: {
source: 'core/post-meta',
args: {
key: 'new_key',
},
},
prop2: {
source: 'core/post-meta',
args: {
key: 'initial_key',
},
},
},
} );
} );

it( 'should be possible to update multiple connections at once', async () => {
renderHook( () => {
const { updateBlockBindings } = useBlockBindingsUtils( clientId );
updateBlockBindings( {
prop1: {
source: 'core/post-meta',
args: {
key: 'new_key',
},
},
prop2: {
source: 'core/post-meta',
args: {
key: 'new_key',
},
},
} );
} );
const { metadata } =
await select( blockEditorStore ).getBlockAttributes( clientId );
expect( metadata ).toMatchObject( {
// Other metadata properties shouldn't change.
name: 'Block name',
bindings: {
prop1: {
source: 'core/post-meta',
args: {
key: 'new_key',
},
},
prop2: {
source: 'core/post-meta',
args: {
key: 'new_key',
},
},
},
} );
} );

it( 'should be possible to remove connections', async () => {
renderHook( () => {
const { updateBlockBindings } = useBlockBindingsUtils( clientId );
updateBlockBindings( {
prop2: undefined,
} );
} );
const { metadata } =
await select( blockEditorStore ).getBlockAttributes( clientId );
expect( metadata ).toMatchObject( {
// Other metadata properties shouldn't change.
name: 'Block name',
bindings: {
prop1: {
source: 'core/post-meta',
args: {
key: 'initial_key',
},
},
},
} );
} );

it( 'should be possible to remove all connections', async () => {
renderHook( () => {
const { removeAllBlockBindings } =
useBlockBindingsUtils( clientId );
removeAllBlockBindings();
} );
const { metadata } =
await select( blockEditorStore ).getBlockAttributes( clientId );
expect( metadata ).toMatchObject( {
// Other metadata properties shouldn't change.
name: 'Block name',
} );
} );
} );
Loading