tree-rows
$ npx shadcn@latest add https://lacodda.github.io/dowel/r/tree-rows.jsonSplit out of TreeView for the reason table-sort and calendar-math were split out of theirs: these are the sums, and the component is the thing that draws them.
Flattening is what makes the keyboard simple. Down is the next row of this list and Up the previous, and neither has to know about nesting. A recursive walk at every keystroke would ask the same question — what is visually next — and answer it differently at each depth.
const rows = visibleRows(nodes, open)// [{ node, depth: 0, parent: undefined }, { node, depth: 1, parent: 'src' }, …]parent is what Left uses. Getting out of a deep folder in one press
rather than walking back up through every sibling needs to know which branch a
row is inside — and that is a fact about the flattened list, not about the
node.
It is also the answer to “how many rows is this tree”, which is what a product needs before putting a tree inside a VirtualList: the window has to be computed from the visible rows, and those depend on what is open.
An empty folder is a folder. children: [] says nothing — absence of
children is what a leaf looks like — so empty marks a folder that opens and
shows nothing, and isBranch counts it as one.
| Type | ||
|---|---|---|
visibleRows |
(nodes, open, depth?, parent?) => TreeRow[] |
The rows, in the order the eye travels |
isBranch |
(node) => boolean |
Something that opens, even if empty |
TreeNode |
{ id, label, children?, empty? } |
|
TreeRow |
{ node, depth, parent? } |
Accessibility
The examples on the stand, through axe 4.14.0 in a browser, in both themes, against WCAG 2.2 A and AA and axe's best practices: 5 rules applied and passed, and none failed. The accessibility report has every item.
History
Each release that changed ui/tree-rows.tsx - the file a product copies - newest first.