Skip to content

Commit

Permalink
Block Variations: Support dot notation in isActive string array (#6…
Browse files Browse the repository at this point in the history
…2088)

If a block variation's `isActive` property is a `string[]`, support "object paths" (i.e. dot ["property accessors"](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors)), such as

```js
isActive: [ 'namespace', 'query.postType' ]
```

---------

Co-authored-by: ntsekouras <[email protected]>
  • Loading branch information
ockham and ntsekouras authored May 30, 2024
1 parent 9c9120c commit d88dffb
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 9 deletions.
6 changes: 6 additions & 0 deletions docs/reference-guides/block-api/block-variations.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,12 @@ The `string[]` version is used to declare which attributes should be compared as
isActive: [ 'providerNameSlug' ]
```

Nested object paths are also supported. For example, consider a block variation that has a `query` object as an attribute. It is possible to determine if the variation is active solely based on that object's `postType` property (while ignoring all its other properties):

```js
isActive: [ 'query.postType' ]
```

### Caveats to using `isActive`

The `isActive` property can return false positives if multiple variations exist for a specific block and the `isActive` checks are not specific enough. To demonstrate this, consider the following example:
Expand Down
4 changes: 1 addition & 3 deletions packages/block-library/src/query/variations.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,7 @@ const variations = [
},
},
scope: [ 'inserter' ],
isActive: ( { namespace, query } ) => {
return namespace === 'core/posts-list' && query.postType === 'post';
},
isActive: [ 'namespace', 'query.postType' ],
},
{
name: 'title-date',
Expand Down
26 changes: 20 additions & 6 deletions packages/blocks/src/store/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -242,16 +242,30 @@ export function getActiveBlockVariation( state, blockName, attributes, scope ) {
const blockType = getBlockType( state, blockName );
const attributeKeys = Object.keys( blockType?.attributes || {} );
const definedAttributes = variation.isActive.filter(
( attribute ) => attributeKeys.includes( attribute )
( attribute ) => {
// We support nested attribute paths, e.g. `layout.type`.
// In this case, we need to check if the part before the
// first dot is a known attribute.
const topLevelAttribute = attribute.split( '.' )[ 0 ];
return attributeKeys.includes( topLevelAttribute );
}
);
if ( definedAttributes.length === 0 ) {
return false;
}
return definedAttributes.every(
( attribute ) =>
attributes[ attribute ] ===
variation.attributes[ attribute ]
);
return definedAttributes.every( ( attribute ) => {
const attributeValue = getValueFromObjectPath(
attributes,
attribute
);
if ( attributeValue === undefined ) {
return false;
}
return (
attributeValue ===
getValueFromObjectPath( variation.attributes, attribute )
);
} );
}

return variation.isActive?.( attributes, variation.attributes );
Expand Down
41 changes: 41 additions & 0 deletions packages/blocks/src/store/test/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,47 @@ describe( 'selectors', () => {
expect( result ).toEqual( variation );
} );
} );
it( 'should support nested attribute paths in the isActive array', () => {
const variations = [
{
name: 'variation-1',
attributes: {
firstTestAttribute: {
nestedProperty: 1,
otherNestedProperty: 5555,
},
},
isActive: [ 'firstTestAttribute.nestedProperty' ],
},
{
name: 'variation-2',
attributes: {
firstTestAttribute: {
nestedProperty: 2,
otherNestedProperty: 5555,
},
},
isActive: [ 'firstTestAttribute.nestedProperty' ],
},
];
const state =
createBlockVariationsStateWithTestBlockType( variations );

expect(
getActiveBlockVariation( state, blockName, {
firstTestAttribute: {
nestedProperty: 1,
},
} )
).toEqual( variations[ 0 ] );
expect(
getActiveBlockVariation( state, blockName, {
firstTestAttribute: {
nestedProperty: 2,
},
} )
).toEqual( variations[ 1 ] );
} );
it( 'should return the active variation based on the given isActive array (multiple values)', () => {
const variations = [
{
Expand Down

0 comments on commit d88dffb

Please sign in to comment.