Skip to content
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

Utilize aria-describedby on all ActionList descriptions #4666

Merged
merged 14 commits into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/lovely-days-march.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@primer/react': patch
---

ActionList: Adds `aria-labelledby` to `ActionList.TrailingVisual`, making it part of the accessible name of `ActionList.Item`
36 changes: 36 additions & 0 deletions packages/react/src/ActionList/ActionList.features.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import Box from '../Box'
import Label from '../Label'
import Heading from '../Heading'
import {AnchoredOverlay} from '../AnchoredOverlay'
import CounterLabel from '../CounterLabel'
import {
EyeIcon,
BookIcon,
Expand All @@ -25,6 +26,9 @@ import {
PeopleIcon,
FileDirectoryIcon,
PlusCircleIcon,
GitPullRequestIcon,
IssueOpenedIcon,
ProjectIcon,
LinkExternalIcon,
} from '@primer/octicons-react'
import {FeatureFlags} from '../FeatureFlags'
Expand Down Expand Up @@ -726,6 +730,38 @@ export const GroupWithFilledTitle = () => {
)
}

export const WithCustomTrailingVisuals = () => (
<ActionList>
<ActionList.Item>
<ActionList.LeadingVisual>
<IssueOpenedIcon />
</ActionList.LeadingVisual>
Issues
<ActionList.TrailingVisual>
<CounterLabel>20</CounterLabel>
</ActionList.TrailingVisual>
</ActionList.Item>
<ActionList.Item>
<ActionList.LeadingVisual>
<GitPullRequestIcon />
</ActionList.LeadingVisual>
PRs
<ActionList.TrailingVisual>
<CounterLabel>12</CounterLabel>
</ActionList.TrailingVisual>
</ActionList.Item>
<ActionList.Item>
<ActionList.LeadingVisual>
<ProjectIcon />
</ActionList.LeadingVisual>
Projects
<ActionList.TrailingVisual>
<CounterLabel>2</CounterLabel>
</ActionList.TrailingVisual>
</ActionList.Item>
</ActionList>
)

export const ActionListWithButtonSemantics = () => {
return (
<FeatureFlags flags={{primer_react_action_list_item_as_button: true}}>
Expand Down
22 changes: 17 additions & 5 deletions packages/react/src/ActionList/Item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ export const Item = React.forwardRef<HTMLLIElement, ActionListItemProps>(
const labelId = `${itemId}--label`
const inlineDescriptionId = `${itemId}--inline-description`
const blockDescriptionId = `${itemId}--block-description`
const trailingVisualId = `${itemId}--trailing-visual`
const inactiveWarningId = inactive && !showInactiveIndicator ? `${itemId}--warning-message` : undefined

const ButtonItemWrapper = React.forwardRef(({as: Component = 'button', children, ...props}, forwardedRef) => {
Expand Down Expand Up @@ -294,10 +295,14 @@ export const Item = React.forwardRef<HTMLLIElement, ActionListItemProps>(
'data-inactive': inactive ? true : undefined,
'data-loading': loading && !inactive ? true : undefined,
tabIndex: disabled || showInactiveIndicator ? undefined : 0,
'aria-labelledby': `${labelId} ${slots.inlineDescription ? inlineDescriptionId : ''}`,
'aria-describedby': slots.blockDescription
? [blockDescriptionId, inactiveWarningId].join(' ')
: inactiveWarningId,
'aria-labelledby': `${labelId} ${slots.trailingVisual ? trailingVisualId : ''} ${
slots.inlineDescription ? inlineDescriptionId : ''
}`,
'aria-describedby':
TylerJDev marked this conversation as resolved.
Show resolved Hide resolved
[slots.blockDescription ? blockDescriptionId : undefined, inactiveWarningId ?? undefined]
.filter(String)
.join(' ')
.trim() || undefined,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional: Don't think we need trim now that we are filtering strings

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this because we'd get aria-describedby=" " if none of the values were true. With the trim() || undefined, it will remove the attribute altogether since it's just an empty string at that point 🤔

...(includeSelectionAttribute && {[itemSelectionAttribute]: selected}),
role: itemRole,
id: itemId,
Expand Down Expand Up @@ -327,7 +332,14 @@ export const Item = React.forwardRef<HTMLLIElement, ActionListItemProps>(

return (
<ItemContext.Provider
value={{variant, disabled, inactive: Boolean(inactiveText), inlineDescriptionId, blockDescriptionId}}
value={{
variant,
disabled,
inactive: Boolean(inactiveText),
inlineDescriptionId,
blockDescriptionId,
trailingVisualId,
}}
>
<LiBox
ref={!buttonSemanticsFeatureFlag || listSemantics ? forwardedRef : null}
Expand Down
3 changes: 2 additions & 1 deletion packages/react/src/ActionList/Visuals.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,10 @@ export const LeadingVisual: React.FC<React.PropsWithChildren<VisualProps>> = ({s

export type ActionListTrailingVisualProps = VisualProps
export const TrailingVisual: React.FC<React.PropsWithChildren<VisualProps>> = ({sx = {}, ...props}) => {
const {variant, disabled, inactive} = React.useContext(ItemContext)
const {variant, disabled, inactive, trailingVisualId} = React.useContext(ItemContext)
return (
<Box
id={trailingVisualId}
as="span"
sx={merge(
{
Expand Down
1 change: 1 addition & 0 deletions packages/react/src/ActionList/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ type MenuItemProps = {
export type ItemContext = Pick<ActionListItemProps, 'variant' | 'disabled'> & {
inlineDescriptionId?: string
blockDescriptionId?: string
trailingVisualId?: string
inactive?: boolean
}

Expand Down
20 changes: 11 additions & 9 deletions packages/react/src/NavList/__snapshots__/NavList.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ exports[`NavList renders a simple list 1`] = `
>
<a
aria-current="page"
aria-labelledby=":r2:--label "
aria-labelledby=":r2:--label "
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could me make the filtering string on aria-labelledby as well so that we don't get these extra spaces 😅

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, definitely! I forgot I turned on auto merge 🤣, I can follow up in one of the PRs that I'll make for one of the sev-3 issues!

class="c3 c4"
href="/"
id=":r2:"
Expand All @@ -362,7 +362,7 @@ exports[`NavList renders a simple list 1`] = `
class="c1 c7"
>
<a
aria-labelledby=":r3:--label "
aria-labelledby=":r3:--label "
class="c3 c4"
href="/about"
id=":r3:"
Expand All @@ -385,7 +385,7 @@ exports[`NavList renders a simple list 1`] = `
class="c1 c7"
>
<a
aria-labelledby=":r4:--label "
aria-labelledby=":r4:--label "
class="c3 c4"
href="/contact"
id=":r4:"
Expand Down Expand Up @@ -803,7 +803,7 @@ exports[`NavList renders with groups 1`] = `
>
<a
aria-current="page"
aria-labelledby=":r8:--label "
aria-labelledby=":r8:--label "
class="c7 c8"
href="/getting-started"
id=":r8:"
Expand Down Expand Up @@ -846,7 +846,7 @@ exports[`NavList renders with groups 1`] = `
class="c5 c11"
>
<a
aria-labelledby=":ra:--label "
aria-labelledby=":ra:--label "
class="c7 c8"
href="/Avatar"
id=":ra:"
Expand Down Expand Up @@ -1274,7 +1274,7 @@ exports[`NavList.Item with NavList.SubNav does not have active styles if SubNav
<button
aria-controls=":r27:"
aria-expanded="true"
aria-labelledby=":r26:--label "
aria-labelledby=":r26:--label :r26:--trailing-visual "
class="c3 c4"
id=":r26:"
tabindex="0"
Expand All @@ -1294,6 +1294,7 @@ exports[`NavList.Item with NavList.SubNav does not have active styles if SubNav
</span>
<span
class="c1 c8"
id=":r26:--trailing-visual"
>
<svg
aria-hidden="true"
Expand Down Expand Up @@ -1324,7 +1325,7 @@ exports[`NavList.Item with NavList.SubNav does not have active styles if SubNav
>
<a
aria-current="page"
aria-labelledby=":r29:--label "
aria-labelledby=":r29:--label "
class="c12 c13"
href="#"
id=":r29:"
Expand Down Expand Up @@ -1773,7 +1774,7 @@ exports[`NavList.Item with NavList.SubNav has active styles if SubNav contains t
<button
aria-controls=":r21:"
aria-expanded="false"
aria-labelledby=":r20:--label "
aria-labelledby=":r20:--label :r20:--trailing-visual "
class="c3 c4"
id=":r20:"
tabindex="0"
Expand All @@ -1793,6 +1794,7 @@ exports[`NavList.Item with NavList.SubNav has active styles if SubNav contains t
</span>
<span
class="c1 c8"
id=":r20:--trailing-visual"
>
<svg
aria-hidden="true"
Expand Down Expand Up @@ -1823,7 +1825,7 @@ exports[`NavList.Item with NavList.SubNav has active styles if SubNav contains t
>
<a
aria-current="page"
aria-labelledby=":r23:--label "
aria-labelledby=":r23:--label "
class="c12 c13"
href="#"
id=":r23:"
Expand Down
Loading
Loading