-
Notifications
You must be signed in to change notification settings - Fork 673
ActionList: Add ActionList.GroupHeading component and update the existing internal Header component for better semantics
#3900
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
Changes from 5 commits
50340c0
f8f60f0
583b7da
255360f
e65f246
acc4d65
b929c00
11daf88
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| '@primer/react': minor | ||
| --- | ||
|
|
||
| ActionList: Add ActionList.GroupHeading component to label the group lists and update labelling semantics for accessibility |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -96,6 +96,146 @@ export const WithVisualListHeading = () => ( | |
| </ActionList> | ||
| ) | ||
|
|
||
| export const ListWithNewGroupHeadingAPI = () => ( | ||
| <ActionList> | ||
| <ActionList.Heading as="h2">List Heading</ActionList.Heading> | ||
| <ActionList.Group data-test-id="ActionList.Group"> | ||
| <ActionList.GroupHeading as="h3">Group 1 Heading</ActionList.GroupHeading> | ||
| <ActionList.Item onClick={() => {}}> | ||
| <ActionList.LeadingVisual> | ||
| <FileDirectoryIcon /> | ||
| </ActionList.LeadingVisual> | ||
| app/assets/modules | ||
| </ActionList.Item> | ||
| <ActionList.Item onClick={() => {}}> | ||
| <ActionList.LeadingVisual> | ||
| <FileDirectoryIcon /> | ||
| </ActionList.LeadingVisual> | ||
| src/react/components | ||
| </ActionList.Item> | ||
| <ActionList.Item onClick={() => {}}> | ||
| <ActionList.LeadingVisual> | ||
| <FileDirectoryIcon /> | ||
| </ActionList.LeadingVisual> | ||
| memex/shared-ui/components | ||
| </ActionList.Item> | ||
| <ActionList.Item onClick={() => {}}> | ||
| <ActionList.LeadingVisual> | ||
| <FileDirectoryIcon /> | ||
| </ActionList.LeadingVisual> | ||
| views/assets/modules | ||
| </ActionList.Item> | ||
| </ActionList.Group> | ||
|
|
||
| <ActionList.Group> | ||
| <ActionList.GroupHeading as="h3">Group 2 Heading</ActionList.GroupHeading> | ||
| <ActionList.Item onClick={() => {}}> | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure what our conventions are, but when would we use an empty handler for events versus using storybook actions?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a really good question. I am not really sure either. I find storybook actions useful when the story is about the action like the data table action stories you added are great examples for this use case in my opinion. The stories I added or the ones I mentioned here to update are not focusing on actions, they are focusing on semantics, visuals, and having group titles. This is why, I didn't worry about the action itself but I am more than happy to update them to use storybook actions if it is going to be helpful. What are your thoughts?? |
||
| <ActionList.LeadingVisual> | ||
| <PlusCircleIcon /> | ||
| </ActionList.LeadingVisual> | ||
| Owner | ||
| </ActionList.Item> | ||
| <ActionList.Item onClick={() => {}}> | ||
| <ActionList.LeadingVisual> | ||
| <PlusCircleIcon /> | ||
| </ActionList.LeadingVisual> | ||
| Symbol | ||
| </ActionList.Item> | ||
| <ActionList.Item onClick={() => {}}> | ||
| <ActionList.LeadingVisual> | ||
| <PlusCircleIcon /> | ||
| </ActionList.LeadingVisual> | ||
| Exclude archived | ||
| </ActionList.Item> | ||
| </ActionList.Group> | ||
| </ActionList> | ||
| ) | ||
|
|
||
| export const MenuWithNewGroupHeadingAPI = () => { | ||
| const [assignees, setAssignees] = React.useState(users.slice(0, 1)) | ||
|
|
||
| const toggleAssignee = (assignee: (typeof users)[number]) => { | ||
| const assigneeIndex = assignees.findIndex(a => a.login === assignee.login) | ||
|
|
||
| if (assigneeIndex === -1) setAssignees([...assignees, assignee]) | ||
| else setAssignees(assignees.filter((_, index) => index !== assigneeIndex)) | ||
| } | ||
|
|
||
| return ( | ||
| <ActionList selectionVariant="multiple" role="menu" showDividers aria-label="Reviewers"> | ||
| <ActionList.Group> | ||
| <ActionList.GroupHeading>Everyone</ActionList.GroupHeading> | ||
| {users.slice(2).map(user => ( | ||
| <ActionList.Item | ||
| role="menuitemcheckbox" | ||
| key={user.login} | ||
| selected={Boolean(assignees.find(assignee => assignee.login === user.login))} | ||
| aria-checked={Boolean(assignees.find(assignee => assignee.login === user.login))} | ||
| onSelect={() => toggleAssignee(user)} | ||
| > | ||
| <ActionList.LeadingVisual> | ||
| <Avatar src={`https://github.com/${user.login}.png`} /> | ||
| </ActionList.LeadingVisual> | ||
| {user.login} | ||
| <ActionList.Description>{user.name}</ActionList.Description> | ||
| </ActionList.Item> | ||
| ))} | ||
| </ActionList.Group> | ||
| </ActionList> | ||
| ) | ||
| } | ||
|
|
||
| export const ListboxWithNewGroupHeadingAPI = () => { | ||
| const [assignees, setAssignees] = React.useState(users.slice(0, 1)) | ||
|
|
||
| const toggleAssignee = (assignee: (typeof users)[number]) => { | ||
| const assigneeIndex = assignees.findIndex(a => a.login === assignee.login) | ||
|
|
||
| if (assigneeIndex === -1) setAssignees([...assignees, assignee]) | ||
| else setAssignees(assignees.filter((_, index) => index !== assigneeIndex)) | ||
| } | ||
|
|
||
| return ( | ||
| <ActionList selectionVariant="multiple" role="listbox" showDividers aria-label="Reviewers"> | ||
| <ActionList.Group> | ||
| <ActionList.GroupHeading>Everyone</ActionList.GroupHeading> | ||
| {users.slice(2).map(user => ( | ||
| <ActionList.Item | ||
| role="option" | ||
| key={user.login} | ||
| selected={Boolean(assignees.find(assignee => assignee.login === user.login))} | ||
| aria-checked={Boolean(assignees.find(assignee => assignee.login === user.login))} | ||
| onSelect={() => toggleAssignee(user)} | ||
| > | ||
| <ActionList.LeadingVisual> | ||
| <Avatar src={`https://github.com/${user.login}.png`} /> | ||
| </ActionList.LeadingVisual> | ||
| {user.login} | ||
| <ActionList.Description>{user.name}</ActionList.Description> | ||
| </ActionList.Item> | ||
| ))} | ||
| </ActionList.Group> | ||
| <ActionList.Group> | ||
| <ActionList.GroupHeading>Review Requested</ActionList.GroupHeading> | ||
| {users.slice(2).map(user => ( | ||
| <ActionList.Item | ||
| role="option" | ||
| key={user.login} | ||
| selected={Boolean(assignees.find(assignee => assignee.login === user.login))} | ||
| aria-checked={Boolean(assignees.find(assignee => assignee.login === user.login))} | ||
| onSelect={() => toggleAssignee(user)} | ||
| > | ||
| <ActionList.LeadingVisual> | ||
| <Avatar src={`https://github.com/${user.login}.png`} /> | ||
| </ActionList.LeadingVisual> | ||
| {user.login} | ||
| <ActionList.Description>{user.name}</ActionList.Description> | ||
| </ActionList.Item> | ||
| ))} | ||
| </ActionList.Group> | ||
| </ActionList> | ||
| ) | ||
| } | ||
| export const WithCustomHeading = () => ( | ||
| <> | ||
| <Heading as="h1" id="list-heading" sx={{fontSize: 3, marginX: 3}}> | ||
|
|
||
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 a documentation perspective, would it help to have the story name be more like
ListWithHeadingor something similar? Trying to think of when someone might be looking for how to do X (where X is adding a heading for a list) and having a story name that makes sense to them.The terminology "NewGroupedHeadingAPI" feels very clear for maintainers but from a user perspective might not make as much sense.
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 sorry I forgot to mention that I added these stories for dev/code review only to make the changes easily viewable. Since we are going to deprecate the
titleprop onActionList.Groupand our new API for providing group title isActionList.GroupHeading, I was thinking to update the stories that usetitleprop withActionList.GroupHeadingsuch as GroupWithFilledTitle and GroupWithSubtleTitle. Would that be helpful and enough you think for consumers to find how to add group headings? Also do you think we should still keep stories with thetitleprop at all? 🤔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 going to take these stories back in this PR. I am thinking to do a follow up one that adds a
@deprecatednotation to thetitleprop and update all title usages with the new API in stories and docs. Let me know if there is any concern!