Skip to content

Commit 533f997

Browse files
authored
StateLabel: Add labels to icon (#4764)
* fix accessibility issue first * stronger types * add tests, update snapshots * remove unused icon * remove unrelated changes * remove unrelated changes * run lint locally (sigh) * Create wild-actors-jam.md * bring back eslint-disable-line * add not planned for issueClosedNotPlanned * have to add an awkward member to the types * update snapshots
1 parent bd362cb commit 533f997

File tree

4 files changed

+53
-9
lines changed

4 files changed

+53
-9
lines changed

.changeset/wild-actors-jam.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@primer/react": patch
3+
---
4+
5+
StateLabel: Differentiate issue and pull request labels for screen readers

packages/react/src/StateLabel/StateLabel.tsx

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,19 @@ const octiconMap = {
3333
unavailable: AlertIcon,
3434
}
3535

36+
const labelMap: Record<keyof typeof octiconMap, 'Issue' | 'Issue, not planned' | 'Pull request' | ''> = {
37+
issueOpened: 'Issue',
38+
pullOpened: 'Pull request',
39+
issueClosed: 'Issue',
40+
issueClosedNotPlanned: 'Issue, not planned',
41+
pullClosed: 'Pull request',
42+
pullMerged: 'Pull request',
43+
draft: 'Pull request',
44+
issueDraft: 'Issue',
45+
pullQueued: 'Pull request',
46+
unavailable: '',
47+
}
48+
3649
const colorVariants = variant({
3750
prop: 'status',
3851
variants: {
@@ -120,7 +133,15 @@ function StateLabel({children, status, variant: variantProp = 'normal', ...rest}
120133
return (
121134
<StateLabelBase {...rest} variant={variantProp} status={status}>
122135
{/* eslint-disable-next-line @typescript-eslint/no-unnecessary-condition */}
123-
{status && <Octicon {...octiconProps} icon={octiconMap[status] || QuestionIcon} sx={{mr: 1}} />}
136+
{status && (
137+
<Octicon
138+
{...octiconProps}
139+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
140+
icon={octiconMap[status] || QuestionIcon}
141+
aria-label={labelMap[status]}
142+
sx={{mr: 1}}
143+
/>
144+
)}
124145
{children}
125146
</StateLabelBase>
126147
)

packages/react/src/StateLabel/__tests__/StateLabel.test.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,14 @@ describe('StateLabel', () => {
4343
it('renders children', () => {
4444
expect(render(<StateLabel status="issueOpened">hi</StateLabel>)).toMatchSnapshot()
4545
})
46+
47+
it('adds label to icon', () => {
48+
const screen1 = HTMLRender(<StateLabel status="issueOpened">Open</StateLabel>)
49+
expect(screen1.getByLabelText('Issue')).toBeInTheDocument() // svg
50+
expect(screen1.getByText('Open')).toBeInTheDocument() // text
51+
52+
const screen2 = HTMLRender(<StateLabel status="pullMerged">Merged</StateLabel>)
53+
expect(screen2.getByLabelText('Pull request')).toBeInTheDocument() // svg
54+
expect(screen2.getByText('Merged')).toBeInTheDocument() // text
55+
})
4656
})

packages/react/src/StateLabel/__tests__/__snapshots__/StateLabel.test.tsx.snap

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,12 @@ exports[`StateLabel renders children 1`] = `
3232
className="c0"
3333
>
3434
<svg
35-
aria-hidden="true"
35+
aria-label="Issue"
3636
className="c1"
3737
fill="currentColor"
3838
focusable="false"
3939
height={16}
40+
role="img"
4041
style={
4142
{
4243
"display": "inline-block",
@@ -91,11 +92,12 @@ exports[`StateLabel respects the status prop 1`] = `
9192
className="c0"
9293
>
9394
<svg
94-
aria-hidden="true"
95+
aria-label="Issue"
9596
className="c1"
9697
fill="currentColor"
9798
focusable="false"
9899
height={16}
100+
role="img"
99101
style={
100102
{
101103
"display": "inline-block",
@@ -149,11 +151,12 @@ exports[`StateLabel respects the status prop 2`] = `
149151
className="c0"
150152
>
151153
<svg
152-
aria-hidden="true"
154+
aria-label="Issue"
153155
className="c1"
154156
fill="currentColor"
155157
focusable="false"
156158
height={16}
159+
role="img"
157160
style={
158161
{
159162
"display": "inline-block",
@@ -207,11 +210,12 @@ exports[`StateLabel respects the status prop 3`] = `
207210
className="c0"
208211
>
209212
<svg
210-
aria-hidden="true"
213+
aria-label="Issue, not planned"
211214
className="c1"
212215
fill="currentColor"
213216
focusable="false"
214217
height={16}
218+
role="img"
215219
style={
216220
{
217221
"display": "inline-block",
@@ -262,11 +266,12 @@ exports[`StateLabel respects the status prop 4`] = `
262266
className="c0"
263267
>
264268
<svg
265-
aria-hidden="true"
269+
aria-label="Pull request"
266270
className="c1"
267271
fill="currentColor"
268272
focusable="false"
269273
height={16}
274+
role="img"
270275
style={
271276
{
272277
"display": "inline-block",
@@ -317,11 +322,12 @@ exports[`StateLabel respects the status prop 5`] = `
317322
className="c0"
318323
>
319324
<svg
320-
aria-hidden="true"
325+
aria-label="Pull request"
321326
className="c1"
322327
fill="currentColor"
323328
focusable="false"
324329
height={16}
330+
role="img"
325331
style={
326332
{
327333
"display": "inline-block",
@@ -372,11 +378,12 @@ exports[`StateLabel respects the variant prop 1`] = `
372378
className="c0"
373379
>
374380
<svg
375-
aria-hidden="true"
381+
aria-label="Issue"
376382
className="c1"
377383
fill="currentColor"
378384
focusable="false"
379385
height={16}
386+
role="img"
380387
style={
381388
{
382389
"display": "inline-block",
@@ -430,11 +437,12 @@ exports[`StateLabel respects the variant prop 2`] = `
430437
className="c0"
431438
>
432439
<svg
433-
aria-hidden="true"
440+
aria-label="Issue"
434441
className="c1"
435442
fill="currentColor"
436443
focusable="false"
437444
height={16}
445+
role="img"
438446
style={
439447
{
440448
"display": "inline-block",

0 commit comments

Comments
 (0)