1
1
mirror of https://github.com/primer/css.git synced 2024-11-29 14:14:26 +03:00

NavigationList (#1905)

* here we go!

* nav list

* divider

* collapsible

* here lies breaking changes

* item simplification

* update examples

* move to patterns

* tree view looks broken but its not

* remove notes

* stash

* action list component stories

* fix sub item

* revert treeview to original markup

* tree view readme

* story chaining

* cleanup + readme

* lint

* tree story fix

* Create quiet-walls-walk.md

* address feedback
This commit is contained in:
Katie Langerman 2022-02-11 09:47:56 -08:00 committed by GitHub
parent bb8895db89
commit 50221a5486
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 3596 additions and 2851 deletions

View File

@ -0,0 +1,5 @@
---
"@primer/css": minor
---
Refactors NavigationList to better handle accessibility. Backwards compatible for TreeView CSS.

View File

@ -7,11 +7,11 @@ bundle: action-list
storybook: https://primer.style/css/storybook/?path=/story/components-actionlist-actionlistitem--playground
---
Reference the [Action list interface guidelines](https://primer.style/design/components/action-list) for details on where and how to use Action List.
Reference the [Action list interface guidelines](https://primer.style/design/components/action-list) for details on where and how to use Action list.
## Action list
Action List is a `ul` list designed to contain Action List Items.
Action list is a `ul` list designed to contain list items.
### Variants
@ -20,6 +20,7 @@ Action List is a `ul` list designed to contain Action List Items.
| `ActionList` | Default styles |
| `ActionList--divided` | Show dividers between items |
| `ActionList--subGroup` | If Action List is nested as a sub-list |
| `ActionList--tree` | Tree-view specific styles |
#### Default
@ -27,12 +28,12 @@ Action List is a `ul` list designed to contain Action List Items.
<ul class="ActionList">
<li class="ActionList-item">
<span class="ActionList-content">
<span class="ActionList-item-label">Item label</span>
<span class="ActionList-item-label">Action list item</span>
</span>
</li>
<li class="ActionList-item">
<span class="ActionList-content">
<span class="ActionList-item-label">Item label</span>
<span class="ActionList-item-label">Action list item</span>
</span>
</li>
</ul>
@ -41,21 +42,21 @@ Action List is a `ul` list designed to contain Action List Items.
#### Item dividers
```html live
<ul class="ActionList ActionList--divided" aria-label="Menu description">
<ul class="ActionList ActionList--divided">
<li class="ActionList-item">
<span class="ActionList-content">
<span class="ActionList-item-label">Action list item</span>
</span>
<a href="/" class="ActionList-content">
<span class="ActionList-item-label">Item 1</span>
</a>
</li>
<li class="ActionList-item">
<span class="ActionList-content">
<span class="ActionList-item-label">Action list item</span>
</span>
<a href="/" class="ActionList-content">
<span class="ActionList-item-label">Item 2</span>
</a>
</li>
<li class="ActionList-item">
<span class="ActionList-content">
<span class="ActionList-item-label">Action list item</span>
</span>
<li class="ActionList-item">
<a href="/" class="ActionList-content">
<span class="ActionList-item-label">Item 3</span>
</a>
</li>
</ul>
```
@ -63,30 +64,41 @@ Action List is a `ul` list designed to contain Action List Items.
#### Nested sub list
```html live
<ul class="ActionList" aria-label="Menu description">
<li class="ActionList-item">
<span class="ActionList-content">
<span class="ActionList-item-label">Action list item</span>
</span>
</li>
<li class="ActionList-item ActionList-item--hasSubItem">
<span class="ActionList-content">
<span class="ActionList-item-label">Sub menu label</span>
</span>
<ul class="ActionList ActionList--subGroup" aria-label="Menu description">
<li class="ActionList-item ActionList-item--subItem">
<span class="ActionList-content">
<span class="ActionList-item-label">Sub menu item</span>
</span>
</li>
<li class="ActionList-item ActionList-item--subItem">
<span class="ActionList-content">
<span class="ActionList-item-label">Sub menu item</span>
</span>
<nav>
<li class="ActionList-sectionDivider">
<h3 class="ActionList-sectionDivider-title" id="group-id-1">Access</h3>
</li>
<ul class="ActionList" role="list" aria-labelledby="group-id-1">
<li class="ActionList-item ActionList-item--hasSubItem">
<button aria-expanded="true" class="ActionList-content ActionList-content--visual16 ActionList-content--hasActiveSubItem">
<span class="ActionList-item-visual ActionList-item-visual--leading">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M1.5 2.75a.25.25 0 01.25-.25h8.5a.25.25 0 01.25.25v5.5a.25.25 0 01-.25.25h-3.5a.75.75 0 00-.53.22L3.5 11.44V9.25a.75.75 0 00-.75-.75h-1a.25.25 0 01-.25-.25v-5.5zM1.75 1A1.75 1.75 0 000 2.75v5.5C0 9.216.784 10 1.75 10H2v1.543a1.457 1.457 0 002.487 1.03L7.061 10h3.189A1.75 1.75 0 0012 8.25v-5.5A1.75 1.75 0 0010.25 1h-8.5zM14.5 4.75a.25.25 0 00-.25-.25h-.5a.75.75 0 110-1.5h.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0114.25 12H14v1.543a1.457 1.457 0 01-2.487 1.03L9.22 12.28a.75.75 0 111.06-1.06l2.22 2.22v-2.19a.75.75 0 01.75-.75h1a.25.25 0 00.25-.25v-5.5z"></path></svg>
</span>
<span class="ActionList-item-label">Moderation</span>
<span class="ActionList-item-action ActionList-item-action--trailing">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16" class="ActionList-item-collapseIcon"><path fill-rule="evenodd" d="M12.78 6.22a.75.75 0 010 1.06l-4.25 4.25a.75.75 0 01-1.06 0L3.22 7.28a.75.75 0 011.06-1.06L8 9.94l3.72-3.72a.75.75 0 011.06 0z"></path></svg>
</span>
</button>
<ul class="ActionList ActionList--subGroup" role="list">
<li class="ActionList-item ActionList-item--subItem">
<a href="#" class="ActionList-content">
<span class="ActionList-item-label">Interaction limits</span>
</a>
</li>
<li class="ActionList-item ActionList-item--navActive ActionList-item--subItem">
<a href="#" aria-current="page" class="ActionList-content">
<span class="ActionList-item-label">Code review limits</span>
</a>
</li>
<li class="ActionList-item ActionList-item--subItem">
<a href="#" class="ActionList-content">
<span class="ActionList-item-label">Reported content</span>
</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</nav>
```
@ -106,7 +118,11 @@ List item `li` for separating groups of content
```html live
<ul class="ActionList">
<li class="ActionList-sectionDivider" role="separator"></li>
<li
class="ActionList-sectionDivider"
role="separator"
aria-hidden="true"
></li>
</ul>
```
@ -114,65 +130,71 @@ List item `li` for separating groups of content
```html live
<ul class="ActionList">
<li class="ActionList-sectionDivider ActionList-sectionDivider--filled" role="separator"></li>
<li
class="ActionList-sectionDivider ActionList-sectionDivider--filled"
role="separator"
aria-hidden="true"
></li>
</ul>
```
### Divider with label text
When using a section label for a group, give the `li` an id to be referenced by the group `ul`
When using a section label for a group, give the `h3` an id to be referenced by the group `ul`
#### Filled with section label
```html live
<ul class="ActionList">
<li class="ActionList-sectionDivider ActionList-sectionDivider--filled" role="presentation" id="nested-group-id" aria-hidden="true">Section label</li>
<li class="ActionList-item">
<ul class="ActionList" aria-labelledby="nested-group-id">
<li class="ActionList-item">
<a href="/" class="ActionList-content">
<span class="ActionList-item-label">Group Item</span>
</a>
</li>
</ul>
<ul>
<li class="ActionList-sectionDivider ActionList-sectionDivider--filled">
<h3 class="ActionList-sectionDivider-title" id="group-id">
List group title
</h3>
</li>
<ul class="ActionList" aria-labelledby="group-id">
<li class="ActionList-item">
<a href="/" class="ActionList-content">
<span class="ActionList-item-label">Group Item</span>
</a>
</li>
</ul>
</ul>
```
#### Default with section label
```html live
<ul class="ActionList">
<li class="ActionList-sectionDivider" role="presentation" id="nested-group-id" aria-hidden="true">Section label</li>
<li class="ActionList-item">
<ul class="ActionList" aria-labelledby="nested-group-id">
<li class="ActionList-item">
<a href="/" class="ActionList-content">
<span class="ActionList-item-label">Group Item</span>
</a>
</li>
</ul>
<ul>
<li class="ActionList-sectionDivider">
<h3 class="ActionList-sectionDivider-title" id="group-id">
List group title
</h3>
</li>
<ul class="ActionList" aria-labelledby="group-id">
<li class="ActionList-item">
<a href="/" class="ActionList-content">
<span class="ActionList-item-label">Group Item</span>
</a>
</li>
</ul>
</ul>
```
#### Default with section label + description
```html live
<ul class="ActionList">
<li class="ActionList-sectionDivider" role="presentation" id="nested-group-id" aria-hidden="true">
Section label
<span class="ActionList-item-description">
Section description
</span>
</li>
<li class="ActionList-item">
<ul class="ActionList" aria-labelledby="nested-group-id">
<li class="ActionList-item">
<a href="/" class="ActionList-content">
<span class="ActionList-item-label">Group Item</span>
</a>
</li>
</ul>
<ul>
<li class="ActionList-sectionDivider">
<h3 class="ActionList-sectionDivider-title" id="group-id">
List group title
</h3>
<span class="ActionList-item-description">Group description</span>
</li>
<ul class="ActionList" aria-labelledby="group-id">
<li class="ActionList-item">
<a href="/" class="ActionList-content">
<span class="ActionList-item-label">Group Item</span>
</a>
</li>
</ul>
</ul>
```
@ -190,79 +212,10 @@ List item `li` handling semantics, state and interactions
| `ActionList-item--navActive` | Nav item and `aria-current` |
| `ActionList-item--danger` | Item is destructive |
Kitchen sink
```html live
<nav>
<ul class="ActionList" aria-label="Main menu description">
<li class="ActionList-item">
<a href="/" class="ActionList-content">
<span class="ActionList-item-label">Nav Item</span>
</a>
</li>
<li class="ActionList-item" >
<a href="/" class="ActionList-content">
<span class="ActionList-item-label">Nav Item</span>
</a>
</li>
<li class="ActionList-item" >
<a href="/" class="ActionList-content">
<span class="ActionList-item-label">Nav Item</span>
</a>
</li>
<li class="ActionList-sectionDivider" role="presentation" id="some-unique-id" aria-hidden="true">Section Divider</li>
<li class="ActionList-item ActionList-item--hasSubItem">
<ul class="ActionList" aria-labelledby="some-unique-id">
<li class="ActionList-item" >
<a href="/" class="ActionList-content">
<span class="ActionList-item-label">Nav Item</span>
</a>
</li>
<li aria-disabled="true" class="ActionList-item" >
<a href="/" class="ActionList-content">
<span class="ActionList-item-label">Disabled Item</span>
</a>
</li>
<li class="ActionList-item ActionList-item--navActive" >
<a href="#" aria-current="location" class="ActionList-content">
<span class="ActionList-item-label">Nav Item</span>
</a>
</li>
<li class="ActionList-item ActionList-item--danger" >
<a href="/" class="ActionList-content">
<span class="ActionList-item-label">Danger Item</span>
</a>
</li>
</ul>
</li>
<li class="ActionList-sectionDivider" role="presentation" id="some-unique-id" aria-hidden="true">Section Divider</li>
<li class="ActionList-item ActionList-item--hasSubItem">
<ul class="ActionList ActionList--subGroup" aria-labelledby="some-unique-id">
<li class="ActionList-item ActionList-item--subItem" >
<a href="/" class="ActionList-content">
<span class="ActionList-item-label">Nav Item</span>
</a>
</li>
<li class="ActionList-item ActionList-item--subItem" >
<a href="#" class="ActionList-content">
<span class="ActionList-item-label">Nav Item</span>
</a>
</li>
<li class="ActionList-item ActionList-item--subItem" >
<a href="/" class="ActionList-content">
<span class="ActionList-item-label">Nav Item</span>
</a>
</li>
</ul>
</li>
</ul>
</nav>
```
## Action list item content
Contains and places all child content within Action List Item. Can be either an `a href` tag for list link items, or a `span` for items that provide an event on Action List Item `li`.
Contains and places all child elements within action list item. Can be either an `a href` tag for list link items, or a `button` for items that provide an event on Action List Item `li`.
### Variants
@ -274,6 +227,7 @@ Contains and places all child content within Action List Item. Can be either an
| `ActionList-content--visual16` | Creates left padding for sub list if leading visual exists |
| `ActionList-content--visual20` | Creates left padding for sub list if leading visual exists |
| `ActionList-content--visual24` | Creates left padding for sub list if leading visual exists |
| `ActionList-content--hasActiveSubItem` | Handles active nav state if child item is active |
| `ActionList-item-action` | min-height + default styles for visual slot |
| `ActionList-item-action--leading` | Slot: multi/single select |
| `ActionList-item-action--trailing` | Slot: Button, collapse icon |
@ -373,7 +327,7 @@ Contains and places all child content within Action List Item. Can be either an
```html live
<nav>
<ul class="ActionList" aria-label="Main menu description">
<ul class="ActionList">
<li class="ActionList-item">
<a href="/" class="ActionList-content">
<span class="ActionList-item-label">Nav Item</span>
@ -476,8 +430,8 @@ Contains and places all child content within Action List Item. Can be either an
```html live
<ul class="ActionList">
<li class="ActionList-item" aria-haspopup="true" aria-expanded="true">
<span class="ActionList-content">
<li class="ActionList-item">
<button class="ActionList-content" aria-expanded="true">
<span class="ActionList-item-label">Collapsible</span>
<span class="ActionList-item-action ActionList-item-action--trailing">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16" class="ActionList-item-collapseIcon">
@ -485,36 +439,7 @@ Contains and places all child content within Action List Item. Can be either an
></path>
</svg>
</span>
</span>
</button>
</li>
</ul>
```
## Accessibility
### Semantic markup
The markup for Action List changes depending on the intended use case.
In all cases, the basic structure is as follows:
```html
<ul>
<li><span>Content with action (onclick)</span></li>
<li><a href="/">Content as link</a></li>
<li>
<ul>
<li>Nested list</li>
</ul>
</li>
</ul>
```
Pay close attention to `role` attributes throughout the documentation. The `role` attribute may change depending on the context in which Action List is used. Some common use case specs:
[Dropdown menu](https://www.w3.org/TR/wai-aria-practices-1.2/examples/menu-button/menu-button-links.html)
[Multi/Single select dropdown menu](https://www.w3.org/TR/wai-aria-practices-1.2/examples/menubar/menubar-2/menubar-2.html)
[Single select listbox](https://www.w3.org/TR/wai-aria-practices-1.2/examples/listbox/listbox-collapsible.html)
Note: JS is required to make Action List keyboard accessible.

View File

@ -44,8 +44,6 @@
- title: Components
url: /components
children:
- title: Action List
url: /components/action-list
- title: Alerts
url: /components/alerts
- title: Autocomplete

View File

@ -1,16 +1,10 @@
import React from 'react'
import clsx from 'clsx'
import {ListItemTemplate} from './ActionListItem.stories'
import {ListItemTemplate} from '../../ui-patterns/ActionList/ActionListItem.stories'
import {ListTemplate} from '../../ui-patterns/ActionList/ActionList.stories.jsx'
export default {
title: 'Components/ActionList/ActionList',
excludeStories: ['ListTemplate'],
parameters: {
design: {
type: 'figma',
url: 'https://www.figma.com/file/oMiRuexZW6gqVbMhQd6lwP/Storybook-Docs?node-id=23%3A30843'
}
},
excludeStories: ['ActionListTemplate'],
argTypes: {
showDividers: {
control: {type: 'boolean'},
@ -20,7 +14,7 @@ export default {
}
},
role: {
options: [null, 'menu', 'group', 'listbox', 'menubar', 'none', 'radiogroup', 'list'],
options: ['list'],
control: {
type: 'inline-radio'
},
@ -29,22 +23,10 @@ export default {
category: 'HTML'
}
},
variant: {
options: [0, 1], // iterator
mapping: [null, 'ActionList--tree'], // values
control: {
type: 'inline-radio',
labels: ['default', 'tree-view']
},
description: 'Specifies variants for different types of lists',
table: {
category: 'CSS'
}
},
ariaLabel: {
name: 'ariaLabel',
type: 'string',
description: 'Descriptive label for menu contents',
description: 'If no list ActionListDivider is provided, include an aria-label',
table: {
category: 'HTML'
}
@ -52,42 +34,14 @@ export default {
ariaLabelledBy: {
name: 'ariaLabelledBy',
type: 'string',
description: 'Reference ID of section divider',
table: {
category: 'HTML'
}
},
groupId: {
name: 'groupId',
type: 'string',
description: 'Menu group id',
table: {
category: 'HTML'
}
},
children: {
table: {
category: 'HTML'
}
},
subGroup: {
control: {type: 'boolean'},
description: 'If ActionList is nested within an ActionList',
table: {
category: 'CSS'
}
},
listboxMultiSelect: {
name: 'listboxMultiSelect',
type: 'boolean',
description: 'If ActionList has listbox role + multiselect children',
description: 'Reference ID of ActionListDivider',
table: {
category: 'HTML'
}
},
listPadding: {
options: [0, 1], // iterator
mapping: ['', 'ActionList--full'], // values
mapping: [null, 'ActionList--full'], // values
control: {
type: 'inline-radio',
labels: ['inset', 'full-bleed']
@ -96,48 +50,24 @@ export default {
table: {
category: 'CSS'
}
},
children: {
table: {
disable: true
}
}
}
}
export const ListTemplate = ({
showDividers,
children,
role,
ariaLabel,
ariaLabelledBy,
subGroup,
listboxMultiSelect,
listPadding,
variant
}) => (
<ul
className={clsx(
'ActionList',
showDividers && 'ActionList--divided',
subGroup && 'ActionList--subGroup',
listPadding && `${listPadding}`,
variant && `${variant}`
)}
role={role}
aria-label={ariaLabel && ariaLabel}
aria-labelledby={ariaLabelledBy && ariaLabelledBy}
aria-multiselectable={listboxMultiSelect ? 'true' : undefined}
>
<>{children}</>
</ul>
)
export const ActionListTemplate = ListTemplate.bind({})
export const Playground = ListTemplate.bind({})
export const Playground = ActionListTemplate.bind({})
Playground.args = {
ariaLabel: 'Menu description',
subGroup: false,
showDividers: false,
listboxMultiSelect: false,
listPadding: 0,
role: 'list',
ariaLabel: '',
ariaLabelledBy: '',
groupId: '',
variant: 0,
children: (
<>
<ListItemTemplate text="Action list item" />

View File

@ -1,15 +1,11 @@
import React from 'react'
import clsx from 'clsx'
import {ListTemplate} from '../../ui-patterns/ActionList/ActionList.stories.jsx'
import {DividerTemplate} from '../../ui-patterns/ActionList/ActionListDivider.stories.jsx'
export default {
title: 'Components/ActionList/ActionListDivider',
excludeStories: ['DividerTemplate'],
parameters: {
design: {
type: 'figma',
url: 'https://www.figma.com/file/oMiRuexZW6gqVbMhQd6lwP/Storybook?node-id=2%3A2'
}
},
excludeStories: ['ActionDividerTemplate'],
argTypes: {
variant: {
options: [0, 1], // iterator
@ -44,38 +40,26 @@ export default {
defaultValue: '',
type: 'string',
name: 'id',
description: 'Used for aria-labelledby',
description: 'Provide label for NavigationList <ul> aria-labelledby',
table: {
category: 'HTML'
}
}
},
decorators: [
Story => (
<ul className="ActionList" role="menu">
<Story />
</ul>
)
]
}
}
export const DividerTemplate = ({title, description, variant, id}) => (
<>
<li
className={clsx('ActionList-sectionDivider', variant && `${variant}`)}
role={title ? 'presentation' : 'separator'}
id={id}
aria-hidden={title ? true : undefined}
>
{title}
{description && <span className="ActionList-item-description">{description}</span>}
</li>
</>
)
export const ActionDividerTemplate = DividerTemplate.bind({})
export const Playground = DividerTemplate.bind({})
export const Playground = ActionDividerTemplate.bind({})
Playground.args = {
title: 'Section title',
description: 'Section description',
variant: 'subtle'
variant: 0
}
Playground.decorators = [
Story => (
<ListTemplate>
<Story />
</ListTemplate>
)
]

View File

@ -1,51 +1,28 @@
import React from 'react'
import clsx from 'clsx'
import {ListTemplate} from './ActionList.stories'
import {ListItemTemplate} from './ActionListItem.stories'
import {DividerTemplate} from './ActionListDivider.stories'
import {ListTemplate} from '../../ui-patterns/ActionList/ActionList.stories.jsx'
import {
PatternTitle,
PatternFilled,
PatternWithDescription,
PatternSeparator
} from '../../ui-patterns/ActionList/ActionListDividerFeatures.stories.jsx'
export default {
title: 'Components/ActionList/ActionListDivider/Features',
decorators: [
Story => (
<ul className="ActionList" role="menu">
<ListTemplate>
<Story />
</ul>
</ListTemplate>
)
]
}
export const WithTitle = DividerTemplate.bind({})
WithTitle.args = {
title: 'List group title'
}
export const Title = ({}) => <PatternTitle {...PatternTitle.args} />
export const Subtle = DividerTemplate.bind({})
Subtle.args = {
variant: 'subtle',
title: 'List group title'
}
export const Filled = ({}) => <PatternFilled {...PatternFilled.args} />
export const Filled = DividerTemplate.bind({})
Filled.args = {
variant: 'ActionList-sectionDivider--filled',
title: 'List group title'
}
export const WithDescription = ({}) => <PatternWithDescription {...PatternWithDescription.args} />
export const WithDescription = DividerTemplate.bind({})
WithDescription.args = {
title: 'List group title',
description: 'Group description'
}
export const RolePresentation = DividerTemplate.bind({})
RolePresentation.storyName = '[role="presentation"]'
RolePresentation.args = {
title: 'List group title'
}
export const RoleSeparator = DividerTemplate.bind({})
RoleSeparator.storyName = '[role="separator"]'
RoleSeparator.args = {}
export const Empty = DividerTemplate.bind({})
export const Separator = ({}) => <PatternSeparator {...PatternSeparator.args} />

View File

@ -1,148 +1,16 @@
import React from 'react'
import clsx from 'clsx'
import {ListTemplate} from './ActionList.stories'
import {ListItemTemplate} from './ActionListItem.stories'
import {
PatternShowDividers,
PatternInsetPadding,
PatternFullBleed
} from '../../ui-patterns/ActionList/ActionListFeatures.stories.jsx'
export default {
title: 'Components/ActionList/ActionList/Features'
}
export const ShowDividers = ListTemplate.bind({})
ShowDividers.args = {
showDividers: true,
children: (
<>
<ListItemTemplate text="Item 1" href="/" listSemantic />
<ListItemTemplate text="Item 2" href="/" listSemantic />
<ListItemTemplate text="Item 3" href="/" listSemantic />
</>
)
}
export const ShowDividers = ({}) => <PatternShowDividers {...PatternShowDividers.args} />
export const InsetPadding = ListTemplate.bind({})
InsetPadding.args = {
listPadding: 'inset',
children: (
<>
<ListItemTemplate text="Item 1" href="/" listSemantic />
<ListItemTemplate text="Item 2" href="/" listSemantic />
<ListItemTemplate text="Item 3" href="/" listSemantic />
</>
)
}
export const InsetPadding = ({}) => <PatternInsetPadding {...PatternInsetPadding.args} />
export const FullBleed = ListTemplate.bind({})
FullBleed.args = {
listPadding: 'ActionList--full',
children: (
<>
<ListItemTemplate text="Item 1" href="/" listSemantic />
<ListItemTemplate text="Item 2" href="/" listSemantic />
<ListItemTemplate text="Item 3" href="/" listSemantic />
</>
)
}
export const AsSubGroup = ListTemplate.bind({})
AsSubGroup.args = {
subGroup: true,
children: (
<>
<ListItemTemplate text="Item 1" href="/" listSemantic />
<ListItemTemplate text="Item 2" href="/" listSemantic />
<ListItemTemplate text="Item 3" href="/" listSemantic />
</>
)
}
export const RoleMenu = ListTemplate.bind({})
RoleMenu.storyName = '[role="menu"] menu list'
RoleMenu.args = {
role: 'menu',
children: (
<>
<ListItemTemplate text="Item 1" href="/" />
<ListItemTemplate text="Item 2" href="/" />
<ListItemTemplate text="Item 3" href="/" />
</>
)
}
export const RoleNav = ListTemplate.bind({})
RoleNav.storyName = '[nav] nav wrapper'
RoleNav.args = {
children: (
<>
<ListItemTemplate text="Item 1" href="/" listSemantic />
<ListItemTemplate text="Item 2" href="/" listSemantic />
<ListItemTemplate text="Item 3" href="/" listSemantic />
</>
)
}
RoleNav.decorators = [
Story => (
<nav>
<Story />
</nav>
)
]
export const RoleTreeView = ListTemplate.bind({})
RoleTreeView.storyName = '[role="tree"] tree view list'
RoleTreeView.args = {
role: 'tree',
variant: 'ActionList--tree',
children: (
<>
<ListItemTemplate
ariaLevel="1"
ariaSetSize="2"
ariaPosInset="1"
treeitem
containsSubItem
text="Tree group"
collapsibleLeading
children={
<ListTemplate
role="group"
containsSubItem
subGroup
ariaLabel="Group description"
children={
<>
<ListItemTemplate
ariaLevel="2"
ariaSetSize="3"
ariaPosInset="1"
subItem
treeitem
text="Tree item 1"
href="/"
/>
<ListItemTemplate
treeitem
ariaLevel="2"
ariaSetSize="3"
ariaPosInset="2"
subItem
text="Tree item 2"
href="/"
/>
<ListItemTemplate
treeitem
ariaLevel="2"
ariaSetSize="3"
ariaPosInset="3"
truncateItem
subItem
text="Tree item 3"
href="/"
/>
</>
}
/>
}
/>
</>
)
}
export const FullBleed = ({}) => <PatternFullBleed {...PatternFullBleed.args} />

View File

@ -1,16 +1,10 @@
import React from 'react'
import clsx from 'clsx'
import useToggle from '../../helpers/useToggle.jsx'
import {ListTemplate} from '../../ui-patterns/ActionList/ActionList.stories.jsx'
import {ListItemTemplate} from '../../ui-patterns/ActionList/ActionListItem.stories.jsx'
export default {
title: 'Components/ActionList/ActionListItem',
parameters: {
design: {
type: 'figma',
url: 'https://www.figma.com/file/oMiRuexZW6gqVbMhQd6lwP/Storybook-Docs?node-id=23%3A30843'
}
},
excludeStories: ['ListItemTemplate'],
excludeStories: ['ActionListItemTemplate'],
argTypes: {
size: {
options: [0, 1, 2], // iterator
@ -37,20 +31,6 @@ export default {
category: 'CSS'
}
},
subItem: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'CSS'
}
},
containsSubItem: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'CSS'
}
},
truncateItem: {
defaultValue: false,
control: {type: 'boolean'},
@ -58,13 +38,6 @@ export default {
category: 'CSS'
}
},
containsActiveSubItem: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'CSS'
}
},
leadingVisual: {
defaultValue: '',
name: 'leadingVisual',
@ -143,445 +116,24 @@ export default {
table: {
category: 'CSS'
}
},
id: {
defaultValue: '',
type: 'string',
name: 'id',
description: 'Used for aria-labelledby if nested group within item',
table: {
category: 'HTML'
}
},
collapsible: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'Interactive'
}
},
collapsibleLeading: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'Interactive'
}
},
singleSelect: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'Interactive'
}
},
multiSelect: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'Interactive'
}
},
listSingleSelect: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'Interactive'
}
},
listMultiSelect: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'Interactive'
}
},
treeitem: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'HTML'
}
},
ariaDisabled: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'Interactive'
}
},
ariaLevel: {
name: 'ariaLevel',
type: 'string',
description: 'number - nested subgroup',
table: {
category: 'HTML'
}
},
ariaSetSize: {
name: 'ariaSetSize',
type: 'string',
description:
'Defines the number of treeitem elements in the set of treeitem elements that are in the same branch and at the same level within the hierarchy',
table: {
category: 'HTML'
}
},
ariaPosInset: {
name: 'ariaPosInset',
type: 'string',
description:
'Defines the position of the element within the set of other treeitem elements that are in the same branch and at the same level within the hierarchy.',
table: {
category: 'HTML'
}
},
fontSize: {
options: [0, 1], // iterator
mapping: ['', 'ActionList-content--fontSmall'], // values
control: {
type: 'inline-radio',
labels: ['default', 'small']
},
description: 'Used to adjust font-size for subgroup items',
table: {
category: 'CSS'
}
}
}
}
export const ListItemTemplate = ({
text,
size,
leadingVisual,
leadingVisualSize,
trailingVisual,
description,
descriptionVariant,
variant,
href,
ariaCurrent,
children,
subItem,
containsSubItem,
id,
collapsible,
trailingAction,
leadingAction,
singleSelect,
multiSelect,
listSingleSelect,
listMultiSelect,
listSemantic,
ariaDisabled,
containsActiveSubItem,
collapsibleLeading,
truncateItem,
ariaLevel,
fontSize,
treeitem,
ariaSetSize,
ariaPosInset,
menuItem
}) => {
const [isCollapsed, itemIsCollapsed] = useToggle()
const [isChecked, itemIsChecked] = useToggle()
const itemStyle = {
'--ActionList-tree-depth': `${ariaLevel}`
}
return (
<li
className={clsx(
'ActionList-item',
ariaCurrent && 'ActionList-item--navActive',
subItem && `ActionList-item--subItem`,
containsSubItem && `ActionList-item--hasSubItem`,
containsActiveSubItem && `ActionList-item--hasActiveSubItem`,
variant && `${variant}`
)}
aria-level={ariaLevel ? `${ariaLevel}` : undefined}
aria-setsize={ariaSetSize ? `${ariaSetSize}` : undefined}
aria-posinset={ariaPosInset ? `${ariaPosInset}` : undefined}
style={ariaLevel && itemStyle}
onClick={collapsible || collapsibleLeading ? itemIsCollapsed : itemIsChecked}
role={
singleSelect
? 'menuitemradio'
: multiSelect
? 'menuitemcheckbox'
: listSingleSelect || listMultiSelect
? 'option'
: listSemantic
? undefined
: href
? 'none'
: treeitem
? 'treeitem'
: menuItem
? 'menuitem'
: undefined
}
id={id}
aria-haspopup={collapsible || collapsibleLeading ? 'true' : undefined}
aria-expanded={collapsible || collapsibleLeading ? (isCollapsed ? 'false' : 'true') : undefined}
aria-checked={singleSelect || multiSelect ? (isChecked ? 'true' : 'false') : undefined}
aria-selected={listSingleSelect || listMultiSelect ? (isChecked ? 'true' : 'false') : undefined}
aria-disabled={ariaDisabled ? 'true' : undefined}
>
{href ? (
<>
<a
href={href}
role={
href && !listSemantic && !treeitem ? 'menuitem' : undefined || (href && treeitem) ? 'treeitem' : undefined
}
aria-current={ariaCurrent}
className={clsx(
text && 'ActionList-content',
size && `${size}`,
fontSize && `${fontSize}`,
(leadingVisual || trailingVisual) && description && 'ActionList-content--blockDescription',
leadingVisual && leadingVisualSize && `${leadingVisualSize}`
)}
>
{(leadingAction ||
singleSelect ||
multiSelect ||
listSingleSelect ||
listMultiSelect ||
collapsibleLeading) && (
<span className="ActionList-item-action ActionList-item-action--leading">
{singleSelect ||
(listSingleSelect && (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
width="16"
height="16"
className="ActionList-item-singleSelectCheckmark"
>
<path
fill-rule="evenodd"
d="M13.78 4.22a.75.75 0 010 1.06l-7.25 7.25a.75.75 0 01-1.06 0L2.22 9.28a.75.75 0 011.06-1.06L6 10.94l6.72-6.72a.75.75 0 011.06 0z"
></path>
</svg>
))}
{multiSelect ||
(listMultiSelect && (
<svg
width="16"
height="16"
viewBox="0 0 16 16"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
focusable="false"
className="ActionList-item-multiSelectIcon"
>
<rect x="2" y="2" width="12" height="12" rx="4" className="ActionList-item-multiSelectIconRect" />
<path
fill-rule="evenodd"
d="M4.03231 8.69862C3.84775 8.20646 4.49385 7.77554 4.95539 7.77554C5.41693 7.77554 6.80154 9.85246 6.80154 9.85246C6.80154 9.85246 10.2631 4.314 10.4938 4.08323C10.7246 3.85246 11.8785 4.08323 11.4169 5.00631C11.0081 5.82388 7.26308 11.4678 7.26308 11.4678C7.26308 11.4678 6.80154 12.1602 6.34 11.4678C5.87846 10.7755 4.21687 9.19077 4.03231 8.69862Z"
className="ActionList-item-multiSelectCheckmark"
/>
</svg>
))}
{collapsibleLeading && (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
width="16"
height="16"
className="ActionList-item-collapseIcon"
>
<path
fill-rule="evenodd"
d="M12.78 6.22a.75.75 0 010 1.06l-4.25 4.25a.75.75 0 01-1.06 0L3.22 7.28a.75.75 0 011.06-1.06L8 9.94l3.72-3.72a.75.75 0 011.06 0z"
></path>
</svg>
)}
{leadingAction}
</span>
)}
{leadingVisual && (
<span
className="ActionList-item-visual ActionList-item-visual--leading"
dangerouslySetInnerHTML={{__html: leadingVisual}}
/>
)}
{description && (
<span className={clsx('ActionList-item-descriptionWrap', `${descriptionVariant}`)}>
<span className={clsx('ActionList-item-label', truncateItem && 'ActionList-item-label--truncate')}>
{text}
</span>
<span className="ActionList-item-description">{description}</span>
</span>
)}
{!description && text && (
<span className={clsx('ActionList-item-label', truncateItem && 'ActionList-item-label--truncate')}>
{text}
</span>
)}
{trailingVisual && (
<span
className="ActionList-item-visual ActionList-item-visual--trailing"
dangerouslySetInnerHTML={{__html: trailingVisual}}
/>
)}
{trailingAction ||
(collapsible && (
<span className="ActionList-item-action ActionList-item-action--trailing">
{collapsible && (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
width="16"
height="16"
className="ActionList-item-collapseIcon"
>
<path
fill-rule="evenodd"
d="M12.78 6.22a.75.75 0 010 1.06l-4.25 4.25a.75.75 0 01-1.06 0L3.22 7.28a.75.75 0 011.06-1.06L8 9.94l3.72-3.72a.75.75 0 011.06 0z"
></path>
</svg>
)}
{trailingAction}
</span>
))}
</a>
{children}
</>
) : (
<>
{text && (
<span
className={clsx(
text && 'ActionList-content',
size && `${size}`,
fontSize && `${fontSize}`,
(leadingVisual || trailingVisual) && description && 'ActionList-content--blockDescription',
leadingVisual && leadingVisualSize && `${leadingVisualSize}`
)}
>
{(leadingAction ||
singleSelect ||
multiSelect ||
listSingleSelect ||
listMultiSelect ||
collapsibleLeading) && (
<span className="ActionList-item-action ActionList-item-action--leading">
{(singleSelect || listSingleSelect) && (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
width="16"
height="16"
className="ActionList-item-singleSelectCheckmark"
>
<path
fill-rule="evenodd"
d="M13.78 4.22a.75.75 0 010 1.06l-7.25 7.25a.75.75 0 01-1.06 0L2.22 9.28a.75.75 0 011.06-1.06L6 10.94l6.72-6.72a.75.75 0 011.06 0z"
></path>
</svg>
)}
{(multiSelect || listMultiSelect) && (
<svg
width="16"
height="16"
viewBox="0 0 16 16"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
focusable="false"
className="ActionList-item-multiSelectIcon"
>
<rect x="2" y="2" width="12" height="12" rx="4" className="ActionList-item-multiSelectIconRect" />
<path
fill-rule="evenodd"
d="M4.03231 8.69862C3.84775 8.20646 4.49385 7.77554 4.95539 7.77554C5.41693 7.77554 6.80154 9.85246 6.80154 9.85246C6.80154 9.85246 10.2631 4.314 10.4938 4.08323C10.7246 3.85246 11.8785 4.08323 11.4169 5.00631C11.0081 5.82388 7.26308 11.4678 7.26308 11.4678C7.26308 11.4678 6.80154 12.1602 6.34 11.4678C5.87846 10.7755 4.21687 9.19077 4.03231 8.69862Z"
className="ActionList-item-multiSelectCheckmark"
/>
</svg>
)}
{collapsibleLeading && (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
width="16"
height="16"
className="ActionList-item-collapseIcon"
>
<path
fill-rule="evenodd"
d="M12.78 6.22a.75.75 0 010 1.06l-4.25 4.25a.75.75 0 01-1.06 0L3.22 7.28a.75.75 0 011.06-1.06L8 9.94l3.72-3.72a.75.75 0 011.06 0z"
></path>
</svg>
)}
{leadingAction}
</span>
)}
{leadingVisual && (
<span
className="ActionList-item-visual ActionList-item-visual--leading"
dangerouslySetInnerHTML={{__html: leadingVisual}}
/>
)}
{description && (
<span className={clsx('ActionList-item-descriptionWrap', `${descriptionVariant}`)}>
<span className={clsx('ActionList-item-label', truncateItem && 'ActionList-item-label--truncate')}>
{text}
</span>
<span className="ActionList-item-description">{description}</span>
</span>
)}
{!description && text && (
<span className={clsx('ActionList-item-label', truncateItem && 'ActionList-item-label--truncate')}>
{text}
</span>
)}
export const ActionListItemTemplate = ListItemTemplate.bind({})
{trailingVisual && (
<span
className="ActionList-item-visual ActionList-item-visual--trailing"
dangerouslySetInnerHTML={{__html: trailingVisual}}
/>
)}
{trailingAction ||
(collapsible && (
<span className="ActionList-item-action ActionList-item-action--trailing">
{collapsible && (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
width="16"
height="16"
className="ActionList-item-collapseIcon"
>
<path
fill-rule="evenodd"
d="M12.78 6.22a.75.75 0 010 1.06l-4.25 4.25a.75.75 0 01-1.06 0L3.22 7.28a.75.75 0 011.06-1.06L8 9.94l3.72-3.72a.75.75 0 011.06 0z"
></path>
</svg>
)}
{trailingAction}
</span>
))}
</span>
)}
{children}
</>
)}
</li>
)
}
export const Playground = ListItemTemplate.bind({})
export const Playground = ActionListItemTemplate.bind({})
Playground.decorators = [
Story => (
<ul className="ActionList">
<ListTemplate>
<Story />
</ul>
</ListTemplate>
)
]
Playground.args = {
id: null,
truncateItem: false
truncateItem: false,
size: 0,
variant: 0,
descriptionVariant: 0,
leadingVisualSize: 0
}

View File

@ -1,589 +1,130 @@
import React from 'react'
import clsx from 'clsx'
import {ListItemTemplate} from './ActionListItem.stories'
import {DividerTemplate} from './ActionListDivider.stories'
import {ListTemplate} from '../../ui-patterns/ActionList/ActionList.stories.jsx'
import {
PatternTextOnly,
PatternSizeMedium,
PatternSizeMediumWithDescription,
PatternSizeLarge,
PatternSizeLargeWithDescription,
PatternVisualLeading,
PatternVisualTrailing,
PatternVisualTrailingText,
PatternVisualLeadingAndTrailing,
PatternDescriptionBlock,
PatternDescriptionBlockWithLeadingVisual,
PatternDescriptionBlockWithTrailingVisual,
PatternDescriptionBlockWithLeadingAndTrailingVisual,
PatternDescriptionInline,
PatternDescriptionInlineWithLeadingVisual,
PatternDescriptionInlineWithTrailingVisual,
PatternDescriptionInlineWithLeadingAndTrailingVisual,
PatternNavActiveAnchor,
PatternNavActivePage,
PatternVariantDangerItem,
PatternVariantDangerItemLeading,
PatternVariantDangerItemTrailing,
PatternVariantDangerItemLeadingTrailing,
PatternTruncateText,
PatternWrapText
} from '../../ui-patterns/ActionList/ActionListItemFeatures.stories.jsx'
export default {
title: 'Components/ActionList/ActionListItem/Features',
parameters: {
design: {
type: 'figma',
url: 'https://www.figma.com/file/oMiRuexZW6gqVbMhQd6lwP/Storybook?node-id=2%3A2'
}
},
decorators: [
Story => (
<ul className="ActionList" role="menu">
<ListTemplate>
<Story />
</ul>
</ListTemplate>
)
]
}
export const TextOnly = ListItemTemplate.bind({})
TextOnly.args = {
text: 'Basic item label'
}
export const TextOnly = ({}) => <PatternTextOnly {...PatternTextOnly.args} />
export const SizeMedium = ListItemTemplate.bind({})
SizeMedium.args = {
...ListItemTemplate.args,
text: 'Medium item',
size: 'ActionList-content--sizeMedium'
}
export const SizeMedium = ({}) => <PatternSizeMedium {...PatternSizeMedium.args} />
export const SizeMediumWithDescription = ListItemTemplate.bind({})
SizeMediumWithDescription.args = {
...ListItemTemplate.args,
text: 'Medium item',
description: 'Some descriptive text',
size: 'ActionList-content--sizeMedium'
}
export const SizeMediumWithDescription = ({}) => (
<PatternSizeMediumWithDescription {...PatternSizeMediumWithDescription.args} />
)
export const SizeLarge = ListItemTemplate.bind({})
SizeLarge.args = {
...ListItemTemplate.args,
text: 'Large item',
size: 'ActionList-content--sizeLarge'
}
export const SizeLarge = ({}) => <PatternSizeLarge {...PatternSizeLarge.args} />
export const SizeLargeWithDescription = ListItemTemplate.bind({})
SizeLargeWithDescription.args = {
...ListItemTemplate.args,
text: 'Large item',
description: 'Some descriptive text',
size: 'ActionList-content--sizeLarge'
}
export const SizeLargeWithDescription = ({}) => (
<PatternSizeLargeWithDescription {...PatternSizeLargeWithDescription.args} />
)
export const VisualLeading = ListItemTemplate.bind({})
VisualLeading.storyName = '[Visuals] Leading'
VisualLeading.args = {
...ListItemTemplate.args,
text: 'Item with leading visual',
leadingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zm.75 4.75a.75.75 0 00-1.5 0v2.5h-2.5a.75.75 0 000 1.5h2.5v2.5a.75.75 0 001.5 0v-2.5h2.5a.75.75 0 000-1.5h-2.5v-2.5z"
></path>
</svg>`
}
export const VisualLeading = ({}) => <PatternVisualLeading {...PatternVisualLeading.args} />
export const VisualTrailing = ListItemTemplate.bind({})
VisualTrailing.storyName = '[Visuals] Trailing'
VisualTrailing.args = {
...ListItemTemplate.args,
text: 'Item with trailing visual',
trailingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zm.75 4.75a.75.75 0 00-1.5 0v2.5h-2.5a.75.75 0 000 1.5h2.5v2.5a.75.75 0 001.5 0v-2.5h2.5a.75.75 0 000-1.5h-2.5v-2.5z"
></path>
</svg>`
}
export const VisualTrailing = ({}) => <PatternVisualTrailing {...PatternVisualTrailing.args} />
export const VisualTrailingText = ListItemTemplate.bind({})
VisualTrailingText.storyName = '[Visuals] Trailing text'
VisualTrailingText.args = {
...ListItemTemplate.args,
text: 'Item with trailing text',
trailingVisual: `⌘N`
}
export const VisualTrailingText = ({}) => <PatternVisualTrailingText {...PatternVisualTrailingText.args} />
export const VisualLeadingAndTrailing = ListItemTemplate.bind({})
VisualLeadingAndTrailing.storyName = '[Visuals] Leading & trailing'
VisualLeadingAndTrailing.args = {
...ListItemTemplate.args,
text: 'Item with trailing visual',
trailingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zm.75 4.75a.75.75 0 00-1.5 0v2.5h-2.5a.75.75 0 000 1.5h2.5v2.5a.75.75 0 001.5 0v-2.5h2.5a.75.75 0 000-1.5h-2.5v-2.5z"
></path>
</svg>`,
leadingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M10.5 5a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0zm.061 3.073a4 4 0 10-5.123 0 6.004 6.004 0 00-3.431 5.142.75.75 0 001.498.07 4.5 4.5 0 018.99 0 .75.75 0 101.498-.07 6.005 6.005 0 00-3.432-5.142z"
></path>
</svg>`
}
export const VisualLeadingAndTrailing = ({}) => (
<PatternVisualLeadingAndTrailing {...PatternVisualLeadingAndTrailing.args} />
)
export const DescriptionBlock = ListItemTemplate.bind({})
DescriptionBlock.storyName = '[Description] block'
DescriptionBlock.args = {
...ListItemTemplate.args,
text: 'Item label',
description: 'This is a description',
descriptionVariant: 'ActionList-item-blockDescription'
}
export const DescriptionBlock = ({}) => <PatternDescriptionBlock {...PatternDescriptionBlock.args} />
export const DescriptionBlockWithLeadingVisual = ListItemTemplate.bind({})
DescriptionBlockWithLeadingVisual.storyName = '[Description] block + leading visual'
DescriptionBlockWithLeadingVisual.args = {
...ListItemTemplate.args,
text: 'Item label',
description: 'This is a description',
descriptionVariant: 'ActionList-item-blockDescription',
leadingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M10.5 5a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0zm.061 3.073a4 4 0 10-5.123 0 6.004 6.004 0 00-3.431 5.142.75.75 0 001.498.07 4.5 4.5 0 018.99 0 .75.75 0 101.498-.07 6.005 6.005 0 00-3.432-5.142z"
></path>
</svg>`
}
export const DescriptionBlockWithLeadingVisual = ({}) => (
<PatternDescriptionBlockWithLeadingVisual {...PatternDescriptionBlockWithLeadingVisual.args} />
)
export const DescriptionBlockWithTrailingVisual = ListItemTemplate.bind({})
DescriptionBlockWithTrailingVisual.storyName = '[Description] block + trailing visual'
DescriptionBlockWithTrailingVisual.args = {
...ListItemTemplate.args,
text: 'Item label',
description: 'This is a description',
descriptionVariant: 'ActionList-item-blockDescription',
trailingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M10.5 5a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0zm.061 3.073a4 4 0 10-5.123 0 6.004 6.004 0 00-3.431 5.142.75.75 0 001.498.07 4.5 4.5 0 018.99 0 .75.75 0 101.498-.07 6.005 6.005 0 00-3.432-5.142z"
></path>
</svg>`
}
export const DescriptionBlockWithTrailingVisual = ({}) => (
<PatternDescriptionBlockWithTrailingVisual {...PatternDescriptionBlockWithTrailingVisual.args} />
)
export const DescriptionBlockWithLeadingAndTrailingVisual = ListItemTemplate.bind({})
DescriptionBlockWithLeadingAndTrailingVisual.storyName = '[Description] block + leading/trailing visual'
DescriptionBlockWithLeadingAndTrailingVisual.args = {
...ListItemTemplate.args,
text: 'Item label',
description: 'This is a description',
descriptionVariant: 'ActionList-item-blockDescription',
leadingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M10.5 5a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0zm.061 3.073a4 4 0 10-5.123 0 6.004 6.004 0 00-3.431 5.142.75.75 0 001.498.07 4.5 4.5 0 018.99 0 .75.75 0 101.498-.07 6.005 6.005 0 00-3.432-5.142z"
></path>
</svg>`,
trailingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zm.75 4.75a.75.75 0 00-1.5 0v2.5h-2.5a.75.75 0 000 1.5h2.5v2.5a.75.75 0 001.5 0v-2.5h2.5a.75.75 0 000-1.5h-2.5v-2.5z"
></path>
</svg>`
}
export const DescriptionBlockWithLeadingAndTrailingVisual = ({}) => (
<PatternDescriptionBlockWithLeadingAndTrailingVisual {...PatternDescriptionBlockWithLeadingAndTrailingVisual.args} />
)
export const DescriptionInline = ListItemTemplate.bind({})
DescriptionInline.storyName = '[Description] inline'
DescriptionInline.args = {
...ListItemTemplate.args,
text: 'Item label',
description: 'This is a description',
descriptionVariant: 'ActionList-item-descriptionWrap--inline'
}
export const DescriptionInline = ({}) => <PatternDescriptionInline {...PatternDescriptionInline.args} />
export const DescriptionInlineWithLeadingVisual = ListItemTemplate.bind({})
DescriptionInlineWithLeadingVisual.storyName = '[Description] inline + leading visual'
DescriptionInlineWithLeadingVisual.args = {
...ListItemTemplate.args,
text: 'Item label',
description: 'This is a description',
descriptionVariant: 'ActionList-item-descriptionWrap--inline',
leadingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M10.5 5a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0zm.061 3.073a4 4 0 10-5.123 0 6.004 6.004 0 00-3.431 5.142.75.75 0 001.498.07 4.5 4.5 0 018.99 0 .75.75 0 101.498-.07 6.005 6.005 0 00-3.432-5.142z"
></path>
</svg>`
}
export const DescriptionInlineWithLeadingVisual = ({}) => (
<PatternDescriptionInlineWithLeadingVisual {...PatternDescriptionInlineWithLeadingVisual.args} />
)
export const DescriptionInlineWithTrailingVisual = ListItemTemplate.bind({})
DescriptionInlineWithTrailingVisual.storyName = '[Description] inline + trailing visual'
DescriptionInlineWithTrailingVisual.args = {
...ListItemTemplate.args,
text: 'Item label',
description: 'This is a description',
descriptionVariant: 'ActionList-item-descriptionWrap--inline',
trailingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M10.5 5a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0zm.061 3.073a4 4 0 10-5.123 0 6.004 6.004 0 00-3.431 5.142.75.75 0 001.498.07 4.5 4.5 0 018.99 0 .75.75 0 101.498-.07 6.005 6.005 0 00-3.432-5.142z"
></path>
</svg>`
}
export const DescriptionInlineWithTrailingVisual = ({}) => (
<PatternDescriptionInlineWithTrailingVisual {...PatternDescriptionInlineWithTrailingVisual.args} />
)
export const DescriptionInlineWithLeadingAndTrailingVisual = ListItemTemplate.bind({})
DescriptionInlineWithLeadingAndTrailingVisual.storyName = '[Description] inline + leading/trailing visual'
DescriptionInlineWithLeadingAndTrailingVisual.args = {
...ListItemTemplate.args,
text: 'Item label',
description: 'This is a description',
descriptionVariant: 'ActionList-item-descriptionWrap--inline',
trailingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M10.5 5a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0zm.061 3.073a4 4 0 10-5.123 0 6.004 6.004 0 00-3.431 5.142.75.75 0 001.498.07 4.5 4.5 0 018.99 0 .75.75 0 101.498-.07 6.005 6.005 0 00-3.432-5.142z"
></path>
</svg>`,
leadingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zm.75 4.75a.75.75 0 00-1.5 0v2.5h-2.5a.75.75 0 000 1.5h2.5v2.5a.75.75 0 001.5 0v-2.5h2.5a.75.75 0 000-1.5h-2.5v-2.5z"
></path>
</svg>`
}
export const DescriptionInlineWithLeadingAndTrailingVisual = ({}) => (
<PatternDescriptionInlineWithLeadingAndTrailingVisual
{...PatternDescriptionInlineWithLeadingAndTrailingVisual.args}
/>
)
export const NavActiveAnchor = ListItemTemplate.bind({})
NavActiveAnchor.storyName = '[Nav] Active anchor'
NavActiveAnchor.args = {
...ListItemTemplate.args,
text: 'Im an anchor link',
href: '#someid',
ariaCurrent: 'location',
activeNavItem: true
}
export const NavActiveAnchor = ({}) => <PatternNavActiveAnchor {...PatternNavActiveAnchor.args} />
export const NavActivePage = ListItemTemplate.bind({})
NavActivePage.storyName = '[Nav] Active page'
NavActivePage.args = {
...ListItemTemplate.args,
text: 'Im a page level link',
href: '/',
ariaCurrent: 'page',
activeNavItem: true
}
export const NavActivePage = ({}) => <PatternNavActivePage {...PatternNavActivePage.args} />
export const VariantDangerItem = ListItemTemplate.bind({})
VariantDangerItem.storyName = '[Variant] Danger'
VariantDangerItem.args = {
...ListItemTemplate.args,
text: 'Danger danger',
variant: 'ActionList-item--danger'
}
export const VariantDangerItem = ({}) => <PatternVariantDangerItem {...PatternVariantDangerItem.args} />
export const VariantDangerItemLeading = ListItemTemplate.bind({})
VariantDangerItemLeading.storyName = '[Variant] Danger + leading visual'
VariantDangerItemLeading.args = {
...ListItemTemplate.args,
text: 'Danger danger',
variant: 'ActionList-item--danger',
leadingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zm.75 4.75a.75.75 0 00-1.5 0v2.5h-2.5a.75.75 0 000 1.5h2.5v2.5a.75.75 0 001.5 0v-2.5h2.5a.75.75 0 000-1.5h-2.5v-2.5z"
></path>
</svg>`
}
export const VariantDangerItemLeading = ({}) => (
<PatternVariantDangerItemLeading {...PatternVariantDangerItemLeading.args} />
)
export const VariantDangerItemTrailing = ListItemTemplate.bind({})
VariantDangerItemTrailing.storyName = '[Variant] Danger + trailing visual'
VariantDangerItemTrailing.args = {
...ListItemTemplate.args,
text: 'Danger danger',
variant: 'ActionList-item--danger',
trailingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M10.5 5a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0zm.061 3.073a4 4 0 10-5.123 0 6.004 6.004 0 00-3.431 5.142.75.75 0 001.498.07 4.5 4.5 0 018.99 0 .75.75 0 101.498-.07 6.005 6.005 0 00-3.432-5.142z"
></path>
</svg>`
}
export const VariantDangerItemTrailing = ({}) => (
<PatternVariantDangerItemTrailing {...PatternVariantDangerItemTrailing.args} />
)
export const VariantDangerItemLeadingTrailing = ListItemTemplate.bind({})
VariantDangerItemLeadingTrailing.storyName = '[Variant] Danger + leading/trailing visual'
VariantDangerItemLeadingTrailing.args = {
...ListItemTemplate.args,
text: 'Danger danger',
variant: 'ActionList-item--danger',
leadingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zm.75 4.75a.75.75 0 00-1.5 0v2.5h-2.5a.75.75 0 000 1.5h2.5v2.5a.75.75 0 001.5 0v-2.5h2.5a.75.75 0 000-1.5h-2.5v-2.5z"
></path>
</svg>`,
trailingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M10.5 5a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0zm.061 3.073a4 4 0 10-5.123 0 6.004 6.004 0 00-3.431 5.142.75.75 0 001.498.07 4.5 4.5 0 018.99 0 .75.75 0 101.498-.07 6.005 6.005 0 00-3.432-5.142z"
></path>
</svg>`
}
export const VariantDangerItemLeadingTrailing = ({}) => (
<PatternVariantDangerItemLeadingTrailing {...PatternVariantDangerItemLeadingTrailing.args} />
)
export const VariantDisabledItem = ListItemTemplate.bind({})
VariantDisabledItem.storyName = '[Variant] Disabled'
VariantDisabledItem.args = {
...ListItemTemplate.args,
text: 'Disabled',
ariaDisabled: true
}
export const VariantDisabledItem = ({}) => <PatternVariantDisabledItem {...PatternVariantDisabledItem.args} />
export const VariantDisabledItemLeading = ListItemTemplate.bind({})
VariantDisabledItemLeading.storyName = '[Variant] Disabled + leading visual'
VariantDisabledItemLeading.args = {
...ListItemTemplate.args,
text: 'Disabled',
ariaDisabled: true,
leadingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zm.75 4.75a.75.75 0 00-1.5 0v2.5h-2.5a.75.75 0 000 1.5h2.5v2.5a.75.75 0 001.5 0v-2.5h2.5a.75.75 0 000-1.5h-2.5v-2.5z"
></path>
</svg>`
}
export const VariantDisabledItemLeading = ({}) => (
<PatternVariantDisabledItemLeading {...PatternVariantDisabledItemLeading.args} />
)
export const VariantDisabledItemTrailing = ListItemTemplate.bind({})
VariantDisabledItemTrailing.storyName = '[Variant] Disabled + trailing visual'
VariantDisabledItemTrailing.args = {
...ListItemTemplate.args,
text: 'Disabled',
ariaDisabled: true,
trailingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M10.5 5a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0zm.061 3.073a4 4 0 10-5.123 0 6.004 6.004 0 00-3.431 5.142.75.75 0 001.498.07 4.5 4.5 0 018.99 0 .75.75 0 101.498-.07 6.005 6.005 0 00-3.432-5.142z"
></path>
</svg>`
}
export const VariantDisabledItemTrailing = ({}) => (
<PatternVariantDisabledItemTrailing {...PatternVariantDisabledItemTrailing.args} />
)
export const VariantDisabledItemLeadingTrailing = ListItemTemplate.bind({})
VariantDisabledItemLeadingTrailing.storyName = '[Variant] Disabled + leading/trailing visual'
VariantDisabledItemLeadingTrailing.args = {
...ListItemTemplate.args,
text: 'Disabled',
ariaDisabled: true,
leadingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zm.75 4.75a.75.75 0 00-1.5 0v2.5h-2.5a.75.75 0 000 1.5h2.5v2.5a.75.75 0 001.5 0v-2.5h2.5a.75.75 0 000-1.5h-2.5v-2.5z"
></path>
</svg>`,
trailingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M10.5 5a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0zm.061 3.073a4 4 0 10-5.123 0 6.004 6.004 0 00-3.431 5.142.75.75 0 001.498.07 4.5 4.5 0 018.99 0 .75.75 0 101.498-.07 6.005 6.005 0 00-3.432-5.142z"
></path>
</svg>`
}
export const VariantDisabledItemLeadingTrailing = ({}) => (
<PatternVariantDisabledItemLeadingTrailing {...PatternVariantDisabledItemLeadingTrailing.args} />
)
export const ActionSingleSelectItem = ListItemTemplate.bind({})
ActionSingleSelectItem.storyName = '[Actions] Single select'
ActionSingleSelectItem.args = {
text: 'Single select item',
singleSelect: true
}
export const TruncateText = ({}) => <PatternTruncateText {...PatternTruncateText.args} />
export const ActionSingleSelectItemWithLeadingVisual = ListItemTemplate.bind({})
ActionSingleSelectItemWithLeadingVisual.storyName = '[Actions] Single select + leading visual'
ActionSingleSelectItemWithLeadingVisual.args = {
text: 'Single select item',
singleSelect: true,
leadingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zm.75 4.75a.75.75 0 00-1.5 0v2.5h-2.5a.75.75 0 000 1.5h2.5v2.5a.75.75 0 001.5 0v-2.5h2.5a.75.75 0 000-1.5h-2.5v-2.5z"
></path>
</svg>`
}
export const ActionSingleSelectItemWithTrailingVisual = ListItemTemplate.bind({})
ActionSingleSelectItemWithTrailingVisual.storyName = '[Actions] Single select + trailing visual'
ActionSingleSelectItemWithTrailingVisual.args = {
text: 'Single select item',
singleSelect: true,
trailingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M10.5 5a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0zm.061 3.073a4 4 0 10-5.123 0 6.004 6.004 0 00-3.431 5.142.75.75 0 001.498.07 4.5 4.5 0 018.99 0 .75.75 0 101.498-.07 6.005 6.005 0 00-3.432-5.142z"
></path>
</svg>`
}
export const ActionSingleSelectItemWithLeadingAndTrailingVisual = ListItemTemplate.bind({})
ActionSingleSelectItemWithLeadingAndTrailingVisual.storyName = '[Actions] Single select + leading/trailing visual'
ActionSingleSelectItemWithLeadingAndTrailingVisual.args = {
text: 'Single select item',
singleSelect: true,
leadingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zm.75 4.75a.75.75 0 00-1.5 0v2.5h-2.5a.75.75 0 000 1.5h2.5v2.5a.75.75 0 001.5 0v-2.5h2.5a.75.75 0 000-1.5h-2.5v-2.5z"
></path>
</svg>`,
trailingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M10.5 5a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0zm.061 3.073a4 4 0 10-5.123 0 6.004 6.004 0 00-3.431 5.142.75.75 0 001.498.07 4.5 4.5 0 018.99 0 .75.75 0 101.498-.07 6.005 6.005 0 00-3.432-5.142z"
></path>
</svg>`
}
export const ActionMultiSelectItem = ListItemTemplate.bind({})
ActionMultiSelectItem.storyName = '[Actions] Multi select'
ActionMultiSelectItem.args = {
text: 'Multi select item',
multiSelect: true
}
export const ActionMultiSelectItemWithLeadingVisual = ListItemTemplate.bind({})
ActionMultiSelectItemWithLeadingVisual.storyName = '[Actions] Multi select + leading visual'
ActionMultiSelectItemWithLeadingVisual.args = {
text: 'Multi select item',
multiSelect: true,
leadingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zm.75 4.75a.75.75 0 00-1.5 0v2.5h-2.5a.75.75 0 000 1.5h2.5v2.5a.75.75 0 001.5 0v-2.5h2.5a.75.75 0 000-1.5h-2.5v-2.5z"
></path>
</svg>`
}
export const ActionMultiSelectItemWithTrailingVisual = ListItemTemplate.bind({})
ActionMultiSelectItemWithTrailingVisual.storyName = '[Actions] Multi select + trailing visual'
ActionMultiSelectItemWithTrailingVisual.args = {
text: 'Multi select item',
multiSelect: true,
trailingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M10.5 5a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0zm.061 3.073a4 4 0 10-5.123 0 6.004 6.004 0 00-3.431 5.142.75.75 0 001.498.07 4.5 4.5 0 018.99 0 .75.75 0 101.498-.07 6.005 6.005 0 00-3.432-5.142z"
></path>
</svg>`
}
export const ActionMultiSelectItemWithLeadingAndTrailingVisual = ListItemTemplate.bind({})
ActionMultiSelectItemWithLeadingAndTrailingVisual.storyName = '[Actions] Multi select + leading/trailing visual'
ActionMultiSelectItemWithLeadingAndTrailingVisual.args = {
text: 'Multi select item',
multiSelect: true,
trailingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M10.5 5a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0zm.061 3.073a4 4 0 10-5.123 0 6.004 6.004 0 00-3.431 5.142.75.75 0 001.498.07 4.5 4.5 0 018.99 0 .75.75 0 101.498-.07 6.005 6.005 0 00-3.432-5.142z"
></path>
</svg>`,
leadingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zm.75 4.75a.75.75 0 00-1.5 0v2.5h-2.5a.75.75 0 000 1.5h2.5v2.5a.75.75 0 001.5 0v-2.5h2.5a.75.75 0 000-1.5h-2.5v-2.5z"
></path>
</svg>`
}
export const ActionCollapsible = ListItemTemplate.bind({})
ActionCollapsible.storyName = '[Actions] Collapsible'
ActionCollapsible.args = {
...ListItemTemplate.args,
text: 'Collapsible',
collapsible: true,
collapsed: false
}
export const ActionCollapsibleWithLeadingVisual = ListItemTemplate.bind({})
ActionCollapsibleWithLeadingVisual.storyName = '[Actions] Collapsible + leading visual'
ActionCollapsibleWithLeadingVisual.args = {
...ListItemTemplate.args,
text: 'Collapsible',
collapsible: true,
collapsed: false,
leadingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zm.75 4.75a.75.75 0 00-1.5 0v2.5h-2.5a.75.75 0 000 1.5h2.5v2.5a.75.75 0 001.5 0v-2.5h2.5a.75.75 0 000-1.5h-2.5v-2.5z"
></path>
</svg>`
}
export const ActionCollapsibleWithTrailingVisual = ListItemTemplate.bind({})
ActionCollapsibleWithTrailingVisual.storyName = '[Actions] Collapsible + trailing visual'
ActionCollapsibleWithTrailingVisual.args = {
...ListItemTemplate.args,
text: 'Collapsible',
collapsible: true,
collapsed: false,
trailingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M10.5 5a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0zm.061 3.073a4 4 0 10-5.123 0 6.004 6.004 0 00-3.431 5.142.75.75 0 001.498.07 4.5 4.5 0 018.99 0 .75.75 0 101.498-.07 6.005 6.005 0 00-3.432-5.142z"
></path>
</svg>`
}
export const ActionCollapsibleWithLeadingAndTrailingVisual = ListItemTemplate.bind({})
ActionCollapsibleWithLeadingAndTrailingVisual.storyName = '[Actions] Collapsible + leading/trailing visual'
ActionCollapsibleWithLeadingAndTrailingVisual.args = {
...ListItemTemplate.args,
text: 'Collapsible',
collapsible: true,
collapsed: false,
leadingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zm.75 4.75a.75.75 0 00-1.5 0v2.5h-2.5a.75.75 0 000 1.5h2.5v2.5a.75.75 0 001.5 0v-2.5h2.5a.75.75 0 000-1.5h-2.5v-2.5z"
></path>
</svg>`,
trailingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M10.5 5a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0zm.061 3.073a4 4 0 10-5.123 0 6.004 6.004 0 00-3.431 5.142.75.75 0 001.498.07 4.5 4.5 0 018.99 0 .75.75 0 101.498-.07 6.005 6.005 0 00-3.432-5.142z"
></path>
</svg>`
}
export const DividerEmpty = DividerTemplate.bind({})
DividerEmpty.storyName = '[Divider] Empty default'
DividerEmpty.args = {}
export const DividerFilled = DividerTemplate.bind({})
DividerFilled.storyName = '[Divider] Empty filled'
DividerFilled.args = {
variant: 'ActionList-sectionDivider--filled'
}
export const DividerText = DividerTemplate.bind({})
DividerText.storyName = '[Divider] Title'
DividerText.args = {
title: 'Title',
id: 'some-id'
}
export const DividerTextFilled = DividerTemplate.bind({})
DividerTextFilled.storyName = '[Divider] Title filled'
DividerTextFilled.args = {
title: 'Title',
id: 'some-id',
variant: 'ActionList-sectionDivider--filled'
}
export const TruncateText = ListItemTemplate.bind({})
TruncateText.storyName = 'Truncate text'
TruncateText.args = {
...ListItemTemplate.args,
truncateItem: true,
text: 'Item with trailing visual',
trailingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zm.75 4.75a.75.75 0 00-1.5 0v2.5h-2.5a.75.75 0 000 1.5h2.5v2.5a.75.75 0 001.5 0v-2.5h2.5a.75.75 0 000-1.5h-2.5v-2.5z"
></path>
</svg>`,
leadingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M10.5 5a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0zm.061 3.073a4 4 0 10-5.123 0 6.004 6.004 0 00-3.431 5.142.75.75 0 001.498.07 4.5 4.5 0 018.99 0 .75.75 0 101.498-.07 6.005 6.005 0 00-3.432-5.142z"
></path>
</svg>`
}
export const WrapText = ListItemTemplate.bind({})
WrapText.storyName = 'Wrap text'
WrapText.args = {
...ListItemTemplate.args,
text: 'This is a very long string of text that will wrap to another line on smaller screens',
trailingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zm.75 4.75a.75.75 0 00-1.5 0v2.5h-2.5a.75.75 0 000 1.5h2.5v2.5a.75.75 0 001.5 0v-2.5h2.5a.75.75 0 000-1.5h-2.5v-2.5z"
></path>
</svg>`,
leadingVisual: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M10.5 5a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0zm.061 3.073a4 4 0 10-5.123 0 6.004 6.004 0 00-3.431 5.142.75.75 0 001.498.07 4.5 4.5 0 018.99 0 .75.75 0 101.498-.07 6.005 6.005 0 00-3.432-5.142z"
></path>
</svg>`
}
export const WrapText = ({}) => <PatternWrapText {...PatternWrapText.args} />

View File

@ -1,199 +0,0 @@
import React from 'react'
import clsx from 'clsx'
import {ListTemplate} from './ActionList.stories'
import {ListItemTemplate} from './ActionListItem.stories'
export default {
title: 'Components/ActionList/ActionTreeView',
excludeStories: ['ActionListTreeViewTemplate'],
layout: 'padded',
argTypes: {
showGroupIcon: {
control: {type: 'boolean'},
description: 'show subgroup leading icon',
table: {
category: 'Interactive'
}
},
showSubItemIcon: {
control: {type: 'boolean'},
description: 'show subgroup item leading icon',
table: {
category: 'Interactive'
}
},
text: {
defaultValue: '',
type: 'string',
name: 'title',
description: 'string',
table: {
category: 'HTML'
}
},
truncateItem: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'CSS'
}
}
}
}
const folder = `<svg aria-hidden="true" role="img" class="octicon octicon-file-directory-fill" viewBox="0 0 24 24" width="16" height="16" fill="currentColor" style="display:inline-block;user-select:none;vertical-align:text-bottom;overflow:visible"><path fill-rule="evenodd" d="M2 4.75C2 3.784 2.784 3 3.75 3h4.971c.58 0 1.12.286 1.447.765l1.404 2.063a.25.25 0 00.207.11h8.471c.966 0 1.75.783 1.75 1.75V19.25A1.75 1.75 0 0120.25 21H3.75A1.75 1.75 0 012 19.25V4.75z"></path></svg>`
const file = `<svg aria-hidden="true" role="img" class="octicon octicon-file" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" style="display:inline-block;user-select:none;vertical-align:text-bottom;overflow:visible"><path fill-rule="evenodd" d="M3.75 1.5a.25.25 0 00-.25.25v11.5c0 .138.112.25.25.25h8.5a.25.25 0 00.25-.25V6H9.75A1.75 1.75 0 018 4.25V1.5H3.75zm5.75.56v2.19c0 .138.112.25.25.25h2.19L9.5 2.06zM2 1.75C2 .784 2.784 0 3.75 0h5.086c.464 0 .909.184 1.237.513l3.414 3.414c.329.328.513.773.513 1.237v8.086A1.75 1.75 0 0112.25 15h-8.5A1.75 1.75 0 012 13.25V1.75z"></path></svg>`
const trailingVisual = `<svg aria-hidden="true" role="img" class="color-fg-attention" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" style="display:inline-block;user-select:none;vertical-align:text-bottom;overflow:visible"><path fill-rule="evenodd" d="M2.75 2.5h10.5a.25.25 0 01.25.25v10.5a.25.25 0 01-.25.25H2.75a.25.25 0 01-.25-.25V2.75a.25.25 0 01.25-.25zM13.25 1H2.75A1.75 1.75 0 001 2.75v10.5c0 .966.784 1.75 1.75 1.75h10.5A1.75 1.75 0 0015 13.25V2.75A1.75 1.75 0 0013.25 1zM8 10a2 2 0 100-4 2 2 0 000 4z"></path></svg>`
export const ActionListTreeViewTemplate = ({showGroupIcon, showSubItemIcon, text, truncateItem}) => (
<ListTemplate ariaLabel="Some description" role="tree" variant="ActionList--tree">
<>
<ListItemTemplate
ariaLevel="1"
ariaSetSize="2"
ariaPosInset="2"
treeitem
containsSubItem
text="level 1"
collapsibleLeading
leadingVisual={showGroupIcon && folder}
href=""
truncateItem={truncateItem}
children={
<ListTemplate
role="group"
containsSubItem
subGroup
ariaLabel="Sub nav descrioption"
children={
<>
<ListItemTemplate
truncateItem={truncateItem}
ariaLevel="2"
ariaSetSize="2"
ariaPosInset="1"
treeitem
subItem
text={text}
href=""
leadingVisual={showSubItemIcon && file}
trailingVisual={trailingVisual}
/>
<ListItemTemplate
truncateItem={truncateItem}
ariaLevel="2"
ariaSetSize="2"
ariaPosInset="2"
treeitem
subItem
containsSubItem
collapsibleLeading
text="level 2"
href=""
leadingVisual={showGroupIcon && folder}
trailingVisual={trailingVisual}
children={
<ListTemplate
role="group"
containsSubItem
subGroup
ariaLabel="Sub nav descrioption"
children={
<>
<ListItemTemplate
truncateItem={truncateItem}
ariaLevel="3"
ariaSetSize="2"
ariaPosInset="1"
subItem
treeitem
containsSubItem
collapsibleLeading
text="level 3"
href=""
leadingVisual={showGroupIcon && folder}
trailingVisual={trailingVisual}
children={
<ListTemplate
role="group"
containsSubItem
subGroup
ariaLabel="Sub nav descrioption"
children={
<>
<ListItemTemplate
truncateItem={truncateItem}
ariaLevel="4"
ariaSetSize="4"
ariaPosInset="1"
subItem
treeitem
text={text}
href=""
leadingVisual={showSubItemIcon && file}
trailingVisual={trailingVisual}
/>
<ListItemTemplate
truncateItem={truncateItem}
ariaLevel="4"
ariaSetSize="4"
ariaPosInset="2"
subItem
treeitem
text={text}
href=""
leadingVisual={showSubItemIcon && file}
trailingVisual={trailingVisual}
/>
<ListItemTemplate
truncateItem={truncateItem}
ariaLevel="4"
ariaSetSize="4"
ariaPosInset="3"
subItem
treeitem
text={text}
href=""
leadingVisual={showSubItemIcon && file}
trailingVisual={trailingVisual}
/>
</>
}
/>
}
/>
<ListItemTemplate
truncateItem={truncateItem}
ariaLevel="3"
ariaSetSize="2"
ariaPosInset="2"
treeitem
subItem
text={text}
href=""
leadingVisual={showSubItemIcon && file}
trailingVisual={trailingVisual}
/>
</>
}
/>
}
/>
</>
}
/>
}
/>
</>
</ListTemplate>
)
// create a "playground" demo page that may set some defaults and allow story to access component controls
export const Playground = ActionListTreeViewTemplate.bind({})
Playground.args = {
showSubItemIcon: true,
showGroupIcon: true,
text: 'item'
}

View File

@ -1,19 +1,19 @@
import React from 'react'
import clsx from 'clsx'
import { PageLayoutTemplate } from './PageLayout.stories'
import {PageLayoutTemplate} from './PageLayout.stories'
import {SplitPageLayoutTemplate} from './SplitPageLayout.stories'
import {RepoSettings, DiscussionsPane} from '../ActionList/ActionListExamples.stories'
import {RepoSettings, DiscussionsPane} from '../NavigationList/NavigationListExamples.stories'
import {LayoutAlphaTemplate} from './LayoutAlpha.stories'
export default {
title: 'Components/Layout/Beta/Examples'
}
export const Settings = SplitPageLayoutTemplate.bind({});
Settings.storyName = 'Settings';
export const Settings = SplitPageLayoutTemplate.bind({})
Settings.storyName = 'Settings'
Settings.parameters = {
layout: 'fullscreen',
};
layout: 'fullscreen'
}
Settings.args = {
// Structure
innerSpacing: 'normal',
@ -39,19 +39,25 @@ Settings.args = {
contentChildren: (
<>
<h3 className="f3 text-normal">General</h3>
<div className="Box mt-3 p-3" style={{minHeight: '200px'}}> </div>
<div className="Box mt-3 p-3" style={{minHeight: '400px'}}> </div>
<div className="Box mt-3 p-3" style={{minHeight: '600px'}}> </div>
<h3 className="f3 text-normal">General</h3>
<div className="Box mt-3 p-3" style={{minHeight: '200px'}}>
{' '}
</div>
<div className="Box mt-3 p-3" style={{minHeight: '400px'}}>
{' '}
</div>
<div className="Box mt-3 p-3" style={{minHeight: '600px'}}>
{' '}
</div>
</>
)
};
}
export const Discussions = PageLayoutTemplate.bind({});
export const Discussions = PageLayoutTemplate.bind({})
Discussions.parameters = {
layout: 'fullscreen',
};
Discussions.storyName = 'Discussions';
layout: 'fullscreen'
}
Discussions.storyName = 'Discussions'
Discussions.args = {
responsiveVariant: 'separateRegions',
panePosition: 'start',
@ -61,16 +67,26 @@ Discussions.args = {
<>
<div class="d-block d-md-none">
<div className="d-flex flex-items-center width-full flex-wrap" style={{gap: '16px'}}>
<h2 className="h3 ml-2 mr-2 flex-1">All discussions<span class="no-wrap">
{/*
<h2 className="h3 ml-2 mr-2 flex-1">
All discussions
<span class="no-wrap">
{/*
I'm using a `no-wrap` class between the heading and the `triangle-down`
octicon to make sure it won't be ever rendered as a typographic widow
*/}
</span><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path d="M4.427 7.427l3.396 3.396a.25.25 0 00.354 0l3.396-3.396A.25.25 0 0011.396 7H4.604a.25.25 0 00-.177.427z"></path></svg>
</span>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path d="M4.427 7.427l3.396 3.396a.25.25 0 00.354 0l3.396-3.396A.25.25 0 0011.396 7H4.604a.25.25 0 00-.177.427z"></path>
</svg>
</h2>
<button class="btn btn-primary">New</button>
<button class="btn btn-octicon" style={{margin: 0, border: '1px solid var(--color-border-default)', width: '32px', height: '32px'}}>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path d="M8 9a1.5 1.5 0 100-3 1.5 1.5 0 000 3zM1.5 9a1.5 1.5 0 100-3 1.5 1.5 0 000 3zm13 0a1.5 1.5 0 100-3 1.5 1.5 0 000 3z"></path></svg>
<button
class="btn btn-octicon"
style={{margin: 0, border: '1px solid var(--color-border-default)', width: '32px', height: '32px'}}
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path d="M8 9a1.5 1.5 0 100-3 1.5 1.5 0 000 3zM1.5 9a1.5 1.5 0 100-3 1.5 1.5 0 000 3zm13 0a1.5 1.5 0 100-3 1.5 1.5 0 000 3z"></path>
</svg>
</button>
</div>
<div className="mt-3">
@ -82,8 +98,12 @@ Discussions.args = {
<input className="form-control flex-1" placeholder="Search discussions" />
<div class="BtnGroup d-block">
<button class="BtnGroup-item btn" type="button">New</button>
<button class="BtnGroup-item btn" type="button">Top</button>
<button class="BtnGroup-item btn" type="button">
New
</button>
<button class="BtnGroup-item btn" type="button">
Top
</button>
</div>
<button class="btn">Labels</button>
@ -105,33 +125,38 @@ Discussions.args = {
contentChildren: (
<>
<LayoutAlphaTemplate
container='xl'
sidebarPosition='end'
sidebarWidth='narrow'
flowRowUntil='lg'
container="xl"
sidebarPosition="end"
sidebarWidth="narrow"
flowRowUntil="lg"
mainChildren={
<>
<div className="Box p-3" style={{minHeight: '800px'}}> </div>
<div className="Box p-3" style={{minHeight: '800px'}}>
{' '}
</div>
</>
}
sidebarChildren={
<>
<div className="Box p-3" style={{minHeight: '200px'}}> </div>
<div className="Box mt-3 p-3" style={{minHeight: '200px'}}> </div>
<div className="Box p-3" style={{minHeight: '200px'}}>
{' '}
</div>
<div className="Box mt-3 p-3" style={{minHeight: '200px'}}>
{' '}
</div>
</>
}
/>
</>
)
};
}
export const IssueDetail = PageLayoutTemplate.bind({});
IssueDetail.storyName = 'Issue detail';
export const IssueDetail = PageLayoutTemplate.bind({})
IssueDetail.storyName = 'Issue detail'
IssueDetail.parameters = {
layout: 'fullscreen',
};
layout: 'fullscreen'
}
IssueDetail.args = {
panePosition: 'end',
paneWidth: 'default',
hasHeader: true,
@ -146,22 +171,46 @@ IssueDetail.args = {
</h2>
<div className="d-flex flex-items-center flex-wrap mt-2" style={{gap: '8px'}}>
<span title="Status: Open" class="State State--open">
<svg height="16" class="octicon octicon-issue-opened" viewBox="0 0 16 16" version="1.1" width="16" aria-hidden="true"><path d="M8 9.5a1.5 1.5 0 100-3 1.5 1.5 0 000 3z"></path><path fill-rule="evenodd" d="M8 0a8 8 0 100 16A8 8 0 008 0zM1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0z"></path></svg> Open
<svg
height="16"
class="octicon octicon-issue-opened"
viewBox="0 0 16 16"
version="1.1"
width="16"
aria-hidden="true"
>
<path d="M8 9.5a1.5 1.5 0 100-3 1.5 1.5 0 000 3z"></path>
<path
fill-rule="evenodd"
d="M8 0a8 8 0 100 16A8 8 0 008 0zM1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0z"
></path>
</svg>{' '}
Open
</span>
<span className="color-fg-muted">
<strong class="color-fg-default">monalisa</strong> opened this issue 6 days ago
</span>
<span className="color-fg-muted"><strong class="color-fg-default">monalisa</strong> opened this issue 6 days ago</span>
</div>
</>
),
contentChildren: (
<>
<div className="Box p-3" style={{minHeight: '1200px'}}> </div>
<div className="Box p-3" style={{minHeight: '1200px'}}>
{' '}
</div>
</>
),
paneChildren: (
<>
<div className="Box p-3" style={{minHeight: '140px'}}> </div>
<div className="Box p-3 mt-3" style={{minHeight: '200px'}}> </div>
<div className="Box p-3 mt-3" style={{minHeight: '140px'}}> </div>
<div className="Box p-3" style={{minHeight: '140px'}}>
{' '}
</div>
<div className="Box p-3 mt-3" style={{minHeight: '200px'}}>
{' '}
</div>
<div className="Box p-3 mt-3" style={{minHeight: '140px'}}>
{' '}
</div>
</>
)
};
}

View File

@ -0,0 +1,97 @@
import React from 'react'
import clsx from 'clsx'
import {NavigationListItemTemplate} from './NavigationListItem.stories'
import ConditionalWrapper from '../../helpers/ConditionalWrapper'
export default {
title: 'Components/NavigationList/NavigationList',
excludeStories: ['NavigationListTemplate'],
argTypes: {
showDividers: {
control: {type: 'boolean'},
description: 'Show dividers between items',
table: {
category: 'CSS'
}
},
ariaLabel: {
name: 'ariaLabel',
type: 'string',
description: 'Required if no visible group title provided by NavigationListDivider',
table: {
category: 'HTML'
}
},
ariaLabelledBy: {
name: 'ariaLabelledBy',
type: 'string',
description: 'Reference ID of NavigationListDivider',
table: {
category: 'HTML'
}
},
children: {
table: {
disable: true
}
},
listPadding: {
options: [0, 1], // iterator
mapping: [null, 'ActionList--full'], // values
control: {
type: 'inline-radio',
labels: ['inset', 'full-bleed']
},
description: 'ActionList includes 8px padding by default, full-bleed removes all padding',
table: {
category: 'CSS'
}
},
listType: {
options: [0, 1], // iterator
mapping: ['parent', 'nested'], // values
control: {
type: 'inline-radio',
labels: ['parent', 'nested']
},
description: 'NavigationList can be a parent list with a <nav> or a nested list with just <ul>',
table: {
category: 'CSS'
}
}
}
}
export const NavigationListTemplate = ({showDividers, children, ariaLabel, ariaLabelledBy, listPadding, listType}) => (
// wrap ul in <nav> if parent list
<ConditionalWrapper condition={listType === 'parent'} wrap={children => <nav>{children}</nav>}>
<ul
className={clsx(
'ActionList',
showDividers && 'ActionList--divided',
listType === 'nested' && 'ActionList--subGroup',
listPadding && `${listPadding}`
)}
role="list"
aria-label={ariaLabel && ariaLabel}
aria-labelledby={ariaLabelledBy && ariaLabelledBy}
>
<>{children}</>
</ul>
</ConditionalWrapper>
)
export const Playground = NavigationListTemplate.bind({})
Playground.args = {
listType: 'parent',
ariaLabel: '',
showDividers: false,
listPadding: 0,
ariaLabelledBy: '',
children: (
<>
<NavigationListItemTemplate text="Nav list item" />
<NavigationListItemTemplate text="Nav list item" />
</>
)
}

View File

@ -0,0 +1,63 @@
import React from 'react'
import {NavigationListTemplate} from './NavigationList.stories'
import {DividerTemplate} from '../../ui-patterns/ActionList/ActionListDivider.stories.jsx'
export default {
title: 'Components/NavigationList/NavigationListDivider',
excludeStories: ['NavigationListDividerTemplate'],
argTypes: {
variant: {
options: [0, 1], // iterator
mapping: ['', 'ActionList-sectionDivider--filled'], // values
control: {
type: 'inline-radio',
labels: ['subtle', 'filled']
},
table: {
category: 'CSS'
}
},
title: {
defaultValue: '',
type: 'string',
name: 'title',
description: 'string',
table: {
category: 'HTML'
}
},
description: {
defaultValue: '',
type: 'string',
name: 'description',
description: 'string',
table: {
category: 'HTML'
}
},
id: {
defaultValue: '',
type: 'string',
name: 'id',
description: 'Provide label for NavigationList <ul> aria-labelledby',
table: {
category: 'HTML'
}
}
}
}
export const NavigationListDividerTemplate = DividerTemplate.bind({})
export const Playground = NavigationListDividerTemplate.bind({})
Playground.args = {
title: 'Section title',
description: 'Section description'
}
Playground.decorators = [
Story => (
<NavigationListTemplate>
<Story />
</NavigationListTemplate>
)
]

View File

@ -0,0 +1,27 @@
import React from 'react'
import {NavigationListTemplate} from './NavigationList.stories'
import {
PatternTitle,
PatternFilled,
PatternWithDescription,
PatternSeparator
} from '../../ui-patterns/ActionList/ActionListDividerFeatures.stories.jsx'
export default {
title: 'Components/NavigationList/NavigationListDivider/Features',
decorators: [
Story => (
<NavigationListTemplate>
<Story />
</NavigationListTemplate>
)
]
}
export const Title = ({}) => <PatternTitle {...PatternTitle.args} />
export const Filled = ({}) => <PatternFilled {...PatternFilled.args} />
export const WithDescription = ({}) => <PatternWithDescription {...PatternWithDescription.args} />
export const Separator = ({}) => <PatternSeparator {...PatternSeparator.args} />

View File

@ -0,0 +1,161 @@
import React from 'react'
import clsx from 'clsx'
import {NavigationListDividerTemplate} from './NavigationListDivider.stories'
import {NavigationListItemTemplate} from './NavigationListItem.stories'
import {NavigationListTemplate} from './NavigationList.stories'
import {NavigationListItemCollapsibleTemplate} from './NavigationListItemCollapsible.stories'
export default {
title: 'Components/NavigationList/Examples'
}
export const RepoSettings = ({}) => (
<nav>
<NavigationListTemplate>
<NavigationListItemTemplate
listSemantic
text="General"
href="#content"
leadingVisualSize="ActionList-content--visual16"
leadingVisual={`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.429 1.525a6.593 6.593 0 011.142 0c.036.003.108.036.137.146l.289 1.105c.147.56.55.967.997 1.189.174.086.341.183.501.29.417.278.97.423 1.53.27l1.102-.303c.11-.03.175.016.195.046.219.31.41.641.573.989.014.031.022.11-.059.19l-.815.806c-.411.406-.562.957-.53 1.456a4.588 4.588 0 010 .582c-.032.499.119 1.05.53 1.456l.815.806c.08.08.073.159.059.19a6.494 6.494 0 01-.573.99c-.02.029-.086.074-.195.045l-1.103-.303c-.559-.153-1.112-.008-1.529.27-.16.107-.327.204-.5.29-.449.222-.851.628-.998 1.189l-.289 1.105c-.029.11-.101.143-.137.146a6.613 6.613 0 01-1.142 0c-.036-.003-.108-.037-.137-.146l-.289-1.105c-.147-.56-.55-.967-.997-1.189a4.502 4.502 0 01-.501-.29c-.417-.278-.97-.423-1.53-.27l-1.102.303c-.11.03-.175-.016-.195-.046a6.492 6.492 0 01-.573-.989c-.014-.031-.022-.11.059-.19l.815-.806c.411-.406.562-.957.53-1.456a4.587 4.587 0 010-.582c.032-.499-.119-1.05-.53-1.456l-.815-.806c-.08-.08-.073-.159-.059-.19a6.44 6.44 0 01.573-.99c.02-.029.086-.075.195-.045l1.103.303c.559.153 1.112.008 1.529-.27.16-.107.327-.204.5-.29.449-.222.851-.628.998-1.189l.289-1.105c.029-.11.101-.143.137-.146zM8 0c-.236 0-.47.01-.701.03-.743.065-1.29.615-1.458 1.261l-.29 1.106c-.017.066-.078.158-.211.224a5.994 5.994 0 00-.668.386c-.123.082-.233.09-.3.071L3.27 2.776c-.644-.177-1.392.02-1.82.63a7.977 7.977 0 00-.704 1.217c-.315.675-.111 1.422.363 1.891l.815.806c.05.048.098.147.088.294a6.084 6.084 0 000 .772c.01.147-.038.246-.088.294l-.815.806c-.474.469-.678 1.216-.363 1.891.2.428.436.835.704 1.218.428.609 1.176.806 1.82.63l1.103-.303c.066-.019.176-.011.299.071.213.143.436.272.668.386.133.066.194.158.212.224l.289 1.106c.169.646.715 1.196 1.458 1.26a8.094 8.094 0 001.402 0c.743-.064 1.29-.614 1.458-1.26l.29-1.106c.017-.066.078-.158.211-.224a5.98 5.98 0 00.668-.386c.123-.082.233-.09.3-.071l1.102.302c.644.177 1.392-.02 1.82-.63.268-.382.505-.789.704-1.217.315-.675.111-1.422-.364-1.891l-.814-.806c-.05-.048-.098-.147-.088-.294a6.1 6.1 0 000-.772c-.01-.147.039-.246.088-.294l.814-.806c.475-.469.679-1.216.364-1.891a7.992 7.992 0 00-.704-1.218c-.428-.609-1.176-.806-1.82-.63l-1.103.303c-.066.019-.176.011-.299-.071a5.991 5.991 0 00-.668-.386c-.133-.066-.194-.158-.212-.224L10.16 1.29C9.99.645 9.444.095 8.701.031A8.094 8.094 0 008 0zm1.5 8a1.5 1.5 0 11-3 0 1.5 1.5 0 013 0zM11 8a3 3 0 11-6 0 3 3 0 016 0z"></path></svg>`}
/>
<NavigationListDividerTemplate />
<NavigationListDividerTemplate title="Access" id="group-id-1" />
<NavigationListItemTemplate hasSubItem>
<NavigationListTemplate ariaLabelledBy="group-id-1" listType="nested">
<NavigationListItemTemplate
listSemantic
text="Collaborators"
href="/"
leadingVisualSize="ActionList-content--visual16"
leadingVisual={`<svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-people"><path fill-rule="evenodd" d="M5.5 3.5a2 2 0 100 4 2 2 0 000-4zM2 5.5a3.5 3.5 0 115.898 2.549 5.507 5.507 0 013.034 4.084.75.75 0 11-1.482.235 4.001 4.001 0 00-7.9 0 .75.75 0 01-1.482-.236A5.507 5.507 0 013.102 8.05 3.49 3.49 0 012 5.5zM11 4a.75.75 0 100 1.5 1.5 1.5 0 01.666 2.844.75.75 0 00-.416.672v.352a.75.75 0 00.574.73c1.2.289 2.162 1.2 2.522 2.372a.75.75 0 101.434-.44 5.01 5.01 0 00-2.56-3.012A3 3 0 0011 4z"></path></svg>`}
/>
<NavigationListItemCollapsibleTemplate
listSemantic
text="Moderation"
leadingVisual={`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M1.5 2.75a.25.25 0 01.25-.25h8.5a.25.25 0 01.25.25v5.5a.25.25 0 01-.25.25h-3.5a.75.75 0 00-.53.22L3.5 11.44V9.25a.75.75 0 00-.75-.75h-1a.25.25 0 01-.25-.25v-5.5zM1.75 1A1.75 1.75 0 000 2.75v5.5C0 9.216.784 10 1.75 10H2v1.543a1.457 1.457 0 002.487 1.03L7.061 10h3.189A1.75 1.75 0 0012 8.25v-5.5A1.75 1.75 0 0010.25 1h-8.5zM14.5 4.75a.25.25 0 00-.25-.25h-.5a.75.75 0 110-1.5h.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0114.25 12H14v1.543a1.457 1.457 0 01-2.487 1.03L9.22 12.28a.75.75 0 111.06-1.06l2.22 2.22v-2.19a.75.75 0 01.75-.75h1a.25.25 0 00.25-.25v-5.5z"></path></svg>`}
collapsePosition={1}
containsSubItem
containsActiveSubItem
leadingVisualSize="ActionList-content--visual16"
>
<NavigationListTemplate listType="nested">
<NavigationListItemTemplate listSemantic text="Interaction limits" href="#" subItem />
<NavigationListItemTemplate listSemantic text="Code review limits" href="#" subItem ariaCurrent="page" />
<NavigationListItemTemplate listSemantic text="Reported content" href="#" subItem />
</NavigationListTemplate>
</NavigationListItemCollapsibleTemplate>
</NavigationListTemplate>
</NavigationListItemTemplate>
<NavigationListDividerTemplate />
<NavigationListDividerTemplate title="Code and automation" id="group-id-2" />
<NavigationListItemTemplate hasSubItem>
<NavigationListTemplate ariaLabelledBy="group-id-2" listType="nested">
<NavigationListItemTemplate
listSemantic
text="Branches"
href="/"
leadingVisualSize="ActionList-content--visual16"
leadingVisual={`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M11.75 2.5a.75.75 0 100 1.5.75.75 0 000-1.5zm-2.25.75a2.25 2.25 0 113 2.122V6A2.5 2.5 0 0110 8.5H6a1 1 0 00-1 1v1.128a2.251 2.251 0 11-1.5 0V5.372a2.25 2.25 0 111.5 0v1.836A2.492 2.492 0 016 7h4a1 1 0 001-1v-.628A2.25 2.25 0 019.5 3.25zM4.25 12a.75.75 0 100 1.5.75.75 0 000-1.5zM3.5 3.25a.75.75 0 111.5 0 .75.75 0 01-1.5 0z"></path></svg>`}
/>
<NavigationListItemTemplate
listSemantic
text="Actions"
href="/"
leadingVisualSize="ActionList-content--visual16"
leadingVisual={`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zM6.379 5.227A.25.25 0 006 5.442v5.117a.25.25 0 00.379.214l4.264-2.559a.25.25 0 000-.428L6.379 5.227z"></path></svg>`}
/>
<NavigationListItemTemplate
listSemantic
text="Webhooks"
href="/"
leadingVisualSize="ActionList-content--visual16"
leadingVisual={`<svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-broadcast">
<path fill-rule="evenodd" d="M3.267 1.457c.3.286.312.76.026 1.06A6.475 6.475 0 001.5 7a6.472 6.472 0 001.793 4.483.75.75 0 01-1.086 1.034 8.89 8.89 0 01-.276-.304l.569-.49-.569.49A7.971 7.971 0 010 7c0-2.139.84-4.083 2.207-5.517a.75.75 0 011.06-.026zm9.466 0a.75.75 0 011.06.026A7.975 7.975 0 0116 7c0 2.139-.84 4.083-2.207 5.517a.75.75 0 11-1.086-1.034A6.475 6.475 0 0014.5 7a6.475 6.475 0 00-1.793-4.483.75.75 0 01.026-1.06zM8.75 8.582a1.75 1.75 0 10-1.5 0v5.668a.75.75 0 001.5 0V8.582zM5.331 4.736a.75.75 0 10-1.143-.972A4.983 4.983 0 003 7c0 1.227.443 2.352 1.177 3.222a.75.75 0 001.146-.967A3.483 3.483 0 014.5 7c0-.864.312-1.654.831-2.264zm6.492-.958a.75.75 0 00-1.146.967c.514.61.823 1.395.823 2.255 0 .86-.31 1.646-.823 2.255a.75.75 0 101.146.967A4.983 4.983 0 0013 7a4.983 4.983 0 00-1.177-3.222z"></path>
</svg>`}
/>
<NavigationListItemTemplate
listSemantic
text="Environments"
href="/"
leadingVisualSize="ActionList-content--visual16"
leadingVisual={`<svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-server">
<path fill-rule="evenodd" d="M1.75 1A1.75 1.75 0 000 2.75v4c0 .372.116.717.314 1a1.742 1.742 0 00-.314 1v4c0 .966.784 1.75 1.75 1.75h12.5A1.75 1.75 0 0016 12.75v-4c0-.372-.116-.717-.314-1 .198-.283.314-.628.314-1v-4A1.75 1.75 0 0014.25 1H1.75zm0 7.5a.25.25 0 00-.25.25v4c0 .138.112.25.25.25h12.5a.25.25 0 00.25-.25v-4a.25.25 0 00-.25-.25H1.75zM1.5 2.75a.25.25 0 01.25-.25h12.5a.25.25 0 01.25.25v4a.25.25 0 01-.25.25H1.75a.25.25 0 01-.25-.25v-4zm5.5 2A.75.75 0 017.75 4h4.5a.75.75 0 010 1.5h-4.5A.75.75 0 017 4.75zM7.75 10a.75.75 0 000 1.5h4.5a.75.75 0 000-1.5h-4.5zM3 4.75A.75.75 0 013.75 4h.5a.75.75 0 010 1.5h-.5A.75.75 0 013 4.75zM3.75 10a.75.75 0 000 1.5h.5a.75.75 0 000-1.5h-.5z"></path>
</svg>`}
/>
</NavigationListTemplate>
</NavigationListItemTemplate>
</NavigationListTemplate>
</nav>
)
export const NavDiscussionsPane = NavigationListTemplate.bind({})
NavDiscussionsPane.storyName = 'Discussions pane'
NavDiscussionsPane.args = {
...NavigationListTemplate.args,
...NavigationListItemTemplate.args,
ariaLabel: 'Discussion type navigation',
showDividers: false,
children: (
<>
<NavigationListItemTemplate
listSemantic
text="All discussions"
href="/"
ariaCurrent={true}
leadingVisualSize="ActionList-content--visual16"
leadingVisual={`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M1.5 2.75a.25.25 0 01.25-.25h8.5a.25.25 0 01.25.25v5.5a.25.25 0 01-.25.25h-3.5a.75.75 0 00-.53.22L3.5 11.44V9.25a.75.75 0 00-.75-.75h-1a.25.25 0 01-.25-.25v-5.5zM1.75 1A1.75 1.75 0 000 2.75v5.5C0 9.216.784 10 1.75 10H2v1.543a1.457 1.457 0 002.487 1.03L7.061 10h3.189A1.75 1.75 0 0012 8.25v-5.5A1.75 1.75 0 0010.25 1h-8.5zM14.5 4.75a.25.25 0 00-.25-.25h-.5a.75.75 0 110-1.5h.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0114.25 12H14v1.543a1.457 1.457 0 01-2.487 1.03L9.22 12.28a.75.75 0 111.06-1.06l2.22 2.22v-2.19a.75.75 0 01.75-.75h1a.25.25 0 00.25-.25v-5.5z"></path></svg>`}
/>
<NavigationListDividerTemplate />
<NavigationListItemTemplate
listSemantic
text="Announcements"
href="/"
leadingVisualSize="ActionList-content--visual16"
leadingVisual={`🔔`}
/>
<NavigationListItemTemplate
listSemantic
text="General"
href="/"
leadingVisualSize="ActionList-content--visual16"
leadingVisual={`💬`}
/>
<NavigationListItemTemplate
listSemantic
text="Ideas"
href="/"
leadingVisualSize="ActionList-content--visual16"
leadingVisual={`🏮`}
/>
<NavigationListItemTemplate
listSemantic
text="Questions and answers"
href="/"
leadingVisualSize="ActionList-content--visual16"
leadingVisual={`🌻`}
/>
<NavigationListItemTemplate
listSemantic
text="Show and tell"
href="/"
leadingVisualSize="ActionList-content--visual16"
leadingVisual={`👋`}
/>
<NavigationListItemTemplate
listSemantic
text="Polls"
href="/"
leadingVisualSize="ActionList-content--visual16"
leadingVisual={`🍒`}
/>
</>
)
}
NavDiscussionsPane.decorators = [
Story => (
<nav>
<Story />
</nav>
)
]

View File

@ -0,0 +1,19 @@
import React from 'react'
import {
PatternShowDividers,
PatternInsetPadding,
PatternFullBleed,
PatternNestedGroup
} from '../../ui-patterns/ActionList/ActionListFeatures.stories.jsx'
export default {
title: 'Components/NavigationList/NavigationList/Features'
}
export const ShowDividers = ({}) => <PatternShowDividers {...PatternShowDividers.args} />
export const InsetPadding = ({}) => <PatternInsetPadding {...PatternInsetPadding.args} />
export const FullBleed = ({}) => <PatternFullBleed {...PatternFullBleed.args} />
export const NestedGroup = ({}) => <PatternNestedGroup {...PatternNestedGroup.args} />

View File

@ -0,0 +1,167 @@
import React from 'react'
import {NavigationListTemplate} from './NavigationList.stories'
import {ListItemTemplate} from '../../ui-patterns/ActionList/ActionListItem.stories.jsx'
export default {
title: 'Components/NavigationList/NavigationListItem',
excludeStories: ['NavigationListItemTemplate'],
argTypes: {
size: {
options: [0, 1, 2], // iterator
mapping: ['', 'ActionList-content--sizeMedium', 'ActionList-content--sizeLarge'], // values
control: {
type: 'inline-radio',
labels: ['default', 'medium', 'large']
},
description: 'small (default), medium, large',
defaultValue: '',
table: {
category: 'CSS'
}
},
variant: {
options: [0, 1], // iterator
mapping: ['', 'ActionList-item--danger'], // values
control: {
type: 'inline-radio',
labels: ['default', 'danger']
},
defaultValue: '',
table: {
category: 'CSS'
}
},
subItem: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'CSS'
}
},
hasSubItem: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'CSS'
}
},
truncateItem: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'CSS'
}
},
leadingVisual: {
defaultValue: '',
name: 'leadingVisual',
type: 'string',
description: 'Paste [Octicon](https://primer.style/octicons/) in control field',
table: {
category: 'HTML'
}
},
leadingVisualSize: {
options: [0, 1, 2], // iterator
mapping: ['ActionList-content--visual16', 'ActionList-content--visual20', 'ActionList-content--visual24'], // values
control: {
type: 'inline-radio',
labels: ['16px', '20px', '24px']
},
description: 'leading visual width',
defaultValue: 'ActionList-content--visual16',
table: {
category: 'CSS'
}
},
trailingVisual: {
defaultValue: '',
name: 'trailingVisual',
type: 'string',
description: 'Paste [Octicon](https://primer.style/octicons/) in control field',
table: {
category: 'HTML'
}
},
text: {
defaultValue: 'Item label',
type: 'string',
name: 'text',
description: 'string',
table: {
category: 'HTML'
}
},
href: {
defaultValue: '',
type: 'string',
name: 'href',
description: 'Item link (href)',
table: {
category: 'HTML'
}
},
ariaCurrent: {
options: ['location', 'page', null],
control: {type: 'inline-radio'},
description: 'location for anchor links, page for global page navigation',
table: {
category: 'HTML'
}
},
description: {
defaultValue: '',
type: 'string',
name: 'description',
description: 'string',
table: {
category: 'HTML'
}
},
descriptionVariant: {
options: [0, 1], // iterator
mapping: ['', 'ActionList-item-descriptionWrap--inline'], // values
control: {
type: 'inline-radio',
labels: ['block', 'inline']
},
description: 'block (default), inline',
defaultValue: 'ActionList-item-blockDescription',
table: {
category: 'CSS'
}
},
fontSize: {
options: [0, 1], // iterator
mapping: ['', 'ActionList-content--fontSmall'], // values
control: {
type: 'inline-radio',
labels: ['default', 'small']
},
description: 'Used to adjust font-size for subgroup items',
table: {
category: 'CSS'
}
}
}
}
export const NavigationListItemTemplate = ListItemTemplate.bind({})
export const Playground = NavigationListItemTemplate.bind({})
Playground.decorators = [
Story => (
<NavigationListTemplate>
<Story />
</NavigationListTemplate>
)
]
Playground.args = {
truncateItem: false,
size: 0,
variant: 0,
descriptionVariant: 0,
fontSize: 0,
ariaCurrent: null,
leadingVisualSize: 0
}

View File

@ -0,0 +1,155 @@
import React from 'react'
import clsx from 'clsx'
import useToggle from '../../helpers/useToggle.jsx'
import {NavigationListTemplate} from './NavigationList.stories'
import {ActionListItemCollapsibleTemplate} from '../../ui-patterns/ActionList/ActionListItemCollapsible.stories.jsx'
export default {
title: 'Components/NavigationList/NavigationListItemCollapsible',
excludeStories: ['NavigationListItemCollapsibleTemplate'],
argTypes: {
size: {
options: [0, 1, 2], // iterator
mapping: ['', 'ActionList-content--sizeMedium', 'ActionList-content--sizeLarge'], // values
control: {
type: 'inline-radio',
labels: ['default', 'medium', 'large']
},
description: 'small (default), medium, large',
defaultValue: '',
table: {
category: 'CSS'
}
},
containsSubItem: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'CSS'
}
},
truncateItem: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'CSS'
}
},
containsActiveSubItem: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'CSS'
}
},
leadingVisual: {
defaultValue: '',
name: 'leadingVisual',
type: 'string',
description: 'Paste [Octicon](https://primer.style/octicons/) in control field',
table: {
category: 'HTML'
}
},
leadingVisualSize: {
options: [0, 1, 2], // iterator
mapping: ['ActionList-content--visual16', 'ActionList-content--visual20', 'ActionList-content--visual24'], // values
control: {
type: 'inline-radio',
labels: ['16px', '20px', '24px']
},
description: 'leading visual width',
defaultValue: 'ActionList-content--visual16',
table: {
category: 'CSS'
}
},
trailingVisual: {
defaultValue: '',
name: 'trailingVisual',
type: 'string',
description: 'Paste [Octicon](https://primer.style/octicons/) in control field',
table: {
category: 'HTML'
}
},
text: {
defaultValue: 'Item label',
type: 'string',
name: 'text',
description: 'string',
table: {
category: 'HTML'
}
},
description: {
defaultValue: '',
type: 'string',
name: 'description',
description: 'string',
table: {
category: 'HTML'
}
},
descriptionVariant: {
options: [0, 1], // iterator
mapping: ['', 'ActionList-item-descriptionWrap--inline'], // values
control: {
type: 'inline-radio',
labels: ['block', 'inline']
},
description: 'block (default), inline',
defaultValue: 'ActionList-item-blockDescription',
table: {
category: 'CSS'
}
},
id: {
defaultValue: '',
type: 'string',
name: 'id',
description: 'Pass in ID of nested <ul> NavigationList',
table: {
category: 'HTML'
}
},
ariaControlsId: {
defaultValue: '',
type: 'string',
name: 'id',
description: 'Pass in ID of nested <ul> NavigationList',
table: {
category: 'HTML'
}
},
collapsePosition: {
options: [0, 1], // iterator
control: {
type: 'inline-radio',
labels: ['leading', 'trailing']
},
description: 'Handle collapse action visual position',
table: {
category: 'HTML'
}
}
}
}
export const NavigationListItemCollapsibleTemplate = ActionListItemCollapsibleTemplate.bind({})
export const Playground = NavigationListItemCollapsibleTemplate.bind({})
Playground.decorators = [
Story => (
<NavigationListTemplate>
<Story />
</NavigationListTemplate>
)
]
Playground.args = {
truncateItem: false,
size: 0,
descriptionVariant: 0,
leadingVisualSize: 0,
collapsePosition: 0
}

View File

@ -0,0 +1,69 @@
import React from 'react'
import {NavigationListTemplate} from './NavigationList.stories'
import {
PatternTrailingCollapsible,
PatternTrailingCollapsibleLeadingVis,
PatternTrailingCollapsibleLeadingTrailingVis,
PatternTrailingCollapsibleTrailingVis,
PatternLeadingCollapsible,
PatternLeadingCollapsibleLeadingVis,
PatternLeadingCollapsibleLeadingTrailingVis,
PatternLeadingCollapsibleTrailingVis,
PatternSizeMedium,
PatternSizeLarge,
PatternConstainsSubItem,
PatternConstainsActiveSubItem,
PatternTruncateText,
PatternWrapText
} from '../../ui-patterns/ActionList/ActionListItemCollapsibleFeatures.stories.jsx'
export default {
title: 'Components/NavigationList/NavigationListItemCollapsible/Features',
decorators: [
Story => (
<NavigationListTemplate>
<Story />
</NavigationListTemplate>
)
]
}
export const TrailingCollapsible = ({}) => <PatternTrailingCollapsible {...PatternTrailingCollapsible.args} />
export const TrailingCollapsibleLeadingVis = ({}) => (
<PatternTrailingCollapsibleLeadingVis {...PatternTrailingCollapsibleLeadingVis.args} />
)
export const TrailingCollapsibleLeadingTrailingVis = ({}) => (
<PatternTrailingCollapsibleLeadingTrailingVis {...PatternTrailingCollapsibleLeadingTrailingVis.args} />
)
export const TrailingCollapsibleTrailingVis = ({}) => (
<PatternTrailingCollapsibleTrailingVis {...PatternTrailingCollapsibleTrailingVis.args} />
)
export const LeadingCollapsible = ({}) => <PatternLeadingCollapsible {...PatternLeadingCollapsible.args} />
export const LeadingCollapsibleLeadingVis = ({}) => (
<PatternLeadingCollapsibleLeadingVis {...PatternLeadingCollapsibleLeadingVis.args} />
)
export const LeadingCollapsibleLeadingTrailingVis = ({}) => (
<PatternLeadingCollapsibleLeadingTrailingVis {...PatternLeadingCollapsibleLeadingTrailingVis.args} />
)
export const LeadingCollapsibleTrailingVis = ({}) => (
<PatternLeadingCollapsibleTrailingVis {...PatternLeadingCollapsibleTrailingVis.args} />
)
export const SizeMedium = ({}) => <PatternSizeMedium {...PatternSizeMedium.args} />
export const SizeLarge = ({}) => <PatternSizeLarge {...PatternSizeLarge.args} />
export const ConstainsSubItem = ({}) => <PatternConstainsSubItem {...PatternConstainsSubItem.args} />
export const ConstainsActiveSubItem = ({}) => <PatternConstainsActiveSubItem {...PatternConstainsActiveSubItem.args} />
export const TruncateText = ({}) => <PatternTruncateText {...PatternTruncateText.args} />
export const WrapText = ({}) => <PatternWrapText {...PatternWrapText.args} />

View File

@ -0,0 +1,98 @@
import React from 'react'
import {NavigationListTemplate} from './NavigationList.stories'
import {
PatternTextOnly,
PatternSizeMedium,
PatternSizeMediumWithDescription,
PatternSizeLarge,
PatternSizeLargeWithDescription,
PatternVisualLeading,
PatternVisualTrailing,
PatternVisualTrailingText,
PatternVisualLeadingAndTrailing,
PatternDescriptionBlock,
PatternDescriptionBlockWithLeadingVisual,
PatternDescriptionBlockWithTrailingVisual,
PatternDescriptionBlockWithLeadingAndTrailingVisual,
PatternDescriptionInline,
PatternDescriptionInlineWithLeadingVisual,
PatternDescriptionInlineWithTrailingVisual,
PatternDescriptionInlineWithLeadingAndTrailingVisual,
PatternNavActiveAnchor,
PatternNavActivePage,
PatternTruncateText,
PatternWrapText
} from '../../ui-patterns/ActionList/ActionListItemFeatures.stories.jsx'
export default {
title: 'Components/NavigationList/NavigationListItem/Features',
decorators: [
Story => (
<NavigationListTemplate>
<Story />
</NavigationListTemplate>
)
]
}
export const TextOnly = ({}) => <PatternTextOnly {...PatternTextOnly.args} />
export const SizeMedium = ({}) => <PatternSizeMedium {...PatternSizeMedium.args} />
export const SizeMediumWithDescription = ({}) => (
<PatternSizeMediumWithDescription {...PatternSizeMediumWithDescription.args} />
)
export const SizeLarge = ({}) => <PatternSizeLarge {...PatternSizeLarge.args} />
export const SizeLargeWithDescription = ({}) => (
<PatternSizeLargeWithDescription {...PatternSizeLargeWithDescription.args} />
)
export const VisualLeading = ({}) => <PatternVisualLeading {...PatternVisualLeading.args} />
export const VisualTrailing = ({}) => <PatternVisualTrailing {...PatternVisualTrailing.args} />
export const VisualTrailingText = ({}) => <PatternVisualTrailingText {...PatternVisualTrailingText.args} />
export const VisualLeadingAndTrailing = ({}) => (
<PatternVisualLeadingAndTrailing {...PatternVisualLeadingAndTrailing.args} />
)
export const DescriptionBlock = ({}) => <PatternDescriptionBlock {...PatternDescriptionBlock.args} />
export const DescriptionBlockWithLeadingVisual = ({}) => (
<PatternDescriptionBlockWithLeadingVisual {...PatternDescriptionBlockWithLeadingVisual.args} />
)
export const DescriptionBlockWithTrailingVisual = ({}) => (
<PatternDescriptionBlockWithTrailingVisual {...PatternDescriptionBlockWithTrailingVisual.args} />
)
export const DescriptionBlockWithLeadingAndTrailingVisual = ({}) => (
<PatternDescriptionBlockWithLeadingAndTrailingVisual {...PatternDescriptionBlockWithLeadingAndTrailingVisual.args} />
)
export const DescriptionInline = ({}) => <PatternDescriptionInline {...PatternDescriptionInline.args} />
export const DescriptionInlineWithLeadingVisual = ({}) => (
<PatternDescriptionInlineWithLeadingVisual {...PatternDescriptionInlineWithLeadingVisual.args} />
)
export const DescriptionInlineWithTrailingVisual = ({}) => (
<PatternDescriptionInlineWithTrailingVisual {...PatternDescriptionInlineWithTrailingVisual.args} />
)
export const DescriptionInlineWithLeadingAndTrailingVisual = ({}) => (
<PatternDescriptionInlineWithLeadingAndTrailingVisual
{...PatternDescriptionInlineWithLeadingAndTrailingVisual.args}
/>
)
export const NavActiveAnchor = ({}) => <PatternNavActiveAnchor {...PatternNavActiveAnchor.args} />
export const NavActivePage = ({}) => <PatternNavActivePage {...PatternNavActivePage.args} />
export const TruncateText = ({}) => <PatternTruncateText {...PatternTruncateText.args} />
export const WrapText = ({}) => <PatternWrapText {...PatternWrapText.args} />

View File

@ -0,0 +1,49 @@
import React from 'react'
import {ActionListTreeViewTemplate} from '../../ui-patterns/ActionList/ActionListTree.stories.jsx'
export default {
title: 'Components/TreeView/TreeView',
excludeStories: ['TreeViewTemplate'],
layout: 'padded',
argTypes: {
showGroupIcon: {
control: {type: 'boolean'},
description: 'show subgroup leading icon',
table: {
category: 'Interactive'
}
},
showSubItemIcon: {
control: {type: 'boolean'},
description: 'show subgroup item leading icon',
table: {
category: 'Interactive'
}
},
text: {
defaultValue: '',
type: 'string',
name: 'title',
description: 'string',
table: {
category: 'HTML'
}
},
truncateItem: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'CSS'
}
}
}
}
export const TreeViewTemplate = ActionListTreeViewTemplate.bind({})
export const Playground = TreeViewTemplate.bind({})
Playground.args = {
showSubItemIcon: true,
showGroupIcon: true,
text: 'item'
}

View File

@ -0,0 +1,7 @@
import React from 'react'
// reference https://gist.github.com/kitze/23d82bb9eb0baabfd03a6a720b1d637f
const ConditionalWrapper = ({condition, wrap, children}) => (condition ? wrap(children) : children)
export default ConditionalWrapper

View File

@ -1,8 +1,10 @@
import {Meta, Story, Canvas} from '@storybook/addon-docs'
<Meta title="Components/ActionList/Accessibility" />
<Meta title="UI Patterns/ActionList/API" />
### Action List
### Action list
`ActionList` CSS is primarily used as the building blocks for compositional components, such as NavigationList. Below is an overview of how the markup may look for specific kinds of implementions and contexts.
An action list is a vertical list of interactive <strong>actions</strong> or <strong>options</strong>.
@ -13,13 +15,13 @@ An action list is a vertical list of interactive <strong>actions</strong> or <st
### Semantic markup
The markup for Action List changes depending on the intended use case.
The markup for Action list changes depending on the intended use case.
In all cases, the basic structure is as follows:
```html
<ul>
<li><span>Content with action</span></li>
<li><button>Content with action</button></li>
<li><a href="/">Content as link</a></li>
<li>
<ul>
@ -29,13 +31,11 @@ In all cases, the basic structure is as follows:
</ul>
```
Pay close attention to `role` attributes throughout the documentation, and find the use case that best suits your needs.
### Dropdown Menu
### Menu
[Menu spec](https://www.w3.org/TR/wai-aria-practices-1.2/examples/menu-button/menu-button-links.html)
The `menu` role should be reserved for dropdown menu scenarios
The `menu` role should be reserved for menu scenarios
| Element | Role |
| :------ | :------------------------------ |
@ -50,9 +50,14 @@ The `menu` role should be reserved for dropdown menu scenarios
Wrap `ActionList` in a `nav` element for site or page navigation, like a sidebar
No roles needed
| Element | Role |
| :------ | :------------ |
| `ul` | `role="list"` |
| `li` | no role |
| `li` | no role |
| `a` | no role |
### Multi select dropdown menu
### Multi select menu
[Menu spec](https://www.w3.org/TR/wai-aria-practices-1.2/examples/menubar/menubar-2/menubar-2.html)
@ -62,7 +67,7 @@ No roles needed
| `li` | `role="menuitemcheckbox"` |
| `li` | `aria-checked="true/false"` |
### Single select dropdown menu
### Single select menu
[Menu spec](https://www.w3.org/TR/wai-aria-practices-1.2/examples/menubar/menubar-2/menubar-2.html)
@ -97,12 +102,10 @@ Note: JS is required for to provide [keyboard handling](https://www.w3.org/TR/wa
### Dividers
| Element | Role |
| :------ | :----------------- |
| `li` | `role="separator"` |
| Element | Role |
| :------ | :-------------------------------------- |
| `li` | `role="separator"` `aria-hidden="true"` |
| Element | Role |
| :------ | :------------------------------------------ |
| `li` | `role="presentation"` |
| `li` | id for nested group `id="group-id"` |
| `li` | if it has id for group `aria-hidden="true"` |
| Element | Role |
| :------ | :--- |
| `h3` | id |

View File

@ -0,0 +1,136 @@
import React from 'react'
import clsx from 'clsx'
import {ListItemTemplate} from './ActionListItem.stories'
export default {
title: 'UI Patterns/ActionList/ActionList',
excludeStories: ['ListTemplate'],
argTypes: {
showDividers: {
control: {type: 'boolean'},
description: 'Show dividers between items',
table: {
category: 'CSS'
}
},
role: {
options: [null, 'menu', 'group', 'listbox', 'menubar', 'none', 'radiogroup', 'list'],
control: {
type: 'inline-radio'
},
description: 'Semantic list role',
table: {
category: 'HTML'
}
},
variant: {
options: [0, 1], // iterator
mapping: [null, 'ActionList--tree'], // values
control: {
type: 'inline-radio',
labels: ['default', 'tree-view']
},
description: 'Specifies variants for different types of lists',
table: {
category: 'CSS'
}
},
ariaLabel: {
name: 'ariaLabel',
type: 'string',
description: 'Descriptive label for menu contents',
table: {
category: 'HTML'
}
},
ariaLabelledBy: {
name: 'ariaLabelledBy',
type: 'string',
description: 'Reference ID of NavigationListDivider',
table: {
category: 'HTML'
}
},
listboxMultiSelect: {
name: 'listboxMultiSelect',
type: 'boolean',
description: 'If ActionList has listbox role + multiselect children',
table: {
category: 'HTML'
}
},
listPadding: {
options: [0, 1], // iterator
mapping: [null, 'ActionList--full'], // values
control: {
type: 'inline-radio',
labels: ['inset', 'full-bleed']
},
description: 'ActionList includes 8px padding by default, full-bleed removes all padding',
table: {
category: 'CSS'
}
},
listType: {
options: [0, 1], // iterator
mapping: ['parent', 'nested'], // values
control: {
type: 'inline-radio',
labels: ['parent', 'nested']
},
description: 'NavigationList can be a parent list with a <nav> or a nested list with just <ul>',
table: {
category: 'CSS'
}
},
children: {
table: {
disable: true
}
}
}
}
export const ListTemplate = ({
showDividers,
children,
role,
ariaLabel,
ariaLabelledBy,
listboxMultiSelect,
listPadding,
variant,
listType
}) => (
<ul
className={clsx(
'ActionList',
showDividers && 'ActionList--divided',
listType === 'nested' && 'ActionList--subGroup',
listPadding && `${listPadding}`,
variant && `${variant}`
)}
role={role}
aria-label={ariaLabel && ariaLabel}
aria-labelledby={ariaLabelledBy && ariaLabelledBy}
aria-multiselectable={listboxMultiSelect ? 'true' : undefined}
>
<>{children}</>
</ul>
)
export const Playground = ListTemplate.bind({})
Playground.args = {
listType: 'parent',
showDividers: false,
listboxMultiSelect: false,
listPadding: 0,
variant: 0,
role: 'list',
children: (
<>
<ListItemTemplate text="Action list item" />
<ListItemTemplate text="Action list item" />
</>
)
}

View File

@ -0,0 +1,86 @@
import React from 'react'
import clsx from 'clsx'
import {ListTemplate} from './ActionList.stories'
export default {
title: 'UI Patterns/ActionList/ActionListDivider',
excludeStories: ['DividerTemplate'],
argTypes: {
variant: {
options: [0, 1], // iterator
mapping: ['', 'ActionList-sectionDivider--filled'], // values
control: {
type: 'inline-radio',
labels: ['subtle', 'filled']
},
table: {
category: 'CSS'
}
},
title: {
defaultValue: '',
type: 'string',
name: 'title',
description: 'string',
table: {
category: 'HTML'
}
},
description: {
defaultValue: '',
type: 'string',
name: 'description',
description: 'string',
table: {
category: 'HTML'
}
},
id: {
defaultValue: '',
type: 'string',
name: 'id',
description: 'Provide label for NavigationList <ul> aria-labelledby',
table: {
category: 'HTML'
}
}
},
decorators: [
Story => (
<ul className="ActionList" role="menu">
<Story />
</ul>
)
]
}
export const DividerTemplate = ({title, description, variant, id}) => (
<>
<li
className={clsx('ActionList-sectionDivider', variant && `${variant}`)}
role={title ? undefined : 'separator'}
aria-hidden={title ? undefined : true}
>
{title && (
<h3 className="ActionList-sectionDivider-title" id={id}>
{title}
</h3>
)}
{description && <span className="ActionList-item-description">{description}</span>}
</li>
</>
)
export const Playground = DividerTemplate.bind({})
Playground.args = {
title: 'Section title',
description: 'Section description',
variant: 'subtle'
}
Playground.decorators = [
Story => (
<ListTemplate>
<Story />
</ListTemplate>
)
]

View File

@ -0,0 +1,36 @@
import React from 'react'
import {ListTemplate} from './ActionList.stories'
import {DividerTemplate} from './ActionListDivider.stories'
export default {
title: 'UI Patterns/ActionList/ActionListDivider/Features',
decorators: [
Story => (
<ListTemplate>
<Story />
</ListTemplate>
)
]
}
export const PatternTitle = DividerTemplate.bind({})
PatternTitle.storyName = 'Title'
PatternTitle.args = {
title: 'List group title'
}
export const PatternFilled = DividerTemplate.bind({})
PatternFilled.storyName = 'Filled'
PatternFilled.args = {
variant: 'ActionList-sectionDivider--filled'
}
export const PatternWithDescription = DividerTemplate.bind({})
PatternWithDescription.storyName = 'With description'
PatternWithDescription.args = {
title: 'List group title',
description: 'Group description'
}
export const PatternSeparator = DividerTemplate.bind({})
PatternSeparator.storyName = 'Separator'

View File

@ -0,0 +1,60 @@
import React from 'react'
import clsx from 'clsx'
import {ListTemplate} from './ActionList.stories'
import {ListItemTemplate} from './ActionListItem.stories'
export default {
title: 'UI Patterns/ActionList/ActionList/Features'
}
export const PatternShowDividers = ListTemplate.bind({})
PatternShowDividers.storyName = 'Show dividers'
PatternShowDividers.args = {
showDividers: true,
children: (
<>
<ListItemTemplate text="Item 1" href="/" listSemantic />
<ListItemTemplate text="Item 2" href="/" listSemantic />
<ListItemTemplate text="Item 3" href="/" listSemantic />
</>
)
}
export const PatternInsetPadding = ListTemplate.bind({})
PatternInsetPadding.storyName = 'Inset padding'
PatternInsetPadding.args = {
listPadding: null,
children: (
<>
<ListItemTemplate text="Item 1" href="/" listSemantic />
<ListItemTemplate text="Item 2" href="/" listSemantic />
<ListItemTemplate text="Item 3" href="/" listSemantic />
</>
)
}
export const PatternFullBleed = ListTemplate.bind({})
PatternFullBleed.storyName = 'Full bleed'
PatternFullBleed.args = {
listPadding: 'ActionList--full',
children: (
<>
<ListItemTemplate text="Item 1" href="/" listSemantic />
<ListItemTemplate text="Item 2" href="/" listSemantic />
<ListItemTemplate text="Item 3" href="/" listSemantic />
</>
)
}
export const PatternNestedGroup = ListTemplate.bind({})
PatternNestedGroup.storyName = 'Nested group'
PatternNestedGroup.args = {
listType: 'nested',
children: (
<>
<ListItemTemplate text="Item 1" href="/" listSemantic />
<ListItemTemplate text="Item 2" href="/" listSemantic />
<ListItemTemplate text="Item 3" href="/" listSemantic />
</>
)
}

View File

@ -0,0 +1,470 @@
import React from 'react'
import clsx from 'clsx'
import useToggle from '../../helpers/useToggle.jsx'
import {ListTemplate} from './ActionList.stories.jsx'
export default {
title: 'UI Patterns/ActionList/ActionListItem',
excludeStories: ['ListItemTemplate'],
argTypes: {
size: {
options: [0, 1, 2], // iterator
mapping: ['', 'ActionList-content--sizeMedium', 'ActionList-content--sizeLarge'], // values
control: {
type: 'inline-radio',
labels: ['default', 'medium', 'large']
},
description: 'small (default), medium, large',
defaultValue: '',
table: {
category: 'CSS'
}
},
variant: {
options: [0, 1], // iterator
mapping: ['', 'ActionList-item--danger'], // values
control: {
type: 'inline-radio',
labels: ['default', 'danger']
},
defaultValue: '',
table: {
category: 'CSS'
}
},
subItem: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'CSS'
}
},
hasSubItem: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'CSS'
}
},
truncateItem: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'CSS'
}
},
leadingVisual: {
defaultValue: '',
name: 'leadingVisual',
type: 'string',
description: 'Paste [Octicon](https://primer.style/octicons/) in control field',
table: {
category: 'HTML'
}
},
leadingVisualSize: {
options: [0, 1, 2], // iterator
mapping: ['ActionList-content--visual16', 'ActionList-content--visual20', 'ActionList-content--visual24'], // values
control: {
type: 'inline-radio',
labels: ['16px', '20px', '24px']
},
description: 'leading visual width',
defaultValue: 'ActionList-content--visual16',
table: {
category: 'CSS'
}
},
trailingVisual: {
defaultValue: '',
name: 'trailingVisual',
type: 'string',
description: 'Paste [Octicon](https://primer.style/octicons/) in control field',
table: {
category: 'HTML'
}
},
text: {
defaultValue: 'Item label',
type: 'string',
name: 'text',
description: 'string',
table: {
category: 'HTML'
}
},
href: {
defaultValue: '',
type: 'string',
name: 'href',
description: 'Item link (href)',
table: {
category: 'HTML'
}
},
ariaCurrent: {
options: ['location', 'page'],
control: {type: 'inline-radio'},
description: 'location for anchor links, page for global page navigation',
table: {
category: 'HTML'
}
},
description: {
defaultValue: '',
type: 'string',
name: 'description',
description: 'string',
table: {
category: 'HTML'
}
},
descriptionVariant: {
options: [0, 1], // iterator
mapping: ['', 'ActionList-item-descriptionWrap--inline'], // values
control: {
type: 'inline-radio',
labels: ['block', 'inline']
},
description: 'block (default), inline',
defaultValue: 'ActionList-item-blockDescription',
table: {
category: 'CSS'
}
},
singleSelect: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'Interactive'
}
},
multiSelect: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'Interactive'
}
},
listSingleSelect: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'Interactive'
}
},
listMultiSelect: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'Interactive'
}
},
treeitem: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'HTML'
}
},
ariaDisabled: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'Interactive'
}
},
ariaLevel: {
name: 'ariaLevel',
type: 'string',
description: 'number - nested subgroup',
table: {
category: 'HTML'
}
},
ariaSetSize: {
name: 'ariaSetSize',
type: 'string',
description:
'Defines the number of treeitem elements in the set of treeitem elements that are in the same branch and at the same level within the hierarchy',
table: {
category: 'HTML'
}
},
ariaPosInset: {
name: 'ariaPosInset',
type: 'string',
description:
'Defines the position of the element within the set of other treeitem elements that are in the same branch and at the same level within the hierarchy.',
table: {
category: 'HTML'
}
},
fontSize: {
options: [0, 1], // iterator
mapping: ['', 'ActionList-content--fontSmall'], // values
control: {
type: 'inline-radio',
labels: ['default', 'small']
},
description: 'Used to adjust font-size for subgroup items',
table: {
category: 'CSS'
}
}
}
}
export const ListItemTemplate = ({
text,
size,
leadingVisual,
leadingVisualSize,
trailingVisual,
description,
descriptionVariant,
variant,
href,
ariaCurrent,
children,
subItem,
hasSubItem,
trailingAction,
leadingAction,
singleSelect,
multiSelect,
listSingleSelect,
listMultiSelect,
listSemantic,
ariaDisabled,
truncateItem,
ariaLevel,
fontSize,
treeitem,
ariaSetSize,
ariaPosInset,
menuItem
}) => {
const [isChecked, itemIsChecked] = useToggle()
const itemStyle = {
'--ActionList-tree-depth': `${ariaLevel}`
}
return (
<li
className={clsx(
'ActionList-item',
ariaCurrent && 'ActionList-item--navActive',
subItem && `ActionList-item--subItem`,
hasSubItem && `ActionList-item--hasSubItem`,
variant && `${variant}`
)}
aria-level={ariaLevel ? `${ariaLevel}` : undefined}
aria-setsize={ariaSetSize ? `${ariaSetSize}` : undefined}
aria-posinset={ariaPosInset ? `${ariaPosInset}` : undefined}
style={ariaLevel && itemStyle}
onClick={itemIsChecked}
role={
singleSelect
? 'menuitemradio'
: multiSelect
? 'menuitemcheckbox'
: listSingleSelect || listMultiSelect
? 'option'
: listSemantic
? 'listitem'
: href
? 'none'
: treeitem
? 'treeitem'
: menuItem
? 'menuitem'
: undefined
}
aria-checked={singleSelect || multiSelect ? (isChecked ? 'true' : 'false') : undefined}
aria-selected={listSingleSelect || listMultiSelect ? (isChecked ? 'true' : 'false') : undefined}
aria-disabled={ariaDisabled ? 'true' : undefined}
>
{href ? (
<>
<a
href={href}
role={
href && !listSemantic && !treeitem ? 'menuitem' : undefined || (href && treeitem) ? 'treeitem' : undefined
}
aria-current={ariaCurrent}
className={clsx(
text && 'ActionList-content',
size && `${size}`,
fontSize && `${fontSize}`,
(leadingVisual || trailingVisual) && description && 'ActionList-content--blockDescription',
leadingVisual && leadingVisualSize && `${leadingVisualSize}`
)}
>
{(leadingAction || singleSelect || multiSelect || listSingleSelect || listMultiSelect) && (
<span className="ActionList-item-action ActionList-item-action--leading">
{singleSelect ||
(listSingleSelect && (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
width="16"
height="16"
className="ActionList-item-singleSelectCheckmark"
>
<path
fill-rule="evenodd"
d="M13.78 4.22a.75.75 0 010 1.06l-7.25 7.25a.75.75 0 01-1.06 0L2.22 9.28a.75.75 0 011.06-1.06L6 10.94l6.72-6.72a.75.75 0 011.06 0z"
></path>
</svg>
))}
{multiSelect ||
(listMultiSelect && (
<svg
width="16"
height="16"
viewBox="0 0 16 16"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
focusable="false"
className="ActionList-item-multiSelectIcon"
>
<rect x="2" y="2" width="12" height="12" rx="4" className="ActionList-item-multiSelectIconRect" />
<path
fill-rule="evenodd"
d="M4.03231 8.69862C3.84775 8.20646 4.49385 7.77554 4.95539 7.77554C5.41693 7.77554 6.80154 9.85246 6.80154 9.85246C6.80154 9.85246 10.2631 4.314 10.4938 4.08323C10.7246 3.85246 11.8785 4.08323 11.4169 5.00631C11.0081 5.82388 7.26308 11.4678 7.26308 11.4678C7.26308 11.4678 6.80154 12.1602 6.34 11.4678C5.87846 10.7755 4.21687 9.19077 4.03231 8.69862Z"
className="ActionList-item-multiSelectCheckmark"
/>
</svg>
))}
{leadingAction}
</span>
)}
{leadingVisual && (
<span
className="ActionList-item-visual ActionList-item-visual--leading"
dangerouslySetInnerHTML={{__html: leadingVisual}}
/>
)}
{description && (
<span className={clsx('ActionList-item-descriptionWrap', `${descriptionVariant}`)}>
<span className={clsx('ActionList-item-label', truncateItem && 'ActionList-item-label--truncate')}>
{text}
</span>
<span className="ActionList-item-description">{description}</span>
</span>
)}
{!description && text && (
<span className={clsx('ActionList-item-label', truncateItem && 'ActionList-item-label--truncate')}>
{text}
</span>
)}
{trailingVisual && (
<span
className="ActionList-item-visual ActionList-item-visual--trailing"
dangerouslySetInnerHTML={{__html: trailingVisual}}
/>
)}
{trailingAction && (
<span className="ActionList-item-action ActionList-item-action--trailing">{trailingAction}</span>
)}
</a>
{children}
</>
) : (
<>
{text && (
<span
className={clsx(
text && 'ActionList-content',
size && `${size}`,
fontSize && `${fontSize}`,
(leadingVisual || trailingVisual) && description && 'ActionList-content--blockDescription',
leadingVisual && leadingVisualSize && `${leadingVisualSize}`
)}
>
{(leadingAction || singleSelect || multiSelect || listSingleSelect || listMultiSelect) && (
<span className="ActionList-item-action ActionList-item-action--leading">
{(singleSelect || listSingleSelect) && (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
width="16"
height="16"
className="ActionList-item-singleSelectCheckmark"
>
<path
fill-rule="evenodd"
d="M13.78 4.22a.75.75 0 010 1.06l-7.25 7.25a.75.75 0 01-1.06 0L2.22 9.28a.75.75 0 011.06-1.06L6 10.94l6.72-6.72a.75.75 0 011.06 0z"
></path>
</svg>
)}
{(multiSelect || listMultiSelect) && (
<svg
width="16"
height="16"
viewBox="0 0 16 16"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
focusable="false"
className="ActionList-item-multiSelectIcon"
>
<rect x="2" y="2" width="12" height="12" rx="4" className="ActionList-item-multiSelectIconRect" />
<path
fill-rule="evenodd"
d="M4.03231 8.69862C3.84775 8.20646 4.49385 7.77554 4.95539 7.77554C5.41693 7.77554 6.80154 9.85246 6.80154 9.85246C6.80154 9.85246 10.2631 4.314 10.4938 4.08323C10.7246 3.85246 11.8785 4.08323 11.4169 5.00631C11.0081 5.82388 7.26308 11.4678 7.26308 11.4678C7.26308 11.4678 6.80154 12.1602 6.34 11.4678C5.87846 10.7755 4.21687 9.19077 4.03231 8.69862Z"
className="ActionList-item-multiSelectCheckmark"
/>
</svg>
)}
{leadingAction}
</span>
)}
{leadingVisual && (
<span
className="ActionList-item-visual ActionList-item-visual--leading"
dangerouslySetInnerHTML={{__html: leadingVisual}}
/>
)}
{description && (
<span className={clsx('ActionList-item-descriptionWrap', `${descriptionVariant}`)}>
<span className={clsx('ActionList-item-label', truncateItem && 'ActionList-item-label--truncate')}>
{text}
</span>
<span className="ActionList-item-description">{description}</span>
</span>
)}
{!description && text && (
<span className={clsx('ActionList-item-label', truncateItem && 'ActionList-item-label--truncate')}>
{text}
</span>
)}
{trailingVisual && (
<span
className="ActionList-item-visual ActionList-item-visual--trailing"
dangerouslySetInnerHTML={{__html: trailingVisual}}
/>
)}
{trailingAction && (
<span className="ActionList-item-action ActionList-item-action--trailing">{trailingAction}</span>
)}
</span>
)}
{children}
</>
)}
</li>
)
}
export const Playground = ListItemTemplate.bind({})
Playground.decorators = [
Story => (
<ListTemplate>
<Story />
</ListTemplate>
)
]
Playground.args = {
truncateItem: false
}

View File

@ -0,0 +1,244 @@
import React from 'react'
import clsx from 'clsx'
import useToggle from '../../helpers/useToggle.jsx'
import {ListTemplate} from './ActionList.stories'
export default {
title: 'UI Patterns/ActionList/ActionListItemCollapsible',
excludeStories: ['ActionListItemCollapsibleTemplate'],
argTypes: {
size: {
options: [0, 1, 2], // iterator
mapping: ['', 'ActionList-content--sizeMedium', 'ActionList-content--sizeLarge'], // values
control: {
type: 'inline-radio',
labels: ['default', 'medium', 'large']
},
description: 'small (default), medium, large',
defaultValue: '',
table: {
category: 'CSS'
}
},
containsSubItem: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'CSS'
}
},
truncateItem: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'CSS'
}
},
containsActiveSubItem: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'CSS'
}
},
leadingVisual: {
defaultValue: '',
name: 'leadingVisual',
type: 'string',
description: 'Paste [Octicon](https://primer.style/octicons/) in control field',
table: {
category: 'HTML'
}
},
leadingVisualSize: {
options: [0, 1, 2], // iterator
mapping: ['ActionList-content--visual16', 'ActionList-content--visual20', 'ActionList-content--visual24'], // values
control: {
type: 'inline-radio',
labels: ['16px', '20px', '24px']
},
description: 'leading visual width',
defaultValue: 'ActionList-content--visual16',
table: {
category: 'CSS'
}
},
trailingVisual: {
defaultValue: '',
name: 'trailingVisual',
type: 'string',
description: 'Paste [Octicon](https://primer.style/octicons/) in control field',
table: {
category: 'HTML'
}
},
text: {
defaultValue: 'Item label',
type: 'string',
name: 'text',
description: 'string',
table: {
category: 'HTML'
}
},
description: {
defaultValue: '',
type: 'string',
name: 'description',
description: 'string',
table: {
category: 'HTML'
}
},
descriptionVariant: {
options: [0, 1], // iterator
mapping: ['', 'ActionList-item-descriptionWrap--inline'], // values
control: {
type: 'inline-radio',
labels: ['block', 'inline']
},
description: 'block (default), inline',
defaultValue: 'ActionList-item-blockDescription',
table: {
category: 'CSS'
}
},
id: {
defaultValue: '',
type: 'string',
name: 'id',
description: 'Pass in ID of nested <ul> NavigationList',
table: {
category: 'HTML'
}
},
ariaControlsId: {
defaultValue: '',
type: 'string',
name: 'id',
description: 'Pass in ID of nested <ul> NavigationList',
table: {
category: 'HTML'
}
},
collapsePosition: {
options: [0, 1], // iterator
control: {
type: 'inline-radio',
labels: ['leading', 'trailing']
},
description: 'Handle collapse action visual position',
table: {
category: 'HTML'
}
}
}
}
export const ActionListItemCollapsibleTemplate = ({
text,
size,
leadingVisual,
leadingVisualSize,
trailingVisual,
description,
descriptionVariant,
children,
containsSubItem,
id,
containsActiveSubItem,
truncateItem,
collapsePosition,
ariaControlsId
}) => {
const [isCollapsed, itemIsCollapsed] = useToggle()
return (
<li className={clsx('ActionList-item', containsSubItem && `ActionList-item--hasSubItem`)}>
<button
onClick={itemIsCollapsed}
aria-expanded={isCollapsed ? 'false' : 'true'}
aria-controls={ariaControlsId}
id={id}
className={clsx(
'ActionList-content',
size && `${size}`,
(leadingVisual || trailingVisual) && description && 'ActionList-content--blockDescription',
leadingVisual && leadingVisualSize && `${leadingVisualSize}`,
containsActiveSubItem && `ActionList-content--hasActiveSubItem`
)}
>
{collapsePosition === 0 && (
<span className="ActionList-item-action ActionList-item-action--leading">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
width="16"
height="16"
className="ActionList-item-collapseIcon"
>
<path
fill-rule="evenodd"
d="M12.78 6.22a.75.75 0 010 1.06l-4.25 4.25a.75.75 0 01-1.06 0L3.22 7.28a.75.75 0 011.06-1.06L8 9.94l3.72-3.72a.75.75 0 011.06 0z"
></path>
</svg>
</span>
)}
{leadingVisual && (
<span
className="ActionList-item-visual ActionList-item-visual--leading"
dangerouslySetInnerHTML={{__html: leadingVisual}}
/>
)}
{description && (
<span className={clsx('ActionList-item-descriptionWrap', `${descriptionVariant}`)}>
<span className={clsx('ActionList-item-label', truncateItem && 'ActionList-item-label--truncate')}>
{text}
</span>
<span className="ActionList-item-description">{description}</span>
</span>
)}
{!description && text && (
<span className={clsx('ActionList-item-label', truncateItem && 'ActionList-item-label--truncate')}>
{text}
</span>
)}
{trailingVisual && (
<span
className="ActionList-item-visual ActionList-item-visual--trailing"
dangerouslySetInnerHTML={{__html: trailingVisual}}
/>
)}
{collapsePosition === 1 && (
<span className="ActionList-item-action ActionList-item-action--trailing">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
width="16"
height="16"
className="ActionList-item-collapseIcon"
>
<path
fill-rule="evenodd"
d="M12.78 6.22a.75.75 0 010 1.06l-4.25 4.25a.75.75 0 01-1.06 0L3.22 7.28a.75.75 0 011.06-1.06L8 9.94l3.72-3.72a.75.75 0 011.06 0z"
></path>
</svg>
</span>
)}
</button>
{children}
</li>
)
}
export const Playground = ActionListItemCollapsibleTemplate.bind({})
Playground.decorators = [
Story => (
<ListTemplate>
<Story />
</ListTemplate>
)
]
Playground.args = {
id: null,
truncateItem: false
}

View File

@ -0,0 +1,158 @@
import React from 'react'
import clsx from 'clsx'
import {ActionListItemCollapsibleTemplate} from './ActionListItemCollapsible.stories'
import {ListTemplate} from './ActionList.stories'
export default {
title: 'UI Patterns/ActionList/ActionListItemCollapsible/Features',
decorators: [
Story => (
<ListTemplate>
<Story />
</ListTemplate>
)
]
}
const leadingVisual = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M10.5 5a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0zm.061 3.073a4 4 0 10-5.123 0 6.004 6.004 0 00-3.431 5.142.75.75 0 001.498.07 4.5 4.5 0 018.99 0 .75.75 0 101.498-.07 6.005 6.005 0 00-3.432-5.142z"
></path>
</svg>`
const trailingVisual = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zm.75 4.75a.75.75 0 00-1.5 0v2.5h-2.5a.75.75 0 000 1.5h2.5v2.5a.75.75 0 001.5 0v-2.5h2.5a.75.75 0 000-1.5h-2.5v-2.5z"
></path>
</svg>`
export const PatternTrailingCollapsible = ActionListItemCollapsibleTemplate.bind({})
PatternTrailingCollapsible.storyName = '[Trailing] Text only'
PatternTrailingCollapsible.args = {
...ActionListItemCollapsibleTemplate.args,
text: 'Collapsible',
collapsePosition: 1
}
export const PatternTrailingCollapsibleLeadingVis = ActionListItemCollapsibleTemplate.bind({})
PatternTrailingCollapsibleLeadingVis.storyName = '[Trailing] Leading visual'
PatternTrailingCollapsibleLeadingVis.args = {
...ActionListItemCollapsibleTemplate.args,
text: 'Collapsible',
collapsePosition: 1,
leadingVisual: leadingVisual
}
export const PatternTrailingCollapsibleLeadingTrailingVis = ActionListItemCollapsibleTemplate.bind({})
PatternTrailingCollapsibleLeadingTrailingVis.storyName = '[Trailing] Leading + trailing visual'
PatternTrailingCollapsibleLeadingTrailingVis.args = {
...ActionListItemCollapsibleTemplate.args,
text: 'Collapsible',
collapsePosition: 1,
leadingVisual: leadingVisual,
trailingVisual: trailingVisual
}
export const PatternTrailingCollapsibleTrailingVis = ActionListItemCollapsibleTemplate.bind({})
PatternTrailingCollapsibleTrailingVis.storyName = '[Trailing] Trailing visual'
PatternTrailingCollapsibleTrailingVis.args = {
...ActionListItemCollapsibleTemplate.args,
text: 'Collapsible',
collapsePosition: 1,
trailingVisual: trailingVisual
}
export const PatternLeadingCollapsible = ActionListItemCollapsibleTemplate.bind({})
PatternLeadingCollapsible.storyName = '[Leading] Text only'
PatternLeadingCollapsible.args = {
...ActionListItemCollapsibleTemplate.args,
text: 'Collapsible',
collapsePosition: 0
}
export const PatternLeadingCollapsibleLeadingVis = ActionListItemCollapsibleTemplate.bind({})
PatternLeadingCollapsibleLeadingVis.storyName = '[Leading] Leading visual'
PatternLeadingCollapsibleLeadingVis.args = {
...ActionListItemCollapsibleTemplate.args,
text: 'Collapsible',
collapsePosition: 0,
leadingVisual: leadingVisual
}
export const PatternLeadingCollapsibleLeadingTrailingVis = ActionListItemCollapsibleTemplate.bind({})
PatternLeadingCollapsibleLeadingTrailingVis.storyName = '[Leading] Leading + trailing visual'
PatternLeadingCollapsibleLeadingTrailingVis.args = {
...ActionListItemCollapsibleTemplate.args,
text: 'Collapsible',
collapsePosition: 0,
leadingVisual: leadingVisual,
trailingVisual: trailingVisual
}
export const PatternLeadingCollapsibleTrailingVis = ActionListItemCollapsibleTemplate.bind({})
PatternLeadingCollapsibleTrailingVis.storyName = '[Leading] Trailing visual'
PatternLeadingCollapsibleTrailingVis.args = {
...ActionListItemCollapsibleTemplate.args,
text: 'Collapsible',
collapsePosition: 0,
trailingVisual: trailingVisual
}
export const PatternSizeMedium = ActionListItemCollapsibleTemplate.bind({})
PatternSizeMedium.storyName = '[Size] Medium'
PatternSizeMedium.args = {
...ActionListItemCollapsibleTemplate.args,
text: 'Medium item',
size: 'ActionList-content--sizeMedium',
collapsePosition: 1
}
export const PatternSizeLarge = ActionListItemCollapsibleTemplate.bind({})
PatternSizeLarge.storyName = '[Size] Large'
PatternSizeLarge.args = {
...ActionListItemCollapsibleTemplate.args,
text: 'Large item',
size: 'ActionList-content--sizeLarge',
collapsePosition: 1
}
export const PatternConstainsSubItem = ActionListItemCollapsibleTemplate.bind({})
PatternConstainsSubItem.storyName = 'Has sub item (render css class)'
PatternConstainsSubItem.args = {
...ActionListItemCollapsibleTemplate.args,
text: 'I am collapsible',
collapsePosition: 1,
containsSubItem: true
}
export const PatternConstainsActiveSubItem = ActionListItemCollapsibleTemplate.bind({})
PatternConstainsActiveSubItem.storyName = 'Has active sub item'
PatternConstainsActiveSubItem.args = {
...ActionListItemCollapsibleTemplate.args,
text: 'I have an active child',
collapsePosition: 1,
containsActiveSubItem: true
}
export const PatternTruncateText = ActionListItemCollapsibleTemplate.bind({})
PatternTruncateText.storyName = 'Truncate text'
PatternTruncateText.args = {
...ActionListItemCollapsibleTemplate.args,
truncateItem: true,
text: 'This is a very long string of text that will wrap to another line on smaller screens',
trailingVisual: trailingVisual,
leadingVisual: leadingVisual,
collapsePosition: 1
}
export const PatternWrapText = ActionListItemCollapsibleTemplate.bind({})
PatternWrapText.storyName = 'Wrap text'
PatternWrapText.args = {
...ActionListItemCollapsibleTemplate.args,
text: 'This is a very long string of text that will wrap to another line on smaller screens',
trailingVisual: trailingVisual,
leadingVisual: leadingVisual,
collapsePosition: 1
}

View File

@ -0,0 +1,356 @@
import React from 'react'
import {ListItemTemplate} from './ActionListItem.stories'
import {ListTemplate} from './ActionList.stories'
export default {
title: 'UI Patterns/ActionList/ActionListItem/Features',
decorators: [
Story => (
<ListTemplate>
<Story />
</ListTemplate>
)
]
}
const leadingVisual = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M10.5 5a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0zm.061 3.073a4 4 0 10-5.123 0 6.004 6.004 0 00-3.431 5.142.75.75 0 001.498.07 4.5 4.5 0 018.99 0 .75.75 0 101.498-.07 6.005 6.005 0 00-3.432-5.142z"
></path>
</svg>`
const trailingVisual = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zm.75 4.75a.75.75 0 00-1.5 0v2.5h-2.5a.75.75 0 000 1.5h2.5v2.5a.75.75 0 001.5 0v-2.5h2.5a.75.75 0 000-1.5h-2.5v-2.5z"
></path>
</svg>`
export const PatternTextOnly = ListItemTemplate.bind({})
PatternTextOnly.storyName = 'Text only'
PatternTextOnly.args = {
text: 'Basic item label'
}
export const PatternSizeMedium = ListItemTemplate.bind({})
PatternSizeMedium.storyName = '[Size] Medium'
PatternSizeMedium.args = {
...ListItemTemplate.args,
text: 'Medium item',
size: 'ActionList-content--sizeMedium'
}
export const PatternSizeMediumWithDescription = ListItemTemplate.bind({})
PatternSizeMediumWithDescription.storyName = '[Size] Medium with description'
PatternSizeMediumWithDescription.args = {
...ListItemTemplate.args,
text: 'Medium item',
description: 'Some descriptive text',
size: 'ActionList-content--sizeMedium'
}
export const PatternSizeLarge = ListItemTemplate.bind({})
PatternSizeLarge.storyName = '[Size] Large'
PatternSizeLarge.args = {
...ListItemTemplate.args,
text: 'Large item',
size: 'ActionList-content--sizeLarge'
}
export const PatternSizeLargeWithDescription = ListItemTemplate.bind({})
PatternSizeLargeWithDescription.storyName = '[Size] Large with description'
PatternSizeLargeWithDescription.args = {
...ListItemTemplate.args,
text: 'Large item',
description: 'Some descriptive text',
size: 'ActionList-content--sizeLarge'
}
export const PatternVisualLeading = ListItemTemplate.bind({})
PatternVisualLeading.storyName = '[Visuals] Leading'
PatternVisualLeading.args = {
...ListItemTemplate.args,
text: 'Item with leading visual',
leadingVisual: leadingVisual
}
export const PatternVisualTrailing = ListItemTemplate.bind({})
PatternVisualTrailing.storyName = '[Visuals] Trailing'
PatternVisualTrailing.args = {
...ListItemTemplate.args,
text: 'Item with trailing visual',
trailingVisual: trailingVisual
}
export const PatternVisualTrailingText = ListItemTemplate.bind({})
PatternVisualTrailingText.storyName = '[Visuals] Trailing text'
PatternVisualTrailingText.args = {
...ListItemTemplate.args,
text: 'Item with trailing text',
trailingVisual: `⌘N`
}
export const PatternVisualLeadingAndTrailing = ListItemTemplate.bind({})
PatternVisualLeadingAndTrailing.storyName = '[Visuals] Leading & trailing'
PatternVisualLeadingAndTrailing.args = {
...ListItemTemplate.args,
text: 'Item with trailing visual',
trailingVisual: trailingVisual,
leadingVisual: leadingVisual
}
export const PatternDescriptionBlock = ListItemTemplate.bind({})
PatternDescriptionBlock.storyName = '[Description] block'
PatternDescriptionBlock.args = {
...ListItemTemplate.args,
text: 'Item label',
description: 'This is a description',
descriptionVariant: 'ActionList-item-blockDescription'
}
export const PatternDescriptionBlockWithLeadingVisual = ListItemTemplate.bind({})
PatternDescriptionBlockWithLeadingVisual.storyName = '[Description] block + leading visual'
PatternDescriptionBlockWithLeadingVisual.args = {
...ListItemTemplate.args,
text: 'Item label',
description: 'This is a description',
descriptionVariant: 'ActionList-item-blockDescription',
leadingVisual: leadingVisual
}
export const PatternDescriptionBlockWithTrailingVisual = ListItemTemplate.bind({})
PatternDescriptionBlockWithTrailingVisual.storyName = '[Description] block + trailing visual'
PatternDescriptionBlockWithTrailingVisual.args = {
...ListItemTemplate.args,
text: 'Item label',
description: 'This is a description',
descriptionVariant: 'ActionList-item-blockDescription',
trailingVisual: trailingVisual
}
export const PatternDescriptionBlockWithLeadingAndTrailingVisual = ListItemTemplate.bind({})
PatternDescriptionBlockWithLeadingAndTrailingVisual.storyName = '[Description] block + leading/trailing visual'
PatternDescriptionBlockWithLeadingAndTrailingVisual.args = {
...ListItemTemplate.args,
text: 'Item label',
description: 'This is a description',
descriptionVariant: 'ActionList-item-blockDescription',
trailingVisual: trailingVisual,
leadingVisual: leadingVisual
}
export const PatternDescriptionInline = ListItemTemplate.bind({})
PatternDescriptionInline.storyName = '[Description] inline'
PatternDescriptionInline.args = {
...ListItemTemplate.args,
text: 'Item label',
description: 'This is a description',
descriptionVariant: 'ActionList-item-descriptionWrap--inline'
}
export const PatternDescriptionInlineWithLeadingVisual = ListItemTemplate.bind({})
PatternDescriptionInlineWithLeadingVisual.storyName = '[Description] inline + leading visual'
PatternDescriptionInlineWithLeadingVisual.args = {
...ListItemTemplate.args,
text: 'Item label',
description: 'This is a description',
descriptionVariant: 'ActionList-item-descriptionWrap--inline',
leadingVisual: leadingVisual
}
export const PatternDescriptionInlineWithTrailingVisual = ListItemTemplate.bind({})
PatternDescriptionInlineWithTrailingVisual.storyName = '[Description] inline + trailing visual'
PatternDescriptionInlineWithTrailingVisual.args = {
...ListItemTemplate.args,
text: 'Item label',
description: 'This is a description',
descriptionVariant: 'ActionList-item-descriptionWrap--inline',
trailingVisual: trailingVisual
}
export const PatternDescriptionInlineWithLeadingAndTrailingVisual = ListItemTemplate.bind({})
PatternDescriptionInlineWithLeadingAndTrailingVisual.storyName = '[Description] inline + leading/trailing visual'
PatternDescriptionInlineWithLeadingAndTrailingVisual.args = {
...ListItemTemplate.args,
text: 'Item label',
description: 'This is a description',
descriptionVariant: 'ActionList-item-descriptionWrap--inline',
trailingVisual: trailingVisual,
leadingVisual: leadingVisual
}
export const PatternNavActiveAnchor = ListItemTemplate.bind({})
PatternNavActiveAnchor.storyName = '[Nav] Active anchor'
PatternNavActiveAnchor.args = {
...ListItemTemplate.args,
text: 'Im an anchor link',
href: '#someid',
ariaCurrent: 'location',
activeNavItem: true
}
export const PatternNavActivePage = ListItemTemplate.bind({})
PatternNavActivePage.storyName = '[Nav] Active page'
PatternNavActivePage.args = {
...ListItemTemplate.args,
text: 'Im a page level link',
href: '/',
ariaCurrent: 'page',
activeNavItem: true
}
export const PatternVariantDangerItem = ListItemTemplate.bind({})
PatternVariantDangerItem.storyName = '[Variant] Danger'
PatternVariantDangerItem.args = {
...ListItemTemplate.args,
text: 'Danger danger',
variant: 'ActionList-item--danger'
}
export const PatternVariantDangerItemLeading = ListItemTemplate.bind({})
PatternVariantDangerItemLeading.storyName = '[Variant] Danger + leading visual'
PatternVariantDangerItemLeading.args = {
...ListItemTemplate.args,
text: 'Danger danger',
variant: 'ActionList-item--danger',
leadingVisual: leadingVisual
}
export const PatternVariantDangerItemTrailing = ListItemTemplate.bind({})
PatternVariantDangerItemTrailing.storyName = '[Variant] Danger + trailing visual'
PatternVariantDangerItemTrailing.args = {
...ListItemTemplate.args,
text: 'Danger danger',
variant: 'ActionList-item--danger',
trailingVisual: trailingVisual
}
export const PatternVariantDangerItemLeadingTrailing = ListItemTemplate.bind({})
PatternVariantDangerItemLeadingTrailing.storyName = '[Variant] Danger + leading/trailing visual'
PatternVariantDangerItemLeadingTrailing.args = {
...ListItemTemplate.args,
text: 'Danger danger',
variant: 'ActionList-item--danger',
trailingVisual: trailingVisual,
leadingVisual: leadingVisual
}
export const PatternVariantDisabledItem = ListItemTemplate.bind({})
PatternVariantDisabledItem.storyName = '[Variant] Disabled'
PatternVariantDisabledItem.args = {
...ListItemTemplate.args,
text: 'Disabled',
ariaDisabled: true
}
export const PatternVariantDisabledItemLeading = ListItemTemplate.bind({})
PatternVariantDisabledItemLeading.storyName = '[Variant] Disabled + leading visual'
PatternVariantDisabledItemLeading.args = {
...ListItemTemplate.args,
text: 'Disabled',
ariaDisabled: true,
leadingVisual: leadingVisual
}
export const PatternVariantDisabledItemTrailing = ListItemTemplate.bind({})
PatternVariantDisabledItemTrailing.storyName = '[Variant] Disabled + trailing visual'
PatternVariantDisabledItemTrailing.args = {
...ListItemTemplate.args,
text: 'Disabled',
ariaDisabled: true,
trailingVisual: trailingVisual
}
export const PatternVariantDisabledItemLeadingTrailing = ListItemTemplate.bind({})
PatternVariantDisabledItemLeadingTrailing.storyName = '[Variant] Disabled + leading/trailing visual'
PatternVariantDisabledItemLeadingTrailing.args = {
...ListItemTemplate.args,
text: 'Disabled',
ariaDisabled: true,
trailingVisual: trailingVisual,
leadingVisual: leadingVisual
}
export const PatternSingleSelectItem = ListItemTemplate.bind({})
PatternSingleSelectItem.storyName = '[Actions] Single select'
PatternSingleSelectItem.args = {
text: 'Single select item',
singleSelect: true
}
export const PatternSingleSelectItemWithLeadingVisual = ListItemTemplate.bind({})
PatternSingleSelectItemWithLeadingVisual.storyName = '[Actions] Single select + leading visual'
PatternSingleSelectItemWithLeadingVisual.args = {
text: 'Single select item',
singleSelect: true,
leadingVisual: leadingVisual
}
export const PatternSingleSelectItemWithTrailingVisual = ListItemTemplate.bind({})
PatternSingleSelectItemWithTrailingVisual.storyName = '[Actions] Single select + trailing visual'
PatternSingleSelectItemWithTrailingVisual.args = {
text: 'Single select item',
singleSelect: true,
trailingVisual: trailingVisual
}
export const PatternSingleSelectItemWithLeadingAndTrailingVisual = ListItemTemplate.bind({})
PatternSingleSelectItemWithLeadingAndTrailingVisual.storyName = '[Actions] Single select + leading/trailing visual'
PatternSingleSelectItemWithLeadingAndTrailingVisual.args = {
text: 'Single select item',
singleSelect: true,
trailingVisual: trailingVisual,
leadingVisual: leadingVisual
}
export const PatternMultiSelectItem = ListItemTemplate.bind({})
PatternMultiSelectItem.storyName = '[Actions] Multi select'
PatternMultiSelectItem.args = {
text: 'Multi select item',
multiSelect: true
}
export const PatternMultiSelectItemWithLeadingVisual = ListItemTemplate.bind({})
PatternMultiSelectItemWithLeadingVisual.storyName = '[Actions] Multi select + leading visual'
PatternMultiSelectItemWithLeadingVisual.args = {
text: 'Multi select item',
multiSelect: true,
leadingVisual: leadingVisual
}
export const PatternMultiSelectItemWithTrailingVisual = ListItemTemplate.bind({})
PatternMultiSelectItemWithTrailingVisual.storyName = '[Actions] Multi select + trailing visual'
PatternMultiSelectItemWithTrailingVisual.args = {
text: 'Multi select item',
multiSelect: true,
trailingVisual: trailingVisual
}
export const PatternMultiSelectItemWithLeadingAndTrailingVisual = ListItemTemplate.bind({})
PatternMultiSelectItemWithLeadingAndTrailingVisual.storyName = '[Actions] Multi select + leading/trailing visual'
PatternMultiSelectItemWithLeadingAndTrailingVisual.args = {
text: 'Multi select item',
multiSelect: true,
trailingVisual: trailingVisual,
leadingVisual: leadingVisual
}
export const PatternTruncateText = ListItemTemplate.bind({})
PatternTruncateText.storyName = 'Truncate text'
PatternTruncateText.args = {
...ListItemTemplate.args,
truncateItem: true,
text: 'This is a very long string of text that will wrap to another line on smaller screens',
trailingVisual: trailingVisual,
leadingVisual: leadingVisual
}
export const PatternWrapText = ListItemTemplate.bind({})
PatternWrapText.storyName = 'Wrap text'
PatternWrapText.args = {
...ListItemTemplate.args,
text: 'This is a very long string of text that will wrap to another line on smaller screens',
trailingVisual: trailingVisual,
leadingVisual: leadingVisual
}

View File

@ -0,0 +1,162 @@
import React from 'react'
import {ListTemplate} from './ActionList.stories'
import {ListItemTemplate} from './ActionListItem.stories'
import {TreeViewListItemCollapsibleTemplate} from './TreeViewListItemCollapsible.stories'
export default {
title: 'UI Patterns/ActionList/ActionTreeView',
excludeStories: ['ActionListTreeViewTemplate'],
layout: 'padded',
argTypes: {
showGroupIcon: {
control: {type: 'boolean'},
description: 'show subgroup leading icon',
table: {
category: 'Interactive'
}
},
showSubItemIcon: {
control: {type: 'boolean'},
description: 'show subgroup item leading icon',
table: {
category: 'Interactive'
}
},
text: {
defaultValue: '',
type: 'string',
name: 'title',
description: 'string',
table: {
category: 'HTML'
}
},
truncateItem: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'CSS'
}
}
}
}
const folder = `<svg aria-hidden="true" role="img" class="octicon octicon-file-directory-fill" viewBox="0 0 24 24" width="16" height="16" fill="currentColor" style="display:inline-block;user-select:none;vertical-align:text-bottom;overflow:visible"><path fill-rule="evenodd" d="M2 4.75C2 3.784 2.784 3 3.75 3h4.971c.58 0 1.12.286 1.447.765l1.404 2.063a.25.25 0 00.207.11h8.471c.966 0 1.75.783 1.75 1.75V19.25A1.75 1.75 0 0120.25 21H3.75A1.75 1.75 0 012 19.25V4.75z"></path></svg>`
const file = `<svg aria-hidden="true" role="img" class="octicon octicon-file" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" style="display:inline-block;user-select:none;vertical-align:text-bottom;overflow:visible"><path fill-rule="evenodd" d="M3.75 1.5a.25.25 0 00-.25.25v11.5c0 .138.112.25.25.25h8.5a.25.25 0 00.25-.25V6H9.75A1.75 1.75 0 018 4.25V1.5H3.75zm5.75.56v2.19c0 .138.112.25.25.25h2.19L9.5 2.06zM2 1.75C2 .784 2.784 0 3.75 0h5.086c.464 0 .909.184 1.237.513l3.414 3.414c.329.328.513.773.513 1.237v8.086A1.75 1.75 0 0112.25 15h-8.5A1.75 1.75 0 012 13.25V1.75z"></path></svg>`
const trailingVisual = `<svg aria-hidden="true" role="img" class="color-fg-attention" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" style="display:inline-block;user-select:none;vertical-align:text-bottom;overflow:visible"><path fill-rule="evenodd" d="M2.75 2.5h10.5a.25.25 0 01.25.25v10.5a.25.25 0 01-.25.25H2.75a.25.25 0 01-.25-.25V2.75a.25.25 0 01.25-.25zM13.25 1H2.75A1.75 1.75 0 001 2.75v10.5c0 .966.784 1.75 1.75 1.75h10.5A1.75 1.75 0 0015 13.25V2.75A1.75 1.75 0 0013.25 1zM8 10a2 2 0 100-4 2 2 0 000 4z"></path></svg>`
export const ActionListTreeViewTemplate = ({showGroupIcon, showSubItemIcon, text, truncateItem}) => (
<ListTemplate ariaLabel="Some description" role="tree" variant="ActionList--tree">
<>
<TreeViewListItemCollapsibleTemplate
text="level 1"
leadingVisual={showGroupIcon && folder}
truncateItem={truncateItem}
ariaLevel="1"
ariaSetSize="2"
ariaPosInset="2"
collapsePosition={0}
containsSubItem
>
<ListTemplate listType="nested">
<ListItemTemplate
truncateItem={truncateItem}
ariaLevel="2"
ariaSetSize="2"
ariaPosInset="1"
treeitem
subItem
text={text}
href="/"
ariaCurrent="page"
leadingVisual={showSubItemIcon && file}
trailingVisual={trailingVisual}
/>
<TreeViewListItemCollapsibleTemplate
text="level 2"
leadingVisual={showGroupIcon && folder}
truncateItem={truncateItem}
ariaLevel="2"
ariaSetSize="2"
ariaPosInset="2"
collapsePosition={0}
containsSubItem
>
<ListTemplate listType="nested">
<TreeViewListItemCollapsibleTemplate
text="level 3"
ariaLevel="3"
ariaSetSize="2"
ariaPosInset="1"
leadingVisual={showGroupIcon && folder}
truncateItem={truncateItem}
collapsePosition={0}
containsSubItem
>
<ListTemplate listType="nested">
<ListItemTemplate
truncateItem={truncateItem}
ariaLevel="4"
ariaSetSize="4"
ariaPosInset="1"
treeitem
subItem
text={text}
href=""
leadingVisual={showSubItemIcon && file}
trailingVisual={trailingVisual}
/>
<ListItemTemplate
truncateItem={truncateItem}
ariaLevel="4"
ariaSetSize="4"
ariaPosInset="2"
treeitem
subItem
text={text}
href=""
leadingVisual={showSubItemIcon && file}
trailingVisual={trailingVisual}
/>
<ListItemTemplate
truncateItem={truncateItem}
ariaLevel="4"
ariaSetSize="4"
ariaPosInset="3"
treeitem
subItem
text={text}
href=""
leadingVisual={showSubItemIcon && file}
trailingVisual={trailingVisual}
/>
</ListTemplate>
</TreeViewListItemCollapsibleTemplate>
<ListItemTemplate
truncateItem={truncateItem}
ariaLevel="3"
ariaSetSize="2"
ariaPosInset="2"
treeitem
subItem
text={text}
href=""
leadingVisual={showSubItemIcon && file}
trailingVisual={trailingVisual}
/>
</ListTemplate>
</TreeViewListItemCollapsibleTemplate>
</ListTemplate>
</TreeViewListItemCollapsibleTemplate>
</>
</ListTemplate>
)
export const Playground = ActionListTreeViewTemplate.bind({})
Playground.args = {
showSubItemIcon: true,
showGroupIcon: true,
text: 'item'
}

View File

@ -1,12 +1,8 @@
import React from 'react'
import clsx from 'clsx'
import {ListTemplate} from './ActionList.stories'
import {ListItemTemplate} from './ActionListItem.stories'
import {DividerTemplate} from './ActionListDivider.stories'
import {ActionListTreeViewTemplate} from './ActionListTree.stories'
export default {
title: 'Components/ActionList/ActionTreeView/Features'
title: 'UI Patterns/ActionList/ActionTreeView/Features'
}
export const TruncateText = ActionListTreeViewTemplate.bind({})

View File

@ -0,0 +1,280 @@
import React from 'react'
import clsx from 'clsx'
import useToggle from '../../helpers/useToggle.jsx'
import {ListTemplate} from './ActionList.stories.jsx'
export default {
title: 'UI Patterns/ActionList/ActionTreeView/TreeViewListItemCollapsible',
excludeStories: ['TreeViewListItemCollapsibleTemplate'],
argTypes: {
size: {
options: [0, 1, 2], // iterator
mapping: ['', 'ActionList-content--sizeMedium', 'ActionList-content--sizeLarge'], // values
control: {
type: 'inline-radio',
labels: ['default', 'medium', 'large']
},
description: 'small (default), medium, large',
defaultValue: '',
table: {
category: 'CSS'
}
},
containsSubItem: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'CSS'
}
},
truncateItem: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'CSS'
}
},
leadingVisual: {
defaultValue: '',
name: 'leadingVisual',
type: 'string',
description: 'Paste [Octicon](https://primer.style/octicons/) in control field',
table: {
category: 'HTML'
}
},
leadingVisualSize: {
options: [0, 1, 2], // iterator
mapping: ['ActionList-content--visual16', 'ActionList-content--visual20', 'ActionList-content--visual24'], // values
control: {
type: 'inline-radio',
labels: ['16px', '20px', '24px']
},
description: 'leading visual width',
defaultValue: 'ActionList-content--visual16',
table: {
category: 'CSS'
}
},
trailingVisual: {
defaultValue: '',
name: 'trailingVisual',
type: 'string',
description: 'Paste [Octicon](https://primer.style/octicons/) in control field',
table: {
category: 'HTML'
}
},
text: {
defaultValue: 'Item label',
type: 'string',
name: 'text',
description: 'string',
table: {
category: 'HTML'
}
},
description: {
defaultValue: '',
type: 'string',
name: 'description',
description: 'string',
table: {
category: 'HTML'
}
},
descriptionVariant: {
options: [0, 1], // iterator
mapping: ['', 'ActionList-item-descriptionWrap--inline'], // values
control: {
type: 'inline-radio',
labels: ['block', 'inline']
},
description: 'block (default), inline',
defaultValue: 'ActionList-item-blockDescription',
table: {
category: 'CSS'
}
},
id: {
defaultValue: '',
type: 'string',
name: 'id',
description: 'Pass in ID of nested <ul> NavigationList',
table: {
category: 'HTML'
}
},
ariaControlsId: {
defaultValue: '',
type: 'string',
name: 'id',
description: 'Pass in ID of nested <ul> NavigationList',
table: {
category: 'HTML'
}
},
collapsePosition: {
options: [0, 1], // iterator
control: {
type: 'inline-radio',
labels: ['leading', 'trailing']
},
description: 'Handle collapse action visual position',
table: {
category: 'HTML'
}
},
ariaDisabled: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'Interactive'
}
},
ariaLevel: {
name: 'ariaLevel',
type: 'string',
description: 'number - nested subgroup',
table: {
category: 'HTML'
}
},
ariaSetSize: {
name: 'ariaSetSize',
type: 'string',
description:
'Defines the number of treeitem elements in the set of treeitem elements that are in the same branch and at the same level within the hierarchy',
table: {
category: 'HTML'
}
},
ariaPosInset: {
name: 'ariaPosInset',
type: 'string',
description:
'Defines the position of the element within the set of other treeitem elements that are in the same branch and at the same level within the hierarchy.',
table: {
category: 'HTML'
}
}
}
}
export const TreeViewListItemCollapsibleTemplate = ({
text,
size,
leadingVisual,
leadingVisualSize,
trailingVisual,
description,
descriptionVariant,
children,
containsSubItem,
id,
truncateItem,
collapsePosition,
ariaSetSize,
ariaPosInset,
ariaLevel,
ariaDisabled
}) => {
const [isCollapsed, itemIsCollapsed] = useToggle()
const itemStyle = {
'--ActionList-tree-depth': `${ariaLevel}`
}
return (
<li
className={clsx('ActionList-item', containsSubItem && `ActionList-item--hasSubItem`)}
onClick={itemIsCollapsed}
id={id}
aria-disabled={ariaDisabled ? 'true' : undefined}
aria-expanded={isCollapsed ? 'false' : 'true'}
aria-level={ariaLevel ? `${ariaLevel}` : undefined}
aria-setsize={ariaSetSize ? `${ariaSetSize}` : undefined}
aria-posinset={ariaPosInset ? `${ariaPosInset}` : undefined}
style={ariaLevel && itemStyle}
>
<span
className={clsx(
'ActionList-content',
size && `${size}`,
(leadingVisual || trailingVisual) && description && 'ActionList-content--blockDescription',
leadingVisual && leadingVisualSize && `${leadingVisualSize}`
)}
>
{collapsePosition === 0 && (
<span className="ActionList-item-action ActionList-item-action--leading">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
width="16"
height="16"
className="ActionList-item-collapseIcon"
>
<path
fill-rule="evenodd"
d="M12.78 6.22a.75.75 0 010 1.06l-4.25 4.25a.75.75 0 01-1.06 0L3.22 7.28a.75.75 0 011.06-1.06L8 9.94l3.72-3.72a.75.75 0 011.06 0z"
></path>
</svg>
</span>
)}
{leadingVisual && (
<span
className="ActionList-item-visual ActionList-item-visual--leading"
dangerouslySetInnerHTML={{__html: leadingVisual}}
/>
)}
{description && (
<span className={clsx('ActionList-item-descriptionWrap', `${descriptionVariant}`)}>
<span className={clsx('ActionList-item-label', truncateItem && 'ActionList-item-label--truncate')}>
{text}
</span>
<span className="ActionList-item-description">{description}</span>
</span>
)}
{!description && text && (
<span className={clsx('ActionList-item-label', truncateItem && 'ActionList-item-label--truncate')}>
{text}
</span>
)}
{trailingVisual && (
<span
className="ActionList-item-visual ActionList-item-visual--trailing"
dangerouslySetInnerHTML={{__html: trailingVisual}}
/>
)}
{collapsePosition === 1 && (
<span className="ActionList-item-action ActionList-item-action--trailing">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
width="16"
height="16"
className="ActionList-item-collapseIcon"
>
<path
fill-rule="evenodd"
d="M12.78 6.22a.75.75 0 010 1.06l-4.25 4.25a.75.75 0 01-1.06 0L3.22 7.28a.75.75 0 011.06-1.06L8 9.94l3.72-3.72a.75.75 0 011.06 0z"
></path>
</svg>
</span>
)}
</span>
{children}
</li>
)
}
export const Playground = TreeViewListItemCollapsibleTemplate.bind({})
Playground.decorators = [
Story => (
<ListTemplate>
<Story />
</ListTemplate>
)
]
Playground.args = {
id: null,
truncateItem: false
}

View File

@ -0,0 +1,30 @@
import {Meta} from '@storybook/addon-docs'
<Meta title="UI Patterns/ActionList/ActionTreeView/TreeViewListItemCollapsible/README" />
# Action list tree view variant
`TreeView` markup and styles is considered unstable and in active development. The `collapsible` functionality and markup differs slightly from `ActionListItemCollapsible`, though this will likely converge as we work towards stability.
**All breaking changes have been scoped to `.ActionList` and reverted in `.ActionList--tree` for backwards compatibility**
### ActionListItemCollapsible
| element | attributes |
| ---------- | --------------------------------------------------------- |
| `<li>` | classes: `ActionList-item`, `ActionList-item--hasSubItem` |
| `<button>` | `onClick`, `aria-expanded`, `aria-controls`. `id` |
| `<button>` | classes: `ActionList-content--hasActiveSubItem` |
### TreeViewListItemCollapsible
| element | attributes |
| ------- | -------------------------------------------------------------------------------------------------------------------------- |
| `<li>` | `onClick`, `aria-level`, `role="treeitem"`, `aria-expanded`, `id` |
| `<li>` | classes: `ActionList-item`, `ActionList-item--hasSubItem`, `ActionList-item--subItem`, `ActionList-item--hasActiveSubItem` |
For `ActionListItemCollapsible` click handling functionality moved down one level to a semantic `<button>` element. With that change, CSS expand/collapse logic also moved down a level. This is indicated with our BEM style naming convention `item--` vs `content--`
| original class | new class |
| ----------------------------------- | -------------------------------------- |
| `ActionList-item--hasActiveSubItem` | `ActionList-content--hasActiveSubItem` |

View File

@ -0,0 +1,11 @@
import {Meta} from '@storybook/addon-docs'
<Meta title="UI Patterns/UI Patterns" />
## UI Patterns
This directory contains pattern level stories that are used to compose component level stories. In general these stories consist of all markup/css that make up an overall "pattern" while component stories are more refined and focused on their own features and intent.
As an example, Overlay is a pattern used by Dialog, Anchored overlay, and "dropdown" type scenarios. Overlay is a set of styles reused for those core components, and provides its own set of stories to be inherited from the UI Patterns directory.
Consider these stories "private API" and use the stories within the `Components` directory as an official API reference.

View File

@ -13,6 +13,7 @@
// no children
&:empty {
display: block;
height: 1px;
padding: 0;
margin: ($spacer-2 - 1px) ($spacer-2 * -1) $spacer-2;
@ -20,6 +21,12 @@
background: var(--color-action-list-item-inline-divider);
border: 0;
}
.ActionList-sectionDivider-title {
font-size: $font-size-small;
font-weight: $font-weight-bold;
color: var(--color-fg-muted);
}
}
.ActionList-sectionDivider--filled {

View File

@ -24,17 +24,10 @@
list-style: none;
background-color: transparent;
border-radius: $border-radius;
touch-action: manipulation;
-webkit-tap-highlight-color: transparent;
&:hover,
&:active {
cursor: pointer;
// a href
.ActionList-content {
text-decoration: none;
}
}
// only hover li without list as children
@ -157,98 +150,6 @@
}
}
// collapsible item [aria-expanded]
// nesting (single level)
// target items inside expanded subgroups
&[aria-expanded] {
.ActionList--subGroup {
@media screen and (prefers-reduced-motion: no-preference) {
transition: opacity 160ms cubic-bezier(0.25, 1, 0.5, 1), transform 160ms cubic-bezier(0.25, 1, 0.5, 1);
}
.ActionList-content {
padding-left: $spacer-4;
}
}
// has 16px leading visual
.ActionList-content--visual16 + .ActionList--subGroup {
.ActionList-content {
padding-left: $spacer-5;
}
}
// has 20px leading visual
.ActionList-content--visual20 + .ActionList--subGroup {
.ActionList-content {
padding-left: $spacer-2 * 4.5; // 36px
}
}
// has 24px leading visual
.ActionList-content--visual24 + .ActionList--subGroup {
.ActionList-content {
padding-left: $spacer-6;
}
}
}
&[aria-expanded='true'] {
.ActionList-item-collapseIcon {
transition: transform 120ms linear;
transform: scaleY(-1);
}
.ActionList--subGroup {
height: auto;
overflow: visible;
visibility: visible;
opacity: 1;
transform: translateY(0);
}
&.ActionList-item--hasActiveSubItem {
> .ActionList-content > .ActionList-item-label {
font-weight: $font-weight-bold;
}
}
}
&[aria-expanded='false'] {
.ActionList-item-collapseIcon {
transition: transform 120ms linear;
transform: scaleY(1);
}
.ActionList--subGroup {
height: 0;
overflow: hidden;
visibility: hidden;
opacity: 0;
transform: translateY(-$spacer-3);
}
// show active indicator on parent collapse if child is active
&.ActionList-item--hasActiveSubItem {
background: var(--color-action-list-item-default-selected-bg);
.ActionList-item-label {
font-weight: $font-weight-bold;
}
&::before,
+ .ActionList-item::before {
visibility: hidden;
}
// blue accent line
&::after {
@include activeIndicatorLine;
}
}
}
// checkbox item [aria-checked]
// listbox [aria-selected]
@ -363,11 +264,60 @@
}
}
&:active {
background: var(--color-action-list-item-danger-active-bg);
.ActionList-content {
&:active {
background: var(--color-action-list-item-danger-active-bg);
}
}
}
// if nested list exists, remove default padding
.ActionList {
// stylelint-disable-next-line primer/spacing
padding: unset;
}
}
// button or a href
.ActionList-content {
position: relative;
display: grid;
width: 100%;
// stylelint-disable-next-line primer/spacing
padding: $actionList-item-padding-vertical $actionList-item-padding-horizontal;
font-size: $body-font-size;
font-weight: $font-weight-normal;
color: var(--color-fg-default);
text-align: left;
user-select: none;
background-color: transparent;
// stylelint-disable-next-line declaration-property-value-disallowed-list
border: none;
border-radius: $border-radius;
transition: $actionList-item-bg-transition;
touch-action: manipulation;
touch-action: manipulation;
-webkit-tap-highlight-color: transparent;
grid-template-rows: min-content;
grid-template-areas: 'leadingAction leadingVisual label trailingVisual trailingAction';
grid-template-columns: min-content min-content minmax(0, auto) min-content min-content;
align-items: start;
// column-gap persists with empty grid-areas, margin applies only when children exist
> :not(:last-child) {
margin-right: $spacer-2;
}
// state
&:hover {
text-decoration: none;
}
&:focus-visible {
@include focusOutline;
}
// disabled
&[aria-disabled='true'] {
.ActionList-item-label,
@ -387,38 +337,96 @@
}
}
// if nested list exists, remove default padding
.ActionList {
// stylelint-disable-next-line primer/spacing
padding: unset;
}
}
// collapsible item [aria-expanded]
// span or a href
.ActionList-content {
position: relative;
display: grid;
// stylelint-disable-next-line primer/spacing
padding: $actionList-item-padding-vertical $actionList-item-padding-horizontal;
font-size: $body-font-size;
font-weight: $font-weight-normal;
color: var(--color-fg-default);
user-select: none;
touch-action: manipulation;
border-radius: $border-radius;
transition: $actionList-item-bg-transition;
grid-template-rows: min-content;
grid-template-areas: 'leadingAction leadingVisual label trailingVisual trailingAction';
grid-template-columns: min-content min-content minmax(0, auto) min-content min-content;
align-items: start;
// nesting (single level)
// target items inside expanded subgroups
&[aria-expanded] {
+ .ActionList--subGroup {
@media screen and (prefers-reduced-motion: no-preference) {
transition: opacity 160ms cubic-bezier(0.25, 1, 0.5, 1), transform 160ms cubic-bezier(0.25, 1, 0.5, 1);
}
// column-gap persists with empty grid-areas, margin applies only when children exist
> :not(:last-child) {
margin-right: $spacer-2;
.ActionList-content {
padding-left: $spacer-4;
}
}
// has 16px leading visual
&.ActionList-content--visual16 + .ActionList--subGroup {
.ActionList-content {
padding-left: $spacer-5;
}
}
// has 20px leading visual
&.ActionList-content--visual20 + .ActionList--subGroup {
.ActionList-content {
padding-left: $spacer-2 * 4.5; // 36px
}
}
// has 24px leading visual
&.ActionList-content--visual24 + .ActionList--subGroup {
.ActionList-content {
padding-left: $spacer-6;
}
}
}
&:focus-visible {
@include focusOutline;
&[aria-expanded='true'] {
.ActionList-item-collapseIcon {
transition: transform 120ms linear;
transform: scaleY(-1);
}
+ .ActionList--subGroup {
height: auto;
overflow: visible;
visibility: visible;
opacity: 1;
transform: translateY(0);
}
&.ActionList-content--hasActiveSubItem {
> .ActionList-item-label {
font-weight: $font-weight-bold;
}
}
}
&[aria-expanded='false'] {
.ActionList-item-collapseIcon {
transition: transform 120ms linear;
transform: scaleY(1);
}
+ .ActionList--subGroup {
height: 0;
overflow: hidden;
visibility: hidden;
opacity: 0;
transform: translateY(-$spacer-3);
}
// show active indicator on parent collapse if child is active
&.ActionList-content--hasActiveSubItem {
background: var(--color-action-list-item-default-selected-bg);
.ActionList-item-label {
font-weight: $font-weight-bold;
}
&::before,
+ .ActionList-item::before {
visibility: hidden;
}
// blue accent line
&::after {
@include activeIndicatorLine;
}
}
}
// sizes

View File

@ -1,9 +1,21 @@
// stylelint-disable max-nesting-depth, selector-max-compound-selectors, selector-max-specificity, no-duplicate-selectors, selector-max-type
// tree-view variant
// renders ActionList with default styling for tree-view
// collapse/expand icons presents as leadingActions, rotate 90deg
// connecting vertical lines between collapse groups
// consistent font-size between nested groups
@mixin activeIndicatorLine {
position: absolute;
top: calc(50% - 12px);
left: -$actionList-item-padding-horizontal;
width: $spacer-1;
height: $spacer-4;
content: '';
background: var(--color-accent-fg);
border-radius: $border-radius;
}
@mixin treeConnectingLine($left) {
position: absolute;
left: $left;
@ -21,6 +33,87 @@
}
.ActionList-item {
// start: copy from ActionList proper- backwards compatible for treeview with different markup structure
&[aria-expanded] {
.ActionList--subGroup {
@media screen and (prefers-reduced-motion: no-preference) {
transition: opacity 160ms cubic-bezier(0.25, 1, 0.5, 1), transform 160ms cubic-bezier(0.25, 1, 0.5, 1);
}
.ActionList-content {
padding-left: $spacer-4;
}
}
// has 16px leading visual
.ActionList-content--visual16 + .ActionList--subGroup {
.ActionList-content {
padding-left: $spacer-5;
}
}
// has 20px leading visual
.ActionList-content--visual20 + .ActionList--subGroup {
.ActionList-content {
padding-left: $spacer-2 * 4.5; // 36px
}
}
// has 24px leading visual
.ActionList-content--visual24 + .ActionList--subGroup {
.ActionList-content {
padding-left: $spacer-6;
}
}
}
&[aria-expanded='true'] {
.ActionList-item-collapseIcon {
transition: transform 120ms linear;
transform: scaleY(-1);
}
.ActionList--subGroup {
height: auto;
overflow: visible;
visibility: visible;
opacity: 1;
transform: translateY(0);
}
}
&[aria-expanded='false'] {
.ActionList-item-collapseIcon {
transition: transform 120ms linear;
transform: scaleY(1);
}
.ActionList--subGroup {
height: 0;
overflow: hidden;
visibility: hidden;
opacity: 0;
transform: translateY(-$spacer-3);
}
// show active indicator on parent collapse if child is active
// this class changed in ActionList proper
&.ActionList-item--hasActiveSubItem {
background: var(--color-action-list-item-default-selected-bg);
&::before,
+ .ActionList-item::before {
visibility: hidden;
}
// blue accent line
&::after {
@include activeIndicatorLine;
}
}
}
// end copy
// nesting (infinate levels)
// target items inside expanded subgroup
&[aria-expanded] {
@ -28,7 +121,6 @@
position: relative;
// --ActionList-tree-depth is defined as an inline style referencing the aria-level of each item ie: aria-level="2"
// stylelint-disable-next-line selector-max-specificity, max-nesting-depth, selector-max-compound-selectors
.ActionList-content {
padding-left: calc(#{$spacer-2} * var(--ActionList-tree-depth));
}
@ -54,11 +146,9 @@
// expand/collapse group
.ActionList-item--hasSubItem {
.ActionList-item--subItem:not(.ActionList-item--hasSubItem) {
// stylelint-disable-next-line selector-max-specificity, selector-max-compound-selectors
.ActionList-content {
// increase child padding by targeting content first child span (add to ActionList-content padding, not replace)
// creates a slight indent of child items
// stylelint-disable-next-line selector-max-specificity, selector-max-type, max-nesting-depth, selector-max-compound-selectors
> span:first-child {
padding-left: $spacer-4;
}
@ -69,7 +159,6 @@
// first subitem
> [aria-level='1'].ActionList-item--hasSubItem {
> .ActionList--subGroup {
// stylelint-disable-next-line selector-max-specificity
&::before {
@include treeConnectingLine($left: $spacer-3);
}
@ -80,7 +169,6 @@
// center connecting line with parent (line is 1px (8px - 1px)
.ActionList-item--hasSubItem:not([aria-level='1']) {
> .ActionList--subGroup {
// stylelint-disable-next-line selector-max-specificity
&::before {
@include treeConnectingLine(
$left: calc(#{$spacer-2} * (var(--ActionList-tree-depth)) + #{$spacer-2 - $border-width})

View File

@ -8,6 +8,11 @@
padding: 0;
}
// nested list within main ActionList
.ActionList--subGroup {
padding: 0;
}
// dividers
.ActionList--divided {