Skip to content

Commit 5e50d2f

Browse files
authored
fix(webapp): align tree mouse and keyboard interactions (#4701)
## Summary Move tree selection onto semantic tree items and use native expansion buttons. Dashboard and story tree rows now share mouse and keyboard selection through `getNodeProps`. Expand and collapse affordances are named buttons instead of clickable layout elements. Base: [#4700](#4700)
1 parent 5ae2471 commit 5e50d2f

3 files changed

Lines changed: 47 additions & 18 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
area: webapp
3+
type: fix
4+
---
5+
6+
Run trace rows now respond consistently to mouse and keyboard selection, including Alt-click expansion controls.

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -968,6 +968,11 @@ function TasksTreeView({
968968
},
969969
});
970970

971+
const getInteractiveNodeProps = (id: string) => ({
972+
...getNodeProps(id),
973+
onClick: () => selectNode(id),
974+
});
975+
971976
return (
972977
<div className="grid h-full grid-rows-[2.5rem_1fr_3.25rem] overflow-hidden">
973978
<div className="flex items-center justify-between gap-2 border-b border-grid-dimmed px-1.5">
@@ -1047,7 +1052,7 @@ function TasksTreeView({
10471052
autoFocus
10481053
tree={events}
10491054
nodes={nodes}
1050-
getNodeProps={getNodeProps}
1055+
getNodeProps={getInteractiveNodeProps}
10511056
getTreeProps={getTreeProps}
10521057
parentClassName="pl-3"
10531058
renderNode={({ node, state, index }) => (
@@ -1058,9 +1063,6 @@ function TasksTreeView({
10581063
? "bg-grid-dimmed hover:bg-grid-bright"
10591064
: "bg-transparent hover:bg-grid-dimmed"
10601065
)}
1061-
onClick={() => {
1062-
selectNode(node.id);
1063-
}}
10641066
>
10651067
<div className="flex h-8 items-center">
10661068
{Array.from({ length: node.level }).map((_, index) => (
@@ -1070,9 +1072,18 @@ function TasksTreeView({
10701072
isSelected={state.selected}
10711073
/>
10721074
))}
1073-
<div
1075+
<button
1076+
type="button"
1077+
tabIndex={-1}
1078+
aria-label={
1079+
node.hasChildren
1080+
? state.expanded
1081+
? "Collapse task"
1082+
: "Expand task"
1083+
: "Select task"
1084+
}
10741085
className={cn(
1075-
"flex h-8 w-4 items-center",
1086+
"flex h-8 w-4 items-center focus-custom",
10761087
node.hasChildren && "hover:bg-surface-control"
10771088
)}
10781089
onClick={(e) => {
@@ -1083,10 +1094,13 @@ function TasksTreeView({
10831094
} else {
10841095
expandAllBelowDepth(node.level);
10851096
}
1086-
} else {
1097+
} else if (node.hasChildren) {
10871098
toggleExpandNode(node.id);
1099+
} else {
1100+
selectNode(node.id, false);
10881101
}
10891102
scrollToNode(node.id);
1103+
parentRef.current?.focus({ preventScroll: true });
10901104
}}
10911105
>
10921106
{node.hasChildren ? (
@@ -1098,7 +1112,7 @@ function TasksTreeView({
10981112
) : (
10991113
<div className="h-8 w-4" />
11001114
)}
1101-
</div>
1115+
</button>
11021116
</div>
11031117

11041118
<div className="flex w-full items-center justify-between gap-2 pl-1">

apps/webapp/app/routes/storybook.tree-view/route.tsx

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,11 @@ function TreeViewParent({
177177
},
178178
});
179179

180+
const getInteractiveNodeProps = (id: string) => ({
181+
...getNodeProps(id),
182+
onClick: () => toggleNodeSelection(id),
183+
});
184+
180185
return (
181186
<div className="flex w-72 flex-col items-start gap-y-4 p-4">
182187
<div className="flex items-center gap-2">
@@ -203,7 +208,7 @@ function TreeViewParent({
203208
autoFocus
204209
tree={tree}
205210
nodes={nodes}
206-
getNodeProps={getNodeProps}
211+
getNodeProps={getInteractiveNodeProps}
207212
getTreeProps={getTreeProps}
208213
parentClassName="h-96 bg-background-deep"
209214
renderNode={({ node, state, index, virtualizer, virtualItem }) => (
@@ -215,19 +220,23 @@ function TreeViewParent({
215220
"flex cursor-pointer items-center gap-2 py-1 hover:bg-blue-500/10",
216221
state.selected && "bg-blue-500/20 hover:bg-blue-500/30"
217222
)}
218-
onClick={() => {
219-
toggleNodeSelection(node.id);
220-
}}
221223
>
222-
<div
223-
className="h-4 w-4"
224+
<button
225+
type="button"
226+
tabIndex={-1}
227+
aria-label={
228+
node.hasChildren
229+
? state.expanded
230+
? "Collapse node"
231+
: "Expand node"
232+
: "Select node"
233+
}
234+
className="h-4 w-4 focus-custom"
224235
onClick={(e) => {
225236
e.stopPropagation();
226237
toggleExpandNode(node.id);
227238
selectNode(node.id, true);
228-
}}
229-
onKeyDown={(e) => {
230-
console.log(e.key);
239+
parentRef.current?.focus();
231240
}}
232241
>
233242
{node.hasChildren ? (
@@ -239,7 +248,7 @@ function TreeViewParent({
239248
) : (
240249
<DocumentIcon className="h-4 w-4" />
241250
)}
242-
</div>
251+
</button>
243252
<div>{node.data.title}</div>
244253
</div>
245254
)}

0 commit comments

Comments
 (0)