mirror of
https://github.com/primer/css.git
synced 2024-12-23 06:01:54 +03:00
[Bug] TreeView animation and padding fix (#2019)
* restore deleted logic * fix stories * Create fuzzy-pants-decide.md * missing closed scenario
This commit is contained in:
parent
3c6d30f04e
commit
57be2d5021
5
.changeset/fuzzy-pants-decide.md
Normal file
5
.changeset/fuzzy-pants-decide.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"@primer/css": patch
|
||||
---
|
||||
|
||||
[Bug] TreeView animation and padding fix
|
@ -297,9 +297,7 @@ export const ListItemTemplate = ({
|
||||
<>
|
||||
<a
|
||||
href={href}
|
||||
role={
|
||||
href && !listSemantic && !treeitem ? 'menuitem' : undefined || (href && treeitem) ? 'treeitem' : undefined
|
||||
}
|
||||
role={href && !listSemantic && !treeitem ? 'menuitem' : undefined}
|
||||
aria-current={ariaCurrent}
|
||||
className={clsx(
|
||||
text && 'ActionList-content',
|
||||
|
@ -131,6 +131,14 @@ export default {
|
||||
table: {
|
||||
category: 'HTML'
|
||||
}
|
||||
},
|
||||
ariaLevel: {
|
||||
name: 'ariaLevel',
|
||||
type: 'string',
|
||||
description: 'number - nested subgroup',
|
||||
table: {
|
||||
category: 'HTML'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -149,11 +157,20 @@ export const ActionListItemCollapsibleTemplate = ({
|
||||
containsActiveSubItem,
|
||||
truncateItem,
|
||||
collapsePosition,
|
||||
ariaControlsId
|
||||
ariaControlsId,
|
||||
ariaLevel
|
||||
}) => {
|
||||
const [isCollapsed, itemIsCollapsed] = useToggle()
|
||||
const itemStyle = {
|
||||
'--ActionList-tree-depth': `${ariaLevel}`
|
||||
}
|
||||
return (
|
||||
<li className={clsx('ActionList-item', containsSubItem && `ActionList-item--hasSubItem`)}>
|
||||
<li
|
||||
className={clsx('ActionList-item', containsSubItem && `ActionList-item--hasSubItem`)}
|
||||
style={ariaLevel && itemStyle}
|
||||
aria-level={ariaLevel ? `${ariaLevel}` : undefined}
|
||||
role={ariaLevel ? 'treeitem' : undefined}
|
||||
>
|
||||
<button
|
||||
onClick={itemIsCollapsed}
|
||||
aria-expanded={isCollapsed ? 'false' : 'true'}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React from 'react'
|
||||
import {ListTemplate} from './ActionList.stories'
|
||||
import {ListItemTemplate} from './ActionListItem.stories'
|
||||
import {TreeViewListItemCollapsibleTemplate} from './TreeViewListItemCollapsible.stories'
|
||||
import {ActionListItemCollapsibleTemplate} from '../../ui-patterns/ActionList/ActionListItemCollapsible.stories.jsx'
|
||||
|
||||
export default {
|
||||
title: 'UI Patterns/ActionList/ActionTreeView',
|
||||
@ -53,22 +53,17 @@ export const ActionListTreeViewTemplate = ({showGroupIcon, showSubItemIcon, text
|
||||
<ListItemTemplate
|
||||
truncateItem={truncateItem}
|
||||
ariaLevel="1"
|
||||
ariaSetSize="1"
|
||||
ariaPosInset="1"
|
||||
treeitem
|
||||
text={text}
|
||||
href="/"
|
||||
leadingVisual={showSubItemIcon && file}
|
||||
trailingVisual={trailingVisual}
|
||||
treeItemSingleton
|
||||
/>
|
||||
<TreeViewListItemCollapsibleTemplate
|
||||
<ActionListItemCollapsibleTemplate
|
||||
text="level 1"
|
||||
leadingVisual={showGroupIcon && folder}
|
||||
truncateItem={truncateItem}
|
||||
ariaLevel="1"
|
||||
ariaSetSize="2"
|
||||
ariaPosInset="2"
|
||||
collapsePosition={0}
|
||||
containsSubItem
|
||||
containsActiveSubItem
|
||||
@ -77,32 +72,25 @@ export const ActionListTreeViewTemplate = ({showGroupIcon, showSubItemIcon, text
|
||||
<ListItemTemplate
|
||||
truncateItem={truncateItem}
|
||||
ariaLevel="2"
|
||||
ariaSetSize="2"
|
||||
ariaPosInset="1"
|
||||
treeitem
|
||||
subItem
|
||||
text={text}
|
||||
href="/"
|
||||
ariaCurrent="page"
|
||||
leadingVisual={showSubItemIcon && file}
|
||||
trailingVisual={trailingVisual}
|
||||
/>
|
||||
<TreeViewListItemCollapsibleTemplate
|
||||
<ActionListItemCollapsibleTemplate
|
||||
text="level 2"
|
||||
leadingVisual={showGroupIcon && folder}
|
||||
truncateItem={truncateItem}
|
||||
ariaLevel="2"
|
||||
ariaSetSize="2"
|
||||
ariaPosInset="2"
|
||||
collapsePosition={0}
|
||||
containsSubItem
|
||||
>
|
||||
<ListTemplate listType="nested">
|
||||
<TreeViewListItemCollapsibleTemplate
|
||||
<ActionListItemCollapsibleTemplate
|
||||
text="level 3"
|
||||
ariaLevel="3"
|
||||
ariaSetSize="2"
|
||||
ariaPosInset="1"
|
||||
leadingVisual={showGroupIcon && folder}
|
||||
truncateItem={truncateItem}
|
||||
collapsePosition={0}
|
||||
@ -112,65 +100,50 @@ export const ActionListTreeViewTemplate = ({showGroupIcon, showSubItemIcon, text
|
||||
<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>
|
||||
</ActionListItemCollapsibleTemplate>
|
||||
<ListItemTemplate
|
||||
truncateItem={truncateItem}
|
||||
ariaLevel="3"
|
||||
ariaSetSize="2"
|
||||
ariaPosInset="2"
|
||||
treeitem
|
||||
subItem
|
||||
text={text}
|
||||
href=""
|
||||
leadingVisual={showSubItemIcon && file}
|
||||
trailingVisual={trailingVisual}
|
||||
/>
|
||||
</ListTemplate>
|
||||
</TreeViewListItemCollapsibleTemplate>
|
||||
</ActionListItemCollapsibleTemplate>
|
||||
</ListTemplate>
|
||||
</TreeViewListItemCollapsibleTemplate>
|
||||
</ActionListItemCollapsibleTemplate>
|
||||
<ListItemTemplate
|
||||
truncateItem={truncateItem}
|
||||
ariaLevel="1"
|
||||
ariaSetSize="1"
|
||||
ariaPosInset="1"
|
||||
treeitem
|
||||
text={text}
|
||||
href="/"
|
||||
leadingVisual={showSubItemIcon && file}
|
||||
trailingVisual={trailingVisual}
|
||||
treeItemSingleton
|
||||
|
@ -1,292 +0,0 @@
|
||||
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'
|
||||
}
|
||||
},
|
||||
containsActiveSubItem: {
|
||||
defaultValue: false,
|
||||
control: {type: 'boolean'},
|
||||
table: {
|
||||
category: 'CSS'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const TreeViewListItemCollapsibleTemplate = ({
|
||||
text,
|
||||
size,
|
||||
leadingVisual,
|
||||
leadingVisualSize,
|
||||
trailingVisual,
|
||||
description,
|
||||
descriptionVariant,
|
||||
children,
|
||||
containsSubItem,
|
||||
id,
|
||||
truncateItem,
|
||||
collapsePosition,
|
||||
ariaSetSize,
|
||||
ariaPosInset,
|
||||
ariaLevel,
|
||||
ariaDisabled,
|
||||
containsActiveSubItem
|
||||
}) => {
|
||||
const [isCollapsed, itemIsCollapsed] = useToggle()
|
||||
const itemStyle = {
|
||||
'--ActionList-tree-depth': `${ariaLevel}`
|
||||
}
|
||||
return (
|
||||
<li
|
||||
className={clsx(
|
||||
'ActionList-item',
|
||||
containsSubItem && `ActionList-item--hasSubItem`,
|
||||
containsActiveSubItem && `ActionList-item--hasActiveSubItem`
|
||||
)}
|
||||
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
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
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` |
|
@ -5,17 +5,6 @@
|
||||
// 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;
|
||||
@ -48,11 +37,13 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ActionList-content {
|
||||
// nesting (infinite levels)
|
||||
// target items inside expanded subgroup
|
||||
&[aria-expanded] {
|
||||
.ActionList--subGroup {
|
||||
+ .ActionList--subGroup {
|
||||
position: relative;
|
||||
|
||||
// --ActionList-tree-depth is defined as an inline style referencing the aria-level of each item ie: aria-level="2"
|
||||
@ -70,8 +61,8 @@
|
||||
}
|
||||
|
||||
// normal weight for parent folder containing active child
|
||||
.ActionList-content--hasActiveSubItem {
|
||||
>.ActionList-item-label {
|
||||
&.ActionList-content--hasActiveSubItem {
|
||||
> .ActionList-item-label {
|
||||
font-weight: $font-weight-normal;
|
||||
}
|
||||
}
|
||||
@ -82,6 +73,12 @@
|
||||
transition: transform 120ms linear;
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
&.ActionList-content--hasActiveSubItem {
|
||||
> .ActionList-item-label {
|
||||
font-weight: $font-weight-normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user