1
1
mirror of https://github.com/primer/css.git synced 2024-12-23 14:13:14 +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:
Katie Langerman 2022-04-05 17:16:54 -07:00 committed by GitHub
parent 3c6d30f04e
commit 57be2d5021
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 43 additions and 375 deletions

View File

@ -0,0 +1,5 @@
---
"@primer/css": patch
---
[Bug] TreeView animation and padding fix

View File

@ -297,9 +297,7 @@ export const ListItemTemplate = ({
<> <>
<a <a
href={href} href={href}
role={ role={href && !listSemantic && !treeitem ? 'menuitem' : undefined}
href && !listSemantic && !treeitem ? 'menuitem' : undefined || (href && treeitem) ? 'treeitem' : undefined
}
aria-current={ariaCurrent} aria-current={ariaCurrent}
className={clsx( className={clsx(
text && 'ActionList-content', text && 'ActionList-content',

View File

@ -131,6 +131,14 @@ export default {
table: { table: {
category: 'HTML' category: 'HTML'
} }
},
ariaLevel: {
name: 'ariaLevel',
type: 'string',
description: 'number - nested subgroup',
table: {
category: 'HTML'
}
} }
} }
} }
@ -149,11 +157,20 @@ export const ActionListItemCollapsibleTemplate = ({
containsActiveSubItem, containsActiveSubItem,
truncateItem, truncateItem,
collapsePosition, collapsePosition,
ariaControlsId ariaControlsId,
ariaLevel
}) => { }) => {
const [isCollapsed, itemIsCollapsed] = useToggle() const [isCollapsed, itemIsCollapsed] = useToggle()
const itemStyle = {
'--ActionList-tree-depth': `${ariaLevel}`
}
return ( 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 <button
onClick={itemIsCollapsed} onClick={itemIsCollapsed}
aria-expanded={isCollapsed ? 'false' : 'true'} aria-expanded={isCollapsed ? 'false' : 'true'}

View File

@ -1,7 +1,7 @@
import React from 'react' import React from 'react'
import {ListTemplate} from './ActionList.stories' import {ListTemplate} from './ActionList.stories'
import {ListItemTemplate} from './ActionListItem.stories' import {ListItemTemplate} from './ActionListItem.stories'
import {TreeViewListItemCollapsibleTemplate} from './TreeViewListItemCollapsible.stories' import {ActionListItemCollapsibleTemplate} from '../../ui-patterns/ActionList/ActionListItemCollapsible.stories.jsx'
export default { export default {
title: 'UI Patterns/ActionList/ActionTreeView', title: 'UI Patterns/ActionList/ActionTreeView',
@ -53,22 +53,17 @@ export const ActionListTreeViewTemplate = ({showGroupIcon, showSubItemIcon, text
<ListItemTemplate <ListItemTemplate
truncateItem={truncateItem} truncateItem={truncateItem}
ariaLevel="1" ariaLevel="1"
ariaSetSize="1"
ariaPosInset="1"
treeitem treeitem
text={text} text={text}
href="/"
leadingVisual={showSubItemIcon && file} leadingVisual={showSubItemIcon && file}
trailingVisual={trailingVisual} trailingVisual={trailingVisual}
treeItemSingleton treeItemSingleton
/> />
<TreeViewListItemCollapsibleTemplate <ActionListItemCollapsibleTemplate
text="level 1" text="level 1"
leadingVisual={showGroupIcon && folder} leadingVisual={showGroupIcon && folder}
truncateItem={truncateItem} truncateItem={truncateItem}
ariaLevel="1" ariaLevel="1"
ariaSetSize="2"
ariaPosInset="2"
collapsePosition={0} collapsePosition={0}
containsSubItem containsSubItem
containsActiveSubItem containsActiveSubItem
@ -77,32 +72,25 @@ export const ActionListTreeViewTemplate = ({showGroupIcon, showSubItemIcon, text
<ListItemTemplate <ListItemTemplate
truncateItem={truncateItem} truncateItem={truncateItem}
ariaLevel="2" ariaLevel="2"
ariaSetSize="2"
ariaPosInset="1"
treeitem treeitem
subItem subItem
text={text} text={text}
href="/"
ariaCurrent="page" ariaCurrent="page"
leadingVisual={showSubItemIcon && file} leadingVisual={showSubItemIcon && file}
trailingVisual={trailingVisual} trailingVisual={trailingVisual}
/> />
<TreeViewListItemCollapsibleTemplate <ActionListItemCollapsibleTemplate
text="level 2" text="level 2"
leadingVisual={showGroupIcon && folder} leadingVisual={showGroupIcon && folder}
truncateItem={truncateItem} truncateItem={truncateItem}
ariaLevel="2" ariaLevel="2"
ariaSetSize="2"
ariaPosInset="2"
collapsePosition={0} collapsePosition={0}
containsSubItem containsSubItem
> >
<ListTemplate listType="nested"> <ListTemplate listType="nested">
<TreeViewListItemCollapsibleTemplate <ActionListItemCollapsibleTemplate
text="level 3" text="level 3"
ariaLevel="3" ariaLevel="3"
ariaSetSize="2"
ariaPosInset="1"
leadingVisual={showGroupIcon && folder} leadingVisual={showGroupIcon && folder}
truncateItem={truncateItem} truncateItem={truncateItem}
collapsePosition={0} collapsePosition={0}
@ -112,65 +100,50 @@ export const ActionListTreeViewTemplate = ({showGroupIcon, showSubItemIcon, text
<ListItemTemplate <ListItemTemplate
truncateItem={truncateItem} truncateItem={truncateItem}
ariaLevel="4" ariaLevel="4"
ariaSetSize="4"
ariaPosInset="1"
treeitem treeitem
subItem subItem
text={text} text={text}
href=""
leadingVisual={showSubItemIcon && file} leadingVisual={showSubItemIcon && file}
trailingVisual={trailingVisual} trailingVisual={trailingVisual}
/> />
<ListItemTemplate <ListItemTemplate
truncateItem={truncateItem} truncateItem={truncateItem}
ariaLevel="4" ariaLevel="4"
ariaSetSize="4"
ariaPosInset="2"
treeitem treeitem
subItem subItem
text={text} text={text}
href=""
leadingVisual={showSubItemIcon && file} leadingVisual={showSubItemIcon && file}
trailingVisual={trailingVisual} trailingVisual={trailingVisual}
/> />
<ListItemTemplate <ListItemTemplate
truncateItem={truncateItem} truncateItem={truncateItem}
ariaLevel="4" ariaLevel="4"
ariaSetSize="4"
ariaPosInset="3"
treeitem treeitem
subItem subItem
text={text} text={text}
href=""
leadingVisual={showSubItemIcon && file} leadingVisual={showSubItemIcon && file}
trailingVisual={trailingVisual} trailingVisual={trailingVisual}
/> />
</ListTemplate> </ListTemplate>
</TreeViewListItemCollapsibleTemplate> </ActionListItemCollapsibleTemplate>
<ListItemTemplate <ListItemTemplate
truncateItem={truncateItem} truncateItem={truncateItem}
ariaLevel="3" ariaLevel="3"
ariaSetSize="2"
ariaPosInset="2"
treeitem treeitem
subItem subItem
text={text} text={text}
href=""
leadingVisual={showSubItemIcon && file} leadingVisual={showSubItemIcon && file}
trailingVisual={trailingVisual} trailingVisual={trailingVisual}
/> />
</ListTemplate> </ListTemplate>
</TreeViewListItemCollapsibleTemplate> </ActionListItemCollapsibleTemplate>
</ListTemplate> </ListTemplate>
</TreeViewListItemCollapsibleTemplate> </ActionListItemCollapsibleTemplate>
<ListItemTemplate <ListItemTemplate
truncateItem={truncateItem} truncateItem={truncateItem}
ariaLevel="1" ariaLevel="1"
ariaSetSize="1"
ariaPosInset="1"
treeitem treeitem
text={text} text={text}
href="/"
leadingVisual={showSubItemIcon && file} leadingVisual={showSubItemIcon && file}
trailingVisual={trailingVisual} trailingVisual={trailingVisual}
treeItemSingleton treeItemSingleton

View File

@ -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
}

View File

@ -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` |

View File

@ -5,17 +5,6 @@
// connecting vertical lines between collapse groups // connecting vertical lines between collapse groups
// consistent font-size between nested 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) { @mixin treeConnectingLine($left) {
position: absolute; position: absolute;
left: $left; left: $left;
@ -48,11 +37,13 @@
} }
} }
} }
}
.ActionList-content {
// nesting (infinite levels) // nesting (infinite levels)
// target items inside expanded subgroup // target items inside expanded subgroup
&[aria-expanded] { &[aria-expanded] {
.ActionList--subGroup { + .ActionList--subGroup {
position: relative; position: relative;
// --ActionList-tree-depth is defined as an inline style referencing the aria-level of each item ie: aria-level="2" // --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 // normal weight for parent folder containing active child
.ActionList-content--hasActiveSubItem { &.ActionList-content--hasActiveSubItem {
>.ActionList-item-label { > .ActionList-item-label {
font-weight: $font-weight-normal; font-weight: $font-weight-normal;
} }
} }
@ -82,6 +73,12 @@
transition: transform 120ms linear; transition: transform 120ms linear;
transform: rotate(-90deg); transform: rotate(-90deg);
} }
&.ActionList-content--hasActiveSubItem {
> .ActionList-item-label {
font-weight: $font-weight-normal;
}
}
} }
} }