-
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
Add non-listbox functionality back to CircularOptionPicker
#54290
Add non-listbox functionality back to CircularOptionPicker
#54290
Conversation
Added some tests and a new story to go with the changes.
They all need to pass through the new `asButtons`/`disableLooping` prop following the `CircularOptionPicker` refactor.
That's annoying that we have to maintain two versions. |
Unfortunately, despite what The joys of component libraries! |
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.
Thank you for working on this (and adding unit tests too).
Left a few comments, let me know in case anything isn't clear.
packages/components/src/circular-option-picker/option-picker.tsx
Outdated
Show resolved
Hide resolved
packages/components/src/circular-option-picker/option-picker.tsx
Outdated
Show resolved
Hide resolved
packages/components/src/circular-option-picker/option-picker.tsx
Outdated
Show resolved
Hide resolved
packages/components/src/circular-option-picker/option-picker.tsx
Outdated
Show resolved
Hide resolved
packages/components/src/circular-option-picker/option-picker-option.tsx
Outdated
Show resolved
Hide resolved
{ ...compositeState } | ||
as={ Button } | ||
className={ classnames( className, { | ||
'is-pressed': isSelected, |
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.
Any reason why we're not passing isPressed
as a prop 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.
Doing so also sets aria-pressed
on the control, which we don't want for role="option"
. I thought I'd tried to override that and failed, but clearly not hard enough. Definitely better to let Button
worry about which classes to apply.
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.
Sounds good. Maybe let's add an inline comment above the aria-pressed
override explaining the reason for 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.
Turns out I possibly had tried hard enough, because aria-pressed={ null }
doesn't "work"...
Types of property ''aria-pressed'' are incompatible.
Type 'null' is not assignable to type 'boolean | "true" | "false" | "mixed" | undefined'.
Setting it to null
does properly override the value, and prevent aria-pressed
from showing up as an attribute in the HTML, but TypeScript doesn't like 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.
From what you say, it sounds like passing undefined
would correctly remove the aria-pressed
attribute from the button.
Maybe something like this would work?
{ ...( isSelected ? { 'aria-pressed': undefined } : {} ) }
Let's still add an inline comment in case.
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.
Unfortunately passing undefined
as a value for aria-pressed
gets it ignored entirely. I've added a note to explain the class addition.
Note
Follow-up task: Update Button
to check for role
before setting aria-pressed
, and set a more appropriate attribute (e.g. aria-selected
) as needed.
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.
Sounds good — could you open a new issue about it? You could work on it as a follow-up in the upcoming weeks.
packages/components/src/circular-option-picker/option-picker-option.tsx
Outdated
Show resolved
Hide resolved
packages/components/src/circular-option-picker/option-picker-option.tsx
Outdated
Show resolved
Hide resolved
packages/components/src/circular-option-picker/option-picker-option.tsx
Outdated
Show resolved
Hide resolved
One more question:
Currently, do My instinct is usually to add the least amount of public APIs necessary. |
|
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.
Definitely agreed with the |
For whatever reason, gutenberg/packages/edit-site/src/components/global-styles/gradients-palette-panel.js Lines 115 to 121 in fec5ffc
|
Overrode the code sample for |
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.
Almost there! Just a few minor comments left, but things are looking good.
packages/components/src/circular-option-picker/option-picker.tsx
Outdated
Show resolved
Hide resolved
{ ...compositeState } | ||
as={ Button } | ||
className={ classnames( className, { | ||
'is-pressed': isSelected, |
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.
From what you say, it sounds like passing undefined
would correctly remove the aria-pressed
attribute from the button.
Maybe something like this would work?
{ ...( isSelected ? { 'aria-pressed': undefined } : {} ) }
Let's still add an inline comment in case.
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 believe something went wrong with the latest trunk
merge.
Also, the last commit broke unit tests
3b1e00e
to
87a3b2b
Compare
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.
🚀
See #52255 for the dev note |
What?
This PR puts back the ability to use
CircularOptionPicker
as buttons, which was removed in #52255, while maintaining the new (now default)listbox
behaviour. (Closes #54239.)Why?
In #35292,
CircularOptionPicker
was refactored to present better semantics and keyboard navigation for picking options. However, as per #54239, it was discovered thatCircularOptionPicker
is not just used as an "option picker", but also as an access method for editing options. As such, we need to put the original functionality back in place, while maintaining the new functionality, so that the control can be used in either way.How?
A new
asButtons
flag has been added toCircularOptionPicker
, allowing component consumers to decide how it should be rendered, depending on context. This is passed on byColorPalette
,DuotonePicker
andGradientPicker
, the higher-order components that expose it.Testing Instructions
Superficially, nothing should change, and
CircularOptionPicker
should continue to behave as before. Clicking each option should fire anonClick
event, and in Storybook, the selected option should show as checked. TogglingasButtons
shouldn't impact this behaviour.Testing Instructions for Keyboard
With a keyboard, the default behaviour should also continue as before. The
CircularOptionPicker
control should still present as a single tab stop, and arrow keys should navigate between the different options. Semantically, it should still present as alistbox
with multipleoption
s, markedaria-selected
as appropriate.Enabling
asButtons
should change this, so that each option becomes its own tab stop. Thelistbox
semantics should be removed, and each option should be abutton
, markedaria-pressed
where needed.