Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ export const TrailingActions: StoryFn = () => {
label: 'Pull Requests',
onClick: () => alert('Pull Requests clicked'),
icon: GitPullRequestIcon,
count: 5,
},
]}
>
Expand Down
73 changes: 51 additions & 22 deletions packages/react/src/TreeView/TreeView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@ import {useTypeahead} from './useTypeahead'
import {SkeletonAvatar} from '../SkeletonAvatar'
import {SkeletonText} from '../SkeletonText'
import {Dialog} from '../Dialog/Dialog'
import {IconButton} from '../Button'
import {Button, IconButton} from '../Button'
import {ActionList} from '../ActionList'
import {getAccessibleKeybindingHintString} from '../KeybindingHint'
import {useIsMacOS} from '../hooks'
import {Tooltip} from '../TooltipV2'

// ----------------------------------------------------------------------------
// Context
Expand Down Expand Up @@ -80,6 +81,7 @@ export type TreeViewSecondaryActions = {
label: string
onClick: () => void
icon: Icon
count?: number | string
}

/* Size of toggle icon in pixels. */
Expand Down Expand Up @@ -739,7 +741,7 @@ const TrailingAction = (props: TreeViewTrailingAction) => {
return (
<>
<div id={trailingActionId} className={clsx('PRIVATE_VisuallyHidden', classes.TreeViewVisuallyHidden)}>
; {shortcutText}
- {shortcutText}
</div>
<div
className={classes.TreeViewItemTrailingAction}
Expand All @@ -751,25 +753,46 @@ const TrailingAction = (props: TreeViewTrailingAction) => {
}
onKeyDown={event => event.stopPropagation()}
>
{items.map(({label, onClick, icon}, index) => (
<IconButton
icon={icon}
variant="invisible"
aria-label={label}
className={classes.TreeViewItemTrailingActionButton}
onClick={onClick}
tabIndex={-1}
aria-hidden={true}
key={index}
onKeyDown={() => {
// hack to send focus back to the tree item after the action is triggered via click
// this is needed because the trailing action shouldn't be focused, as it does not interact well with
// the focus management of TreeView
const parentElement = document.getElementById(itemId)
parentElement?.focus()
}}
/>
))}
{items.map(({label, onClick, icon, count}, index) => {
// If there is a count, we render a Button instead of an IconButton,
// as IconButton doesn't support displaying a count.
if (count) {
return (
<Tooltip key={index} text={label}>
<Button
aria-label={label}
leadingVisual={icon}
variant="invisible"
className={classes.TreeViewItemTrailingActionButton}
onClick={onClick}
tabIndex={-1}
aria-hidden={true}
count={count}
/>
</Tooltip>
)
}

return (
<IconButton
icon={icon}
variant="invisible"
aria-label={label}
className={classes.TreeViewItemTrailingActionButton}
onClick={onClick}
tabIndex={-1}
aria-hidden={true}
key={index}
onKeyDown={() => {
// hack to send focus back to the tree item after the action is triggered via click
// this is needed because the trailing action shouldn't be focused, as it does not interact well with
// the focus management of TreeView
const parentElement = document.getElementById(itemId)
parentElement?.focus()
}}
/>
)
})}
</div>
</>
)
Expand Down Expand Up @@ -816,12 +839,18 @@ const ActionDialog: React.FC<TreeViewActionDialogProps> = ({items, onClose}) =>
}}
>
<ActionList>
{items.map(({label, onClick, icon: Icon}, index) => (
{items.map(({label, onClick, icon: Icon, count}, index) => (
<ActionList.Item key={index} onSelect={onClick}>
<ActionList.LeadingVisual>
<Icon />
</ActionList.LeadingVisual>
{label}
{count ? (
<ActionList.TrailingVisual>
{count}
<VisuallyHidden>items</VisuallyHidden>
</ActionList.TrailingVisual>
) : null}
</ActionList.Item>
))}
</ActionList>
Expand Down
Loading