PUI-44 feat(tree-index)!: build TreeIndex to any depth and drop the tree from Index and DataTable #114

Merged
pienter merged 4 commits from feature/PUI-44-build-treeindex-to-any-depth-and-remove-the-tree-f into main 2026-09-22 14:34:09 +00:00
Owner

TreeIndex is its own component (ADR 0012, Goal Tree Index, milestone 31, page 45).

  • TreeTable at @pienter/ui/components/TreeTable.vue: the data-driven tree over Table, the way DataTable is for flat rows. Controlled rows and v-model:placing; draws the lanes, level cue, move buttons and zones; emits the move intent.
  • TreeIndex at @pienter/ui/components/TreeIndex.vue: composes TreeTable, loads the whole tree in manual order, shows loading, error and retry, owns the placing state and the optimistic move with rollback and announcement, renders any depth with an optional maxDepth, and names depth and direct parent in a hidden "Level n, under parent" row-header prefix. Plain <table>, no treegrid, no collapse.
  • Index and DataTable lose loadTree, move, parentKey, canMove, canParent, rowLabel and moveLabels; useIndexQuery loses loadTree and tree. They are the paged list and the flat table again.
  • utils/tree walks any depth (treeItems, applyMove, moveTo); MoveLabels.childOf becomes level(n, parent).
  • Storybook: TreeIndex stories (Default with play, Max Depth, Read Only, Load Failed) and TreeTable stories (Default with play, Max Depth, Selectable, Read Only, Loading); the DataTable Tree story is gone. AUDIT.md for tree-table, tree-index, index and table; CONVENTIONS.md; ADR 0012 consequence line clarified.
  • Playground: the Pages index is a TreeIndex with three seeded third-level pages; search and filters return with PUI-42. examples/CMS_PLAYGROUND.md updated.

Breaking (feat!), migration under ## Unreleased in packages/ui/CHANGELOG.md. The move request body is unchanged.

Also fix(table): .pui-table-wrap is position: relative, so the table's visually hidden content (caption, typed header labels, the live region in the after slot) no longer stretches the page to the table's height. That made a long tree scroll the window behind the app layout's own scrolling main and left a gap under the sticky footer.

Checks: typecheck, lint, format:check, bun test (164), build:vue, build:storybook. Browser: three-level tree at rest, pointer and keyboard moves, Escape with focus return, rejected move under Contact rolled back and announced, TreeIndex Default and Max Depth and TreeTable Default story plays pass.

Follow-ups in the Goal: PUI-42 (dimming search and filters), PUI-43 (Tree contract section and schema). Out of scope: PUI-76, the Button label contrast axe flags in these stories.

Refs: PUI-44

TreeIndex is its own component (ADR 0012, Goal Tree Index, milestone 31, page 45). - `TreeTable` at `@pienter/ui/components/TreeTable.vue`: the data-driven tree over `Table`, the way `DataTable` is for flat rows. Controlled `rows` and `v-model:placing`; draws the lanes, level cue, move buttons and zones; emits the `move` intent. - `TreeIndex` at `@pienter/ui/components/TreeIndex.vue`: composes `TreeTable`, loads the whole tree in manual order, shows loading, error and retry, owns the placing state and the optimistic `move` with rollback and announcement, renders any depth with an optional `maxDepth`, and names depth and direct parent in a hidden "Level n, under parent" row-header prefix. Plain `<table>`, no `treegrid`, no collapse. - `Index` and `DataTable` lose `loadTree`, `move`, `parentKey`, `canMove`, `canParent`, `rowLabel` and `moveLabels`; `useIndexQuery` loses `loadTree` and `tree`. They are the paged list and the flat table again. - `utils/tree` walks any depth (`treeItems`, `applyMove`, `moveTo`); `MoveLabels.childOf` becomes `level(n, parent)`. - Storybook: `TreeIndex` stories (Default with play, Max Depth, Read Only, Load Failed) and `TreeTable` stories (Default with play, Max Depth, Selectable, Read Only, Loading); the DataTable Tree story is gone. AUDIT.md for tree-table, tree-index, index and table; CONVENTIONS.md; ADR 0012 consequence line clarified. - Playground: the Pages index is a `TreeIndex` with three seeded third-level pages; search and filters return with PUI-42. `examples/CMS_PLAYGROUND.md` updated. Breaking (`feat!`), migration under `## Unreleased` in `packages/ui/CHANGELOG.md`. The move request body is unchanged. Also `fix(table)`: `.pui-table-wrap` is `position: relative`, so the table's visually hidden content (caption, typed header labels, the live region in the `after` slot) no longer stretches the page to the table's height. That made a long tree scroll the window behind the app layout's own scrolling main and left a gap under the sticky footer. Checks: typecheck, lint, format:check, bun test (164), build:vue, build:storybook. Browser: three-level tree at rest, pointer and keyboard moves, Escape with focus return, rejected move under Contact rolled back and announced, TreeIndex Default and Max Depth and TreeTable Default story plays pass. Follow-ups in the Goal: PUI-42 (dimming search and filters), PUI-43 (Tree contract section and schema). Out of scope: PUI-76, the Button label contrast axe flags in these stories. Refs: PUI-44
TreeIndex is its own component (ADR 0012): it loads the whole tree in
manual order, owns the placing state and the optimistic move with rollback
and announcement, shows every level with an optional maxDepth, and names
depth and direct parent in a hidden row-header prefix. Index and DataTable
lose their tree props and go back to the paged list and the flat table;
utils/tree walks any depth. The CHANGELOG entry carries the migration.

Refs: PUI-44
chore(examples): move the Pages index to TreeIndex and seed third-level pages
All checks were successful
ci / typecheck (pull_request) Successful in 32s
ci / lint (pull_request) Successful in 37s
ci / format (pull_request) Successful in 40s
ci / release (pull_request) Has been skipped
25fbd4adf8
Refs: PUI-44
feat(tree-table): split the tree rendering out of TreeIndex into TreeTable
All checks were successful
ci / typecheck (pull_request) Successful in 35s
ci / lint (pull_request) Successful in 38s
ci / format (pull_request) Successful in 40s
ci / release (pull_request) Has been skipped
596d0f3585
TreeTable is the data-driven tree over Table, the way DataTable is for
flat rows: it draws the lanes, level cue, move buttons and zones from
controlled rows and a placing key, and emits the move intent. TreeIndex
keeps the lifecycle: load, error and retry, the move call with rollback
and the outcome announcements. ADR 0003's layering now holds on both
sides; ADR 0012's consequence line says so.

Refs: PUI-44
fix(table): contain the table's visually hidden content in its scroll port
All checks were successful
ci / typecheck (pull_request) Successful in 33s
ci / lint (pull_request) Successful in 36s
ci / format (pull_request) Successful in 39s
ci / release (pull_request) Has been skipped
c24d473e8e
The caption, typed header labels and a live region in the after slot are
absolutely positioned; with a static wrap their containing block was the
page, which grew to the table's height and scrolled behind the app
layout's own scrolling main. The wrap is position: relative now.

Refs: PUI-44
pienter deleted branch feature/PUI-44-build-treeindex-to-any-depth-and-remove-the-tree-f 2026-09-22 14:34:09 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
pienter/ui!114
No description provided.