From 2f2677a7fe291bb0b0775ed6a68967bfce7426f5 Mon Sep 17 00:00:00 2001 From: Bernie Reiter <96308+ockham@users.noreply.github.com> Date: Wed, 5 Jun 2024 19:18:27 +0200 Subject: [PATCH] Block Variations: Compare objects based on given properties (#62272) If a block variation has an isActive property that is an array of strings (attribute names), and one of the attributes referenced therein is an object, compare that attribute based on the object properties specified by the variation, rather than by reference. Co-authored-by: ockham Co-authored-by: ntsekouras Co-authored-by: cbravobernal Co-authored-by: tyxla Co-authored-by: gziolo maxMatchedAttributes ) { match = variation; diff --git a/packages/blocks/src/store/test/selectors.js b/packages/blocks/src/store/test/selectors.js index 88e5828b2fd0e..1f95809c9674b 100644 --- a/packages/blocks/src/store/test/selectors.js +++ b/packages/blocks/src/store/test/selectors.js @@ -494,6 +494,83 @@ describe( 'selectors', () => { } ) ).toEqual( variations[ 1 ] ); } ); + it( 'should compare object attributes in the isActive array based on given properties', () => { + const variations = [ + { + name: 'variation-1', + attributes: { + firstTestAttribute: { + nestedProperty: 1, + secondNestedProperty: 10, + }, + secondTestAttribute: { + nestedProperty: { + firstDeeplyNestedProperty: 'a1', + secondDeeplyNestedProperty: 'a2', + }, + }, + }, + isActive: [ + 'firstTestAttribute', + 'secondTestAttribute.nestedProperty', + ], + }, + { + name: 'variation-2', + attributes: { + firstTestAttribute: { + nestedProperty: 2, + secondNestedProperty: 20, + }, + secondTestAttribute: { + nestedProperty: { + firstDeeplyNestedProperty: 'b1', + secondDeeplyNestedProperty: 'b2', + }, + }, + }, + isActive: [ + 'firstTestAttribute', + 'secondTestAttribute.nestedProperty', + ], + }, + ]; + const state = + createBlockVariationsStateWithTestBlockType( variations ); + + expect( + getActiveBlockVariation( state, blockName, { + firstTestAttribute: { + nestedProperty: 1, + secondNestedProperty: 10, + otherNestedProperty: 5555, + }, + secondTestAttribute: { + nestedProperty: { + firstDeeplyNestedProperty: 'a1', + secondDeeplyNestedProperty: 'a2', + otherDeeplyNestedProperty: 'ffff', + }, + }, + } ) + ).toEqual( variations[ 0 ] ); + expect( + getActiveBlockVariation( state, blockName, { + firstTestAttribute: { + nestedProperty: 2, + secondNestedProperty: 20, + otherNestedProperty: 5555, + }, + secondTestAttribute: { + nestedProperty: { + firstDeeplyNestedProperty: 'b1', + secondDeeplyNestedProperty: 'b2', + otherDeeplyNestedProperty: 'ffff', + }, + }, + } ) + ).toEqual( variations[ 1 ] ); + } ); it( 'should return the active variation based on the given isActive array (multiple values)', () => { const variations = [ { diff --git a/packages/blocks/src/store/utils.js b/packages/blocks/src/store/utils.js index 64974bd8000b2..ce9b9f9ab3be9 100644 --- a/packages/blocks/src/store/utils.js +++ b/packages/blocks/src/store/utils.js @@ -18,3 +18,33 @@ export const getValueFromObjectPath = ( object, path, defaultValue ) => { } ); return value ?? defaultValue; }; + +function isObject( candidate ) { + return ( + typeof candidate === 'object' && + candidate.constructor === Object && + candidate !== null + ); +} + +/** + * Determine whether a set of object properties matches a given object. + * + * Given an object of block attributes and an object of variation attributes, + * this function checks recursively whether all the variation attributes are + * present in the block attributes object. + * + * @param {Object} blockAttributes The object to inspect. + * @param {Object} variationAttributes The object of property values to match. + * @return {boolean} Whether the block attributes match the variation attributes. + */ +export function matchesAttributes( blockAttributes, variationAttributes ) { + if ( isObject( blockAttributes ) && isObject( variationAttributes ) ) { + return Object.entries( variationAttributes ).every( + ( [ key, value ] ) => + matchesAttributes( blockAttributes?.[ key ], value ) + ); + } + + return blockAttributes === variationAttributes; +}