-
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 ToggleMultipleGroupControl component #45128
base: trunk
Are you sure you want to change the base?
Conversation
Open in CodeSandbox Web Editor | VS Code | VS Code Insiders |
0338cae
to
6f4b7a6
Compare
7327210
to
276c808
Compare
9588263
to
5591154
Compare
# Conflicts: # packages/components/src/toggle-group-control/toggle-group-control/as-button-group.tsx # packages/components/src/toggle-group-control/toggle-group-control/as-radio-group.tsx # packages/components/src/toggle-group-control/types.ts # Conflicts: # packages/components/src/toggle-group-control/toggle-group-control-option-base/component.tsx # packages/components/src/toggle-group-control/toggle-group-control-option-base/styles.ts
# Conflicts: # packages/components/src/toggle-group-control/toggle-group-control-option-base/styles.ts
276c808
to
1d41c30
Compare
d9121c2
to
89e4acf
Compare
Size Change: +217 B (0%) Total Size: 1.28 MB
ℹ️ View Unchanged
|
@@ -92,7 +93,7 @@ function UnforwardedToggleGroupControlAsButtonGroup( | |||
containerWidth={ sizes.width } | |||
isAdaptiveWidth={ isAdaptiveWidth } | |||
/> | |||
{ children } | |||
<HStack spacing={ 1 }>{ children }</HStack> |
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.
Gap increased to 8px:
@@ -12,6 +12,12 @@ import type { | |||
ToggleGroupControlProps, | |||
ToggleGroupControlOptionBaseProps, | |||
} from '../types'; | |||
import { BACKDROP_BG_COLOR } from '../toggle-group-control/styles'; |
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.
The changes in this style file is to allow a pressed button's black background to remain "static", unlike the animated roving background in the single-select variant.
Thanks for reviewing! I increased the button gap to 8px. The button size will be tweaked separately (#45532).
No, this is not for the block toolbar. Just for sidebar controls like Decoration, Line Height, that kind of thing. |
Sounds good. But conceptually is it the same mechanism, or different? UI wise they should be the same, but I'm curiuos of the inner workings, if you don't mind. In any case, this seems good to me, since we're following up separately on the 32x32 footprint. Just needs a code review 👍 👍 |
I love this question! Semantically, they are similar in that they both contain When we zoom out from the button and consider the whole, they become conceptually different. In the Toolbar, keyboard navigation is completely managed by the Toolbar itself, and the buttons are not semantically grouped. In a sense, they are each just independent buttons in a toolbar that happen to be visually separated by vertical dividers. In ToggleGroupControl, the buttons are semantically grouped together ( |
Thank you for indulging my question! 🙏 |
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! We're getting closer and closer :)
const singleSelectButtonProps = { | ||
'aria-pressed': isPressed, | ||
onClick: () => | ||
otherContextProps.setState( isPressed ? undefined : 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.
Previously, undefined
was passed as the new state only when isDeselectable === true
— is it ok to remove that check?
export { | ||
ToggleMultipleGroupControl as __experimentalToggleMultipleGroupControl, | ||
ToggleMultipleGroupControlOptionIcon as __experimentalToggleMultipleGroupControlOptionIcon, | ||
} from './toggle-multiple-group-control'; |
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.
With @adamziel we recently discussed using the IS_GUTENBERG_PLUGIN
env variable, so that we can prevent these experimental components from making their way in a Core release, effectively keeping them truly experimental.
Adam, could you help us understand a bit better what using IS_GUTENBERG_PLUGIN
would look like in this scenario? Thank you 🙏
* | ||
* @default false | ||
*/ | ||
isMultiple?: boolean; |
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.
Do we need to update ToggleGroupControlOptionBase
and ToggleGroupControlOptionIcon
's READMEs with docs about this new prop?
forwardedRef: ForwardedRef< any > | ||
) { | ||
const { | ||
onChange, // omit |
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.
What's this inline comment about ?
/** | ||
* Listen to click events to manage the `isPressed` state. | ||
*/ | ||
onClick: React.MouseEventHandler< HTMLButtonElement >; |
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.
Thought: if we allow this component to be polymorphic, then we're not guaranteed about the HTMLButtonElement
part on the onClick
event?
{ | ||
isPressed, | ||
...otherProps | ||
}: WordPressComponentProps< |
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 explicitly Omit
the aria-pressed
attribute from WordPressComponentProps
here?
|
||
### `value`: `string | number` | ||
|
||
The unique key of the option. |
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.
Could using key
be confusing in the context of a React component?
|
||
const contextProviderValue = { | ||
ToggleGroupControlOptionBase: { | ||
isMultiple: true, |
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.
Instead of using the context system, could we instead pass the isMultiple
prop directly to the ToggleGroupControlOptionIcon
inside ToggleMultipleGroupControlOptionIcon
?
Maybe it could be a bit easier to discover for a developer? WDYT ? (not a strong opinion, though)
Extracted from #44168 (where a high-level review was completed first)
What?
Add a ToggleMultipleGroupControl component.
Why?
We need a component that looks like ToggleGroupControl, but allows multiple selection. Splitting this variant into a thin wrapper component keeps the API simpler. (See #44168 for details)
How?
Exports two new components — ToggleMultipleGroupControl and ToggleMultipleGroupControlOptionIcon — that are just thin wrappers around the original ToggleGroupControl components. Conditional logic is handled internally, and the API surface is kept simple.
From a DX standpoint, the main difference is that the consumer needs to manage the
isPressed
states on their own for each of the option buttons via anonClick
handler. This seems like more work, but it's actually a simpler DX compared to having the main ToggleMultipleGroupControl component handle all the states and centrally and trying to read them through a singleonChange
.Testing Instructions
npm run storybook:dev
and check the docs/stories for ToggleMultipleGroupControl.✅ Unit tests pass
Screenshots or screencast