Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
2c5e29e
initial impl for overflow behaviour
broccolinisoup Aug 31, 2022
fd409d4
scroll behaviour initial commit - wip
broccolinisoup Sep 1, 2022
b2f4738
overflow and scroll behaviour and styles
broccolinisoup Sep 6, 2022
ce08e12
introduce scroll arrow buttons
broccolinisoup Sep 7, 2022
5fa9687
scroll behaviour in dept
broccolinisoup Sep 11, 2022
9c8c8c7
revert back stories to original state
broccolinisoup Sep 11, 2022
26c4e7b
Fix types and align/variant issues
pksjce Sep 12, 2022
912fc49
Use separate component for arrow buttons
pksjce Sep 12, 2022
e5a0835
fade out affects on scroll ends
broccolinisoup Sep 12, 2022
917a335
type issues and some refactor
broccolinisoup Sep 13, 2022
e7aae17
style refactor & theming & scrollIntoView from primer behaviour
broccolinisoup Sep 13, 2022
2ca3a03
Update documentation
broccolinisoup Sep 14, 2022
b9451b0
Update documentation
broccolinisoup Sep 14, 2022
d650a99
add changeset
broccolinisoup Sep 14, 2022
cff64a6
Merge branch 'main' into broccolinisoup/underlineNav-overflow
broccolinisoup Sep 14, 2022
0918910
remove scroll story until finding a way to simulate coarse pointer
broccolinisoup Sep 14, 2022
33a7cc0
add single variant selection to ActionList
broccolinisoup Sep 14, 2022
1cebcd2
take more button into account when calculating & code review feedback
broccolinisoup Sep 18, 2022
eade73d
remove scroll behaviour - due to accessibility concerns
broccolinisoup Sep 18, 2022
50e8d78
hover state remove on mobile and improvments on more btn functionality
broccolinisoup Sep 18, 2022
7b58eae
Merge branch 'main' into broccolinisoup/underlineNav-overflow
broccolinisoup Sep 18, 2022
3b7ae57
remove prop controls and align story
broccolinisoup Sep 18, 2022
6688580
update tests and docs
broccolinisoup Sep 19, 2022
a8c4bf4
update docs
broccolinisoup Sep 19, 2022
a450308
overflow effect improvments
broccolinisoup Sep 19, 2022
a7624af
Revert "remove scroll behaviour - due to accessibility concerns"
broccolinisoup Sep 20, 2022
c9652ef
scroll behaviour feedback
broccolinisoup Sep 21, 2022
4a822ca
update tests
broccolinisoup Sep 21, 2022
bb75406
Merge branch 'main' into broccolinisoup/underlineNav-overflow
broccolinisoup Sep 21, 2022
e9142f7
keyboard navigation tab through
broccolinisoup Sep 22, 2022
de082d5
Merge branch 'main' into broccolinisoup/underlineNav-overflow
broccolinisoup Sep 22, 2022
580ce51
Update .changeset/sweet-eggs-complain.md
broccolinisoup Sep 28, 2022
54d2775
Merge branch 'main' into broccolinisoup/underlineNav-overflow
broccolinisoup Sep 28, 2022
1604fc2
Merge branch 'main' into broccolinisoup/underlineNav-overflow
broccolinisoup Sep 28, 2022
80e52e3
Update docs/content/drafts/UnderlineNav2.mdx
broccolinisoup Sep 28, 2022
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/sweet-eggs-complain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@primer/react': minor
---

UnderlineNav2: Introducing overflow behavior for fine and coarse pointer devices
114 changes: 88 additions & 26 deletions docs/content/drafts/UnderlineNav2.mdx
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
---
title: UnderlineNav v2
componentId: underline_nav_2
status: Draft
description: Use an underlined nav to allow tab like navigation with overflow behaviour in your UI.
source: https://github.com/primer/react/tree/main/src/UnderlineNav2
storybook: https://primer.style/react/storybook/?path=/story/layout-underlinenav
---

```js
import {UnderlineNav} from '@primer/react/drafts'
```

## Examples

### Simple

```jsx live drafts
<UnderlineNav label="simple nav">
<UnderlineNav>
<UnderlineNav.Item selected>Item 1</UnderlineNav.Item>
<UnderlineNav.Item>Item 2</UnderlineNav.Item>
<UnderlineNav.Item>Item 3</UnderlineNav.Item>
Expand All @@ -19,20 +26,88 @@ description: Use an underlined nav to allow tab like navigation with overflow be
### With icons

```jsx live drafts
<UnderlineNav label="simple nav with icons">
<UnderlineNav.Item selected leadingIcon={EyeIcon}>
Item 1
<UnderlineNav>
Copy link
Member Author

Choose a reason for hiding this comment

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

Instead of repeating the lines here, I wanted to write it with react like this but I am having a trouble to import UnderlineNav from drafts 😞 It is fine to import it on a different project like I tried to import to my primer prototype project but not sure what is going on here. Maybe we can pair tomorrow? @pksjce

<UnderlineNav.Item selected icon={CodeIcon}>
Code
</UnderlineNav.Item>
<UnderlineNav.Item icon={IssueOpenedIcon} counter={30}>
Issues
</UnderlineNav.Item>
<UnderlineNav.Item icon={GitPullRequestIcon} counter={3}>
Pull requests
</UnderlineNav.Item>
<UnderlineNav.Item icon={CommentDiscussionIcon}>Discussions</UnderlineNav.Item>
<UnderlineNav.Item icon={EyeIcon} counter={9}>
Actions
</UnderlineNav.Item>
<UnderlineNav.Item icon={EyeIcon} counter={7}>
Projects
</UnderlineNav.Item>
<UnderlineNav.Item>Item 2</UnderlineNav.Item>
</UnderlineNav>
```

### Small variant
### Overflow Behaviour

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)

#### Items without Icons

```jsx live drafts
<UnderlineNav label="small variant" variant="small">
<UnderlineNav.Item selected>Item 1</UnderlineNav.Item>
<UnderlineNav.Item>Item 2</UnderlineNav.Item>
<UnderlineNav>
<UnderlineNav.Item selected icon={CodeIcon}>
Code
</UnderlineNav.Item>
<UnderlineNav.Item icon={IssueOpenedIcon} counter={30}>
Issues
</UnderlineNav.Item>
<UnderlineNav.Item icon={GitPullRequestIcon} counter={3}>
Pull requests
</UnderlineNav.Item>
<UnderlineNav.Item icon={CommentDiscussionIcon}>Discussions</UnderlineNav.Item>
<UnderlineNav.Item icon={PlayIcon} counter={9}>
Actions
</UnderlineNav.Item>
<UnderlineNav.Item icon={ProjectIcon} counter={7}>
Projects
</UnderlineNav.Item>
<UnderlineNav.Item icon={ShieldLockIcon}>Security</UnderlineNav.Item>
<UnderlineNav.Item icon={GraphIcon}>Insights</UnderlineNav.Item>
<UnderlineNav.Item icon={GearIcon} counter={1}>
Settings
</UnderlineNav.Item>
</UnderlineNav>
```

#### Display `More` menu

If there is still overflow, the component will behave depending on the pointer.

```jsx live drafts
<UnderlineNav>
<UnderlineNav.Item selected icon={CodeIcon}>
Code
</UnderlineNav.Item>
<UnderlineNav.Item icon={IssueOpenedIcon} counter={30}>
Issues
</UnderlineNav.Item>
<UnderlineNav.Item icon={GitPullRequestIcon} counter={3}>
Pull requests
</UnderlineNav.Item>
<UnderlineNav.Item icon={CommentDiscussionIcon}>Discussions</UnderlineNav.Item>
<UnderlineNav.Item icon={EyeIcon} counter={9}>
Actions
</UnderlineNav.Item>
<UnderlineNav.Item icon={EyeIcon} counter={7}>
Projects
</UnderlineNav.Item>
<UnderlineNav.Item icon={EyeIcon}>Security</UnderlineNav.Item>
<UnderlineNav.Item icon={EyeIcon} counter={14}>
Insights
</UnderlineNav.Item>
<UnderlineNav.Item icon={EyeIcon} counter={1}>
Settings
</UnderlineNav.Item>
<UnderlineNav.Item icon={EyeIcon}>Wiki</UnderlineNav.Item>
</UnderlineNav>
```

Expand All @@ -44,19 +119,6 @@ description: Use an underlined nav to allow tab like navigation with overflow be
<PropsTableRow name="aria-label" type="string" />
<PropsTableRow name="aria-labelledby" type="string" />
<PropsTableRow name="aria-describedby" type="string" />
<PropsTableRow
name="overflow"
type="'auto' | 'menu' | 'scroll'"
defaultValue="auto"
description="Controls the type of overflow behaviour in smaller screens"
/>
<PropsTableRow name="align" type="right | left" defaultValue="left" description="The alignment of the nav links" />
<PropsTableRow
name="variant"
type="default | small"
defaultValue="default"
description="The alignment of the nav links"
/>
<PropsTableRow
name="afterSelect"
type="(event) => void"
Expand All @@ -68,7 +130,7 @@ description: Use an underlined nav to allow tab like navigation with overflow be
### UnderlineNav.Item

<PropsTable>
<PropsTableRow name="leadingIcon" type="Component" description="The leading icon comes before item label" />
<PropsTableRow name="icon" type="Component" description="The leading icon comes before item label" />
<PropsTableRow name="selected" type="boolean" description="Whether the link is selected" />
<PropsTableRow
name="onSelect"
Expand All @@ -89,9 +151,9 @@ description: Use an underlined nav to allow tab like navigation with overflow be
<ComponentChecklist
items={{
propsDocumented: true,
noUnnecessaryDeps: false,
adaptsToThemes: false,
adaptsToScreenSizes: false,
noUnnecessaryDeps: true,
adaptsToThemes: true,
adaptsToScreenSizes: true,
fullTestCoverage: false,
usedInProduction: false,
usageExamplesDocumented: false,
Expand Down
63 changes: 58 additions & 5 deletions src/UnderlineNav2/UnderlineNav.test.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,30 @@
import React from 'react'
import '@testing-library/jest-dom/extend-expect'
import {render} from '@testing-library/react'
import {fireEvent, render} from '@testing-library/react'
import {CodeIcon, EyeIcon} from '@primer/octicons-react'

import {UnderlineNav} from '.'

// window.matchMedia() is not implemented by JSDOM so we have to create a mock:
// https://jestjs.io/docs/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation(query => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(), // deprecated
removeListener: jest.fn(), // deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn()
}))
})

Object.defineProperty(window.Element.prototype, 'scrollTo', {
value: jest.fn(),
writable: true
})
describe('UnderlineNav', () => {
test('selected nav', () => {
const {getByText} = render(
Expand All @@ -30,15 +51,47 @@ describe('UnderlineNav', () => {

expect(nav.getAttribute('aria-label')).toBe('Test nav')
})
test('respect align prop', () => {
test('with icons', () => {
const {container} = render(
<UnderlineNav label="Test nav">
<UnderlineNav.Item icon={CodeIcon}>Code</UnderlineNav.Item>
<UnderlineNav.Item icon={EyeIcon} counter={6}>
Issues
</UnderlineNav.Item>
<UnderlineNav.Item>Pull Request</UnderlineNav.Item>
</UnderlineNav>
)
const nav = container.getElementsByTagName('nav')[0]
expect(nav.getElementsByTagName('svg').length).toEqual(2)
})
test('should fire onSelect on click and keypress', async () => {
const onSelect = jest.fn()
const {getByText} = render(
<UnderlineNav label="Test nav">
<UnderlineNav.Item onSelect={onSelect}>Item 1</UnderlineNav.Item>
<UnderlineNav.Item onSelect={onSelect}>Item 2</UnderlineNav.Item>
<UnderlineNav.Item onSelect={onSelect}>Item 3</UnderlineNav.Item>
</UnderlineNav>
)
const item = getByText('Item 1')
fireEvent.click(item)
expect(onSelect).toHaveBeenCalledTimes(1)
fireEvent.keyPress(item, {key: 'Enter', code: 13, charCode: 13})
expect(onSelect).toHaveBeenCalledTimes(2)
})
test('respect counter prop', () => {
const {getByText} = render(
<UnderlineNav label="Test nav" align="right">
<UnderlineNav.Item selected>Item 1</UnderlineNav.Item>
<UnderlineNav.Item counter={8} selected>
Item 1
</UnderlineNav.Item>
<UnderlineNav.Item>Item 2</UnderlineNav.Item>
<UnderlineNav.Item>Item 3</UnderlineNav.Item>
</UnderlineNav>
)
const nav = container.getElementsByTagName('nav')[0]
expect(nav).toHaveStyle(`justify-content:flex-end`)
const item = getByText('Item 1').closest('a')
const counter = item?.getElementsByTagName('span')[2]
expect(counter?.className).toContain('CounterLabel')
expect(counter?.textContent).toBe('8')
})
})
Loading