From 93dd22d9c5e69d25ab9890fc45fdbff2dc7e5790 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 88e5828b2fd0e4..1f95809c9674b0 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 64974bd8000b27..ce9b9f9ab3be94 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; +}