-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
ToggleGroupControl: Don't set value on focus after a reset #66151
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. |
toggleGroupControlContext.value === null || | ||
toggleGroupControlContext.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.
Due to how we add a layer of value
conversion in controlled mode, the Ariakit store will hold a null
value on first render with no value provided, but then an empty string after a consumer resets the value
to undefined
.
// Ensures that the active id is also reset after the value is "reset" by the consumer. | ||
useEffect( () => { | ||
if ( selectedValue === '' ) { | ||
radio.setActiveId( undefined ); | ||
} | ||
}, [ radio, selectedValue ] ); |
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 can feel the tech debt catching up to us 😅
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.
Food for thought: I wonder if this can be improved with a centralized controlled component layer that all controlled components would use. Probably a too idealistic idea, since some components use Ariakit and others do not, and this layer would be quite complicated to cover all cases.
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 think that the most practical fix here is to change the APIs to follow the standard convention for controlled / uncontrolled component. Since that would be a breaking change, we could just release a V2 of the component that would give us also a chance to:
- implement / test the new design spec alongside the legacy one
- review the current API strategy around "deselectability" and potentially multiple selection (should they be separate components? Or different subcomponents?)
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.
For this case specifically, I think there might be room to argue that resetting the active id on empty-ish (or invalid) values should be handled by Ariakit out of the box. I'll try and follow up.
Flaky tests detected in 1c8b689. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/11356382384
|
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.
LGTM, thanks for the fix 👍 🚀
@@ -141,10 +141,14 @@ function ToggleGroupControlOptionBase( | |||
<Ariakit.Radio | |||
disabled={ disabled } | |||
onFocusVisible={ () => { | |||
const selectedValueIsNullish = |
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.
Naming nit: nullish
often refers to null
or undefined
, so if someone isn't reading closely, they might be confused and expect this checks for undefined
and not an empty string.
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.
Maybe selectedValueIsEmpty
? Or even inlining the check?
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'd be fine with inlining 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.
Good point, I'll go with selectedValueIsEmpty
here. (It started as an inline condition, but it was hard to parse/understand so I prefer it named.)
// Ensures that the active id is also reset after the value is "reset" by the consumer. | ||
useEffect( () => { | ||
if ( selectedValue === '' ) { | ||
radio.setActiveId( undefined ); | ||
} | ||
}, [ radio, selectedValue ] ); |
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.
Food for thought: I wonder if this can be improved with a centralized controlled component layer that all controlled components would use. Probably a too idealistic idea, since some components use Ariakit and others do not, and this layer would be quite complicated to cover all cases.
@@ -175,6 +175,32 @@ describe.each( [ | |||
expect( radio ).not.toBeChecked(); | |||
} ); | |||
|
|||
if ( mode === 'controlled' ) { |
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 move it next to the other controlled
-only tests?
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.
No strong opinion, but I think I prefer it here because it's closely related to the test right above it.
There was a conflict while trying to cherry-pick the commit to the wp/6.7 branch. Please resolve the conflict manually and create a PR to the wp/6.7 branch. PRs to wp/6.7 are similar to PRs to trunk, but you should base your PR on the wp/6.7 branch instead of trunk.
|
@mirka just a ping in case you didn't notice the failed backport |
* Add test * ToggleGroupControl: Don't set value on focus after a reset * Add changelog * Rename to `selectedValueIsEmpty` Co-authored-by: mirka <0mirka00@git.wordpress.org> Co-authored-by: tyxla <tyxla@git.wordpress.org> Co-authored-by: ciampo <mciampini@git.wordpress.org> # Conflicts: # packages/components/CHANGELOG.md
Backported at 4a7de72 |
…#66151) * Add test * ToggleGroupControl: Don't set value on focus after a reset * Add changelog * Rename to `selectedValueIsEmpty` Co-authored-by: mirka <0mirka00@git.wordpress.org> Co-authored-by: tyxla <tyxla@git.wordpress.org> Co-authored-by: ciampo <mciampini@git.wordpress.org>
Bug discovered in #65386 (comment)
What?
Fixes an incomplete bug fix in #65892 where ToggleGroupControl could still autoselect an option on focus after the selected value was reset by the consumer.
Testing Instructions for Keyboard
Modify the Storybook story so it has a reset button, like this: