-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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 Variations: Compare objects based on given properties #62272
Block Variations: Compare objects based on given properties #62272
Conversation
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.
To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
Size Change: +453 B (+0.03%) Total Size: 1.75 MB
ℹ️ View Unchanged
|
8fcc7a6
to
3633a2b
Compare
Flaky tests detected in 3633a2b. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/9368609354
|
packages/blocks/src/store/utils.js
Outdated
@@ -18,3 +18,15 @@ export const getValueFromObjectPath = ( object, path, defaultValue ) => { | |||
} ); | |||
return value ?? defaultValue; | |||
}; | |||
|
|||
export function matchesAttributes( blockAttributes, variation ) { | |||
return Object.entries( variation ).every( ( [ key, value ] ) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering if we have a util for this already with all the removal of lodash work.. --cc @tyxla
Maybe isShallowEqual
? Additionally it seem we would have the same issue with arrays
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(isShallowEqual
isn't quite the right fit: We only need the given block to match all the variation object attribute's properties, but it's okay if the block's object attribute has additional properties. E.g. in the example from the PR description, if the given block's metadata.bindings.content
object has an additional label
property, the variation should still match it.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Additionally it seem we would have the same issue with
arrays
.
That's a fair point, but I'd rather tackle that separately. It's a bit less clear to me what the desired behavior should be for them, so I think it deserves a bit of dedicated discussion. If a variation has
"attributes": {
"arrayAttr": [ "a", "b", "c" ]
},
"isActive": [ "arrayAttr" ]
then which of the following blocks should we match?
[ "a", "b", "c", "d" ] // Variation contains a subset
[ "b", "c", "a" ] // Variation matches array items but not array order
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to close the loop, based on the need @ockham described, I agree that it's best if we reintroduce that util.
packages/blocks/src/store/utils.js
Outdated
return Object.entries( variationAttributes ).every( ( [ key, value ] ) => { | ||
if ( | ||
typeof value === 'object' && | ||
typeof blockAttributes[ key ] === 'object' | ||
) { | ||
return matchesAttributes( blockAttributes[ key ], value ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we add an exception for null
? typeof null
is object
, but if both value
and blockAttributes[ key ]
are null
, we'll call Object.entries( null )
which will be a TypeError
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, good spot! I added a check in b69dc0a which I think should be sufficient.
); | ||
// If the attribute value is an object, we need to compare its properties. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How far is it from isShallowEqual
from @wordpress/is-shallow-equal
at this point?
gutenberg/packages/is-shallow-equal/src/index.js
Lines 23 to 33 in 06470bb
export default function isShallowEqual( a, b ) { | |
if ( a && b ) { | |
if ( a.constructor === Object && b.constructor === Object ) { | |
return isShallowEqualObjects( a, b ); | |
} else if ( Array.isArray( a ) && Array.isArray( b ) ) { | |
return isShallowEqualArrays( a, b ); | |
} | |
} | |
return a === b; | |
} |
b69dc0a
to
e378dad
Compare
@cbravobernal pointed out to me that the example in the PR desc is currently not working (thank you!)
Edit: Ignore, I just missed the |
e378dad
to
75d61fc
Compare
I think I tracked down the error and fixed it (see the last couple of commits). |
Checking in on PRs with the Backport to Gutenberg RC. I'll release 18.5 later today, do you think this'll make it in time? |
Depends on whether we'll get approval in time 🤞 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now works as expected. Great job @ockham !
@@ -19,6 +19,14 @@ export const getValueFromObjectPath = ( object, path, defaultValue ) => { | |||
return value ?? defaultValue; | |||
}; | |||
|
|||
function isObject( candidate ) { | |||
return ( | |||
typeof candidate === 'object' && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We called it item
in Interactivity. I like this nomenclature, maybe we should update to keep consistency in the codebase. Ping @DAreRodz @luisherranz
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I need more context. What exactly are we referring to as "item" in the Interactivity API? What is being referred to here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const isObject = ( item: unknown ): item is Record< string, unknown > => |
In Interactivity API, we check that several "items" are a JSON object in the same file (sources, state, config, proxy handlers, etc). So we call the variable to check "item".
"Candidate" seems also a good general definition, and would be ok to use the same name in all functions that are just checking that an item is an object (there are a few of them across the workspace).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, ok. You can change that if you want 🙂
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 <bernhard-reiter@git.wordpress.org> Co-authored-by: ntsekouras <ntsekouras@git.wordpress.org> Co-authored-by: cbravobernal <cbravobernal@git.wordpress.org> Co-authored-by: tyxla <tyxla@git.wordpress.org> Co-authored-by: gziolo <gziolo@git.wordpress.org
I just cherry-picked this PR to the release/18.5 branch to get it included in the next release: 2f2677a |
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 <bernhard-reiter@git.wordpress.org> Co-authored-by: ntsekouras <ntsekouras@git.wordpress.org> Co-authored-by: cbravobernal <cbravobernal@git.wordpress.org> Co-authored-by: tyxla <tyxla@git.wordpress.org> Co-authored-by: gziolo <gziolo@git.wordpress.org
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 <bernhard-reiter@git.wordpress.org> Co-authored-by: ntsekouras <ntsekouras@git.wordpress.org> Co-authored-by: cbravobernal <cbravobernal@git.wordpress.org> Co-authored-by: tyxla <tyxla@git.wordpress.org> Co-authored-by: gziolo <gziolo@git.wordpress.org
…s#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 <bernhard-reiter@git.wordpress.org> Co-authored-by: ntsekouras <ntsekouras@git.wordpress.org> Co-authored-by: cbravobernal <cbravobernal@git.wordpress.org> Co-authored-by: tyxla <tyxla@git.wordpress.org> Co-authored-by: gziolo <gziolo@git.wordpress.org
This was cherry-picked to the wp/6.6 branch. |
What?
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.Why?
Object attributes of a variation are currently compared by reference to the given block's attributes, meaning that the comparison will never return
true
.For example, take the following variation of the Paragraph block:
Prior to this PR,
isActive
would returnfalse
for the given variation, because it would compare the given block'smetadata.bindings.content
(nested) attribute by object reference to the variation's.How?
By (recursively) iterating over the object properties specified by the variation and comparing those to the given block's. (In the example above, those properties are
source
andargs
; sinceargs
is an object itself, the comparison steps into it recursively and compares itskey
property to the given block's as well).Note that this PR re-introduces the
matchesAttributes
util function (albeit in a different place) that was previously removed by #58194.Testing Instructions
Smoke-test block variations and verify that they still work as before.
Optionally, try adding the above variation to the Paragraph block, and verify that the variation is correctly detected (thus fixing the issue reported in this comment).