Skip to content

Commit e03b5e4

Browse files
[UnderlineNav2]: Deprecate coarse input detection and its scroll behaviour (A11y sign-off remediations) (#2447)
* Discard the pointer types and scroll behaviour * add changeset * remove arrow btn styles * introduce gap between items and remove 4px padding around the links * [UnderlineNav2]: React router implementation fixes & docs improvement (#2448) * react router implementation fixes * add changeset * [UnderlineNav2]: Add string type to the `counter` prop and display loading counter for all (#2449) * string type for counters and fix loading issue * add changeset * improve docs * update animation details * Inverte the pulse effect Co-authored-by: Daniel Guillan <[email protected]> Co-authored-by: Daniel Guillan <[email protected]> * Remove unnecessary styles (scroll behaviour styles) * improve docs Co-authored-by: Daniel Guillan <[email protected]>
1 parent ddac91d commit e03b5e4

File tree

13 files changed

+189
-409
lines changed

13 files changed

+189
-409
lines changed

.changeset/polite-dodos-behave.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@primer/react': minor
3+
---
4+
5+
UnderlineNav2: Add support and docs for react router configuration

.changeset/tough-peas-sort.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+
UnderlineNav2: Add string type to the `counter` prop and display loading counter for all

.changeset/witty-apples-think.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@primer/react': minor
3+
---
4+
5+
UnderlineNav2: Deprecate coarse input detection and its scroll behaviour

docs/content/drafts/UnderlineNav2.mdx

Lines changed: 79 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ import {UnderlineNav} from '@primer/react/drafts'
1717

1818
```jsx live drafts
1919
<UnderlineNav aria-label="Repository">
20-
<UnderlineNav.Item selected>Item 1</UnderlineNav.Item>
21-
<UnderlineNav.Item>Item 2</UnderlineNav.Item>
22-
<UnderlineNav.Item>Item 3</UnderlineNav.Item>
20+
<UnderlineNav.Item selected>Code</UnderlineNav.Item>
21+
<UnderlineNav.Item>Issues</UnderlineNav.Item>
22+
<UnderlineNav.Item>Pull Requests</UnderlineNav.Item>
2323
</UnderlineNav>
2424
```
2525

@@ -48,96 +48,99 @@ import {UnderlineNav} from '@primer/react/drafts'
4848

4949
### Overflow Behaviour
5050

51-
When overflow occurs, the component first hides icons if present to optimize for space and show as many items as possible. (Only for fine pointer devices)
52-
53-
#### Items Without Icons
54-
55-
```jsx live drafts
56-
<UnderlineNav aria-label="Repository">
57-
<UnderlineNav.Item selected icon={CodeIcon}>
58-
Code
59-
</UnderlineNav.Item>
60-
<UnderlineNav.Item icon={IssueOpenedIcon} counter={30}>
61-
Issues
62-
</UnderlineNav.Item>
63-
<UnderlineNav.Item icon={GitPullRequestIcon} counter={3}>
64-
Pull Requests
65-
</UnderlineNav.Item>
66-
<UnderlineNav.Item icon={CommentDiscussionIcon}>Discussions</UnderlineNav.Item>
67-
<UnderlineNav.Item icon={PlayIcon} counter={9}>
68-
Actions
69-
</UnderlineNav.Item>
70-
<UnderlineNav.Item icon={ProjectIcon} counter={7}>
71-
Projects
72-
</UnderlineNav.Item>
73-
<UnderlineNav.Item icon={ShieldLockIcon}>Security</UnderlineNav.Item>
74-
<UnderlineNav.Item icon={GraphIcon}>Insights</UnderlineNav.Item>
75-
<UnderlineNav.Item icon={GearIcon} counter={1}>
76-
Settings
77-
</UnderlineNav.Item>
78-
</UnderlineNav>
51+
Component first hides icons if they present to optimize for space and show as many items as possible. If there is still an overflow, it will display the items that don't fit in the `More` menu.
52+
53+
```javascript noinline live drafts
54+
const Navigation = () => {
55+
const items = [
56+
{navigation: 'Code', icon: CodeIcon},
57+
{navigation: 'Issues', icon: IssueOpenedIcon, counter: 120},
58+
{navigation: 'Pull Requests', icon: GitPullRequestIcon, counter: 13},
59+
{navigation: 'Discussions', icon: CommentDiscussionIcon, counter: 5},
60+
{navigation: 'Actions', icon: PlayIcon, counter: 4},
61+
{navigation: 'Projects', icon: ProjectIcon, counter: 9},
62+
{navigation: 'Insights', icon: GraphIcon},
63+
{navigation: 'Settings', icon: GearIcon, counter: 10},
64+
{navigation: 'Security', icon: ShieldLockIcon}
65+
]
66+
const [selectedIndex, setSelectedIndex] = React.useState(0)
67+
return (
68+
<Box sx={{width: 750, border: '1px solid', borderBottom: 0, borderColor: 'border.default'}}>
69+
<UnderlineNav aria-label="Repository">
70+
{items.map((item, index) => (
71+
<UnderlineNav.Item
72+
key={item.navigation}
73+
icon={item.icon}
74+
selected={index === selectedIndex}
75+
onSelect={e => {
76+
setSelectedIndex(index)
77+
e.preventDefault()
78+
}}
79+
counter={item.counter}
80+
>
81+
{item.navigation}
82+
</UnderlineNav.Item>
83+
))}
84+
</UnderlineNav>
85+
</Box>
86+
)
87+
}
88+
render(<Navigation />)
7989
```
8090

81-
#### Display `More` Menu
82-
83-
If there is still overflow, the component will behave depending on the pointer.
91+
### Loading State For Counters
8492

8593
```jsx live drafts
86-
<UnderlineNav aria-label="Repository">
87-
<UnderlineNav.Item selected icon={CodeIcon}>
94+
<UnderlineNav aria-label="Repository" loadingCounters={true}>
95+
<UnderlineNav.Item counter={4} selected>
8896
Code
8997
</UnderlineNav.Item>
90-
<UnderlineNav.Item icon={IssueOpenedIcon} counter={30}>
91-
Issues
92-
</UnderlineNav.Item>
93-
<UnderlineNav.Item icon={GitPullRequestIcon} counter={3}>
94-
Pull Requests
95-
</UnderlineNav.Item>
96-
<UnderlineNav.Item icon={CommentDiscussionIcon}>Discussions</UnderlineNav.Item>
97-
<UnderlineNav.Item icon={EyeIcon} counter={9}>
98-
Actions
99-
</UnderlineNav.Item>
100-
<UnderlineNav.Item icon={EyeIcon} counter={7}>
101-
Projects
102-
</UnderlineNav.Item>
103-
<UnderlineNav.Item icon={EyeIcon}>Security</UnderlineNav.Item>
104-
<UnderlineNav.Item icon={EyeIcon} counter={14}>
105-
Insights
106-
</UnderlineNav.Item>
107-
<UnderlineNav.Item icon={EyeIcon} counter={1}>
108-
Settings
109-
</UnderlineNav.Item>
110-
<UnderlineNav.Item icon={EyeIcon}>Wiki</UnderlineNav.Item>
98+
<UnderlineNav.Item counter={44}>Issues</UnderlineNav.Item>
99+
<UnderlineNav.Item>Pull Requests</UnderlineNav.Item>
111100
</UnderlineNav>
112101
```
113102

114-
### Loading state for counters
103+
### With React Router
115104

116-
```jsx live drafts
117-
<UnderlineNav aria-label="Repository" loadingCounters={true}>
118-
<UnderlineNav.Item counter={4} selected>
119-
Item 1
120-
</UnderlineNav.Item>
121-
<UnderlineNav.Item counter={44}>Item 2</UnderlineNav.Item>
122-
<UnderlineNav.Item>Item 3</UnderlineNav.Item>
123-
</UnderlineNav>
105+
```jsx
106+
import {Link} from 'react-router-dom'
107+
import {UnderlineNav} from '@primer/react/drafts'
108+
const Navigation = () => {
109+
return (
110+
<UnderlineNav aria-label="Repository">
111+
<UnderlineNav.Item as={Link} to="code" counter={4} selected>
112+
Code
113+
</UnderlineNav.Item>
114+
<UnderlineNav.Item counter={44} as={Link} to="issues">
115+
Issues
116+
</UnderlineNav.Item>
117+
<UnderlineNav.Item as={Link} to="pulls">
118+
Pull Requests
119+
</UnderlineNav.Item>
120+
</UnderlineNav>
121+
)
122+
}
124123
```
125124

126125
## Props
127126

128127
### UnderlineNav
129128

130129
<PropsTable>
130+
<PropsTableRow name="children" required type="UnderlineNav.Item[]" />
131131
<PropsTableRow
132132
name="aria-label"
133133
type="string"
134-
description="A unique name for the rendered 'nav' landmark. It will also be used to label the arrow buttons that control the scroll behaviour on coarse pointer devices. (I.e. 'Scroll ${aria-label} left/right')"
134+
description="A unique name for the rendered 'nav' landmark. It will also be used to label the arrow
135+
buttons that control the scroll behaviour on coarse pointer devices. (I.e.
136+
'Scroll ${aria-label} left/right')
137+
"
135138
/>
136139
<PropsTableRow
137140
name="loadingCounters"
138141
type="boolean"
139142
defaultValue="false"
140-
description="Whether all of the counters are in loading state"
143+
description="Whether the navigation items are in loading state. Component waits for all the counters to finish loading to prevent multiple layout shifts."
141144
/>
142145
<PropsTableRow
143146
name="afterSelect"
@@ -150,18 +153,23 @@ If there is still overflow, the component will behave depending on the pointer.
150153
### UnderlineNav.Item
151154

152155
<PropsTable>
156+
<PropsTableRow
157+
name="href"
158+
type="string"
159+
description="The URL that the item navigates to. 'href' is passed to the underlying '<a>' element. If 'as' is specified, the component may need different props and 'href' is ignored. (Required prop for the react router is 'to' for example)"
160+
/>
153161
<PropsTableRow name="icon" type="Component" description="The leading icon comes before item label" />
154162
<PropsTableRow name="selected" type="boolean" description="Whether the link is selected" />
155163
<PropsTableRow
156164
name="onSelect"
157165
type="(event) => void"
158-
description="The handler that gets called when a nav link is selected"
166+
description="The handler that gets called when a nav link is selected. For example, a manual route binding can be done here(I.e. 'navigate(href)' for the react router.)"
159167
/>
160168
<PropsTableRow
161169
name="as"
162-
type="string | Component"
170+
type="string | React.ElementType"
163171
defaultValue="a"
164-
description="What kind of component needs to be rendered"
172+
description="The underlying element to render — either a HTML element name or a React component."
165173
/>
166174
<PropsTableSxRow />
167175
</PropsTable>

src/UnderlineNav2/LoadingCounter.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ import styled, {keyframes} from 'styled-components'
22
import {get} from '../constants'
33

44
const loading = keyframes`
5-
from { opacity: 0.4; }
6-
to { opacity: 0.8; }
5+
from { opacity: 1; }
6+
to { opacity: 0.2; }
77
`
88

99
export const LoadingCounter = styled.span`
10-
animation: ${loading} 1.2s linear infinite alternate;
11-
background-color: ${get('colors.neutral.emphasis')};
10+
animation: ${loading} 1.2s ease-in-out infinite alternate;
11+
background-color: ${get('colors.neutral.muted')};
1212
border-color: ${get('colors.border.default')};
1313
width: 1.5rem;
1414
height: 1rem; // 16px

src/UnderlineNav2/UnderlineNav.test.tsx

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,6 @@ Object.defineProperty(window, 'matchMedia', {
3030
}))
3131
})
3232

33-
Object.defineProperty(window.Element.prototype, 'scrollTo', {
34-
value: jest.fn(),
35-
writable: true
36-
})
37-
3833
const ResponsiveUnderlineNav = ({
3934
selectedItemText = 'Code',
4035
loadingCounters = false

0 commit comments

Comments
 (0)