Files
suaveplan/openspec/changes/enterprise-react-tree-view/tasks.md
2026-05-27 23:29:53 +01:00

87 lines
4.2 KiB
Markdown

# Tasks: enterprise-react-tree-view
**Change ID**: enterprise-react-tree-view
**Package**: `@suaveplan/react-tree-view`
**Target path**: `react/ui/react-tree-view`
**Prerequisite packages on Verdaccio**: `@suaveplan/error`, `@suaveplan/react-translate`, `@suaveplan/react-virtual`
---
## 0. Pre-flight (non-negotiable)
- [ ] 0.1 Confirm clean working tree (`git status` reports nothing) and no in-flight worktrees with uncommitted work (`git worktree list` then `git status` in each)
- [ ] 0.2 If any worktrees exist under `.claude/worktrees/`, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (`git worktree remove`) before opening a new one — code that has been lost twice on main is the failure mode this guards against.
- [ ] 0.3 Confirm the package set in `MANIFEST.md` matches `find packages -maxdepth 3 -name package.json` count. Drift here means a prior change archived without regenerating the manifest.
## 1. Scaffold
- [ ] Create directory tree per proposal layout.
- [ ] Write `package.json` at `0.1.0` with `"sideEffects": false`, exports map.
- [ ] Dependencies: `@suaveplan/error workspace:^`, `@suaveplan/react-translate workspace:^`, `@suaveplan/react-virtual workspace:^`, `zod catalog:forms`, `tslib catalog:build`.
- [ ] Write `tsconfig.json`, `vitest.config.ts`, scripts.
---
## 2. Types and errors
- [ ] Define `TreeViewError` extending `SuaveplanError`; code: `TREE_VIEW_CONTEXT_MISSING`.
- [ ] Define `TreeNode<T>`: `{ id: string; label: string; children?: TreeNode<T>[]; data?: T; disabled?: boolean }`.
- [ ] Define `TreeViewProps<T>`, `UseTreeStateOptions`, `UseTreeStateReturn`.
---
## 3. Utils (`src/utils/tree-utils/`)
- [ ] Implement `flattenTree<T>(root)` — DFS traversal, returns flat array.
- [ ] Implement `filterTree<T>(root, predicate)` — returns subtree containing matching nodes; `null` if no match.
- [ ] Implement `collectAllIds<T>(root)` — returns all `id` values.
- [ ] Write `tree-utils.test.ts` (≤500 lines): flat tree, nested tree, filter no-match, filter partial-match, collectAllIds deep. `{ timeout: 5000 }`.
- [ ] Write `tree-utils.md`.
---
## 4. Hook — `useTreeState`
- [ ] Manages `expandedIds: Set<string>` in `useState`.
- [ ] Exposes `toggle(id)`, `expand(id)`, `collapse(id)`, `expandAll(tree)`, `collapseAll()`, `isExpanded(id)`.
- [ ] Controlled mode: accepts `expandedIds` + `onExpandedChange` props; uncontrolled: manages internally.
- [ ] Activates `@suaveplan/react-virtual` `useVirtualList` when `flattenTree(root).length > 100`.
- [ ] Write `use-tree-state.test.ts`: toggle, expand, collapse, expandAll, collapseAll, controlled mode, uncontrolled mode. `{ timeout: 5000 }`.
- [ ] Write `use-tree-state.md`.
---
## 5. Components
### TreeNodeComponent
- [ ] Renders arrow indicator (collapsed/expanded), indent per `depth`, optional `showLines`, `renderNode` slot for custom node markup.
- [ ] Keyboard: `ArrowRight` expands, `ArrowLeft` collapses (or moves to parent when already collapsed), `ArrowDown`/`ArrowUp` moves focus to next/prev visible node.
- [ ] `aria-expanded`, `aria-selected`, `role="treeitem"`, `tabIndex` management.
- [ ] Write test, stories (default, with-custom-render, playground), md.
### TreeView
- [ ] Top-level controlled/uncontrolled tree: optional search input (`showSearch` prop) using `useTranslation` for placeholder; filters via `filterTree` on input change.
- [ ] Renders `TreeNodeComponent` for each visible node; uses virtual list when node count > 100.
- [ ] `role="tree"`, `aria-label` from i18n.
- [ ] Write test, stories (default, large-tree 500 nodes, with-search, keyboard-nav, playground), md.
---
## 6. E2E
- [ ] `e2e/tree-view.spec.ts` — Playwright:
- Render tree, click expand arrow, verify children visible.
- Keyboard: Tab into tree, `ArrowRight` to expand, `ArrowDown` to move focus, `ArrowLeft` to collapse.
- Type in search box, verify filtered nodes only.
---
## 7. Verify and publish
- [ ] `bunx turbo lint typecheck test --filter=@suaveplan/react-tree-view` — green.
- [ ] `bunx turbo test:coverage --filter=@suaveplan/react-tree-view` — 100%.
- [ ] `bun scripts/publish.ts --package @suaveplan/react-tree-view`.
- [ ] Archive change folder.