Skip to content

feat(Treeview): add new component#144

Merged
johnleider merged 23 commits intomasterfrom
feat/treeview
Mar 24, 2026
Merged

feat(Treeview): add new component#144
johnleider merged 23 commits intomasterfrom
feat/treeview

Conversation

@johnleider
Copy link
Copy Markdown
Member

@johnleider johnleider commented Mar 4, 2026

Summary

  • Adds a headless compound Treeview component built on createNested composable
  • 10 sub-components: Root, List, Item, Activator, Content, Cue, Checkbox, Indicator, Group, SelectAll
  • Full WAI-ARIA treeview pattern with keyboard support
  • Cascade, independent, and leaf selection modes
  • Tri-state checkbox with mixed/indeterminate states
  • Documentation page with settings panel and cascade selection examples
  • API reference with JSDoc descriptions and @example snippets for all props
  • Fixed generate-api.ts to extract props and examples from external types.ts files via ts-morph fallback

Sub-components

Component Purpose
Treeview.Root Provides nested context, selection mode, open strategy
Treeview.List Wrapper with role="tree" and aria-multiselectable
Treeview.Item Registers as tree node, provides item context
Treeview.Activator Toggle button for expand/collapse
Treeview.Content Collapsible children container
Treeview.Cue Visual expand/collapse indicator (chevron)
Treeview.Checkbox Tri-state selection checkbox
Treeview.Indicator Visual selection state indicator
Treeview.Group Semantic role="group" wrapper
Treeview.SelectAll Tree-wide select/unselect toggle

Test plan

  • 1267 lines of component tests (54 tests)
  • 114 composable tests for createNested
  • Full suite: 3065 tests passing
  • Typecheck clean
  • Lint clean
  • knip + sherif clean
  • Manual: verify docs page renders at /components/disclosure/treeview
  • Manual: verify API reference shows descriptions and code examples

johnleider and others added 8 commits March 1, 2026 20:36
Headless treeview with 9 sub-components: Root, List, Item, Activator,
Content, Cue, Group, Checkbox, Indicator. Built on createNested for
tree state management with selection, open/close, and activation.

Exposes --v0-treeview-depth CSS custom property on each item for
consumer-driven indentation. Cue self-hides on leaf nodes via
hasContent signal from Content. Indicator follows existing
CheckboxIndicator pattern with data-state visibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…gister

Ticket select/unselect/toggle were pointing to createGroup's
non-cascade versions. Override them after group.register() so
TreeviewCheckbox clicks propagate to descendants and update
ancestor mixed states.
Settings panel demonstrates activation, functional toggles/selects,
disabled categories, depth indentation via CSS variable, and recursive
rendering. Removes file-explorer and selection live examples.
…rops

Also fix generate-api.ts to extract @example tags in the ts-morph
fallback path used by components with external types files.
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Mar 4, 2026

Open in StackBlitz

commit: 920bd35

@johnleider johnleider changed the title feat(Treeview): add compound treeview component feat(Treeview): add new component Mar 5, 2026
Create reusable useRovingFocus composable for roving tabindex pattern
with linear and grid navigation modes. Wire into Treeview for full
WAI-ARIA tree keyboard nav: arrows, Home/End, Enter, Space, *.

- useRovingFocus: manages focusedId, isTabbable, step with disabled
  skip, optional circular nav, orientation + grid (columns) support
- createNested: add el to NestedTicket, add visibleItems() for
  depth-first traversal of open nodes
- TreeviewList: creates roving focus, handles all tree keyboard
  mappings including ArrowRight/Left for expand/collapse/parent
- TreeviewItem: captures el ref, consumes roving for tabindex
- TreeviewActivator/Checkbox: remove independent tabindex (now -1),
  keyboard handling moved to tree container level
Add renderless Treeview.Checkbox with cascade selection to the basic
example. Demonstrates keyboard Space to toggle selection alongside
arrow key navigation and Enter to expand/collapse.
…sable

- Enter key activates focused node (leaf nodes now keyboard-reachable)
- Space key no-op in single-select mode per WAI-ARIA spec
- SelectAll onClick/onKeydown in attrs for renderless mode support
- revealOnOpen runs after open strategy to fix single+reveal combo
- Remove String(ticket.id) coercion; use ID type throughout
- unselectAll with mandatory recalculates ancestor mixed states
- Move TreeviewRoot imports to regular script (dual-script convention)
- disabled prop typed as MaybeRefOrGetter for consistency
- siblings() uses rootIds set for root nodes
- Fix duplicate describe names in createNested tests
@johnleider johnleider force-pushed the master branch 5 times, most recently from a6133f0 to eb8ed41 Compare March 17, 2026 02:24
Resolve useRovingFocus conflict by taking master's RTL support.
ArrowRight/ArrowLeft tree semantics (open/close, focus parent/child)
now swap in RTL layouts, matching the useRovingFocus RTL support
added in master.
- Space key toggles selection in single-select mode per WAI-ARIA spec
- Unwrap NestedContext.multiple with toValue to match boolean type
- Use isNullOrUndefined type guard in TreeviewList keyboard handler
- Fix orphaned JSDoc on NestedActiveMode (belongs on NestedOptions)
- Remove stale comment headers in createNested
# Conflicts:
#	packages/0/src/composables/createNested/index.ts
#	playground/src/components.d.ts
Replace try/catch optional context injection with null defaults
(matching Snackbar precedent). Add named context type exports
(TreeviewRootContext, TreeviewListContext, TreeviewItemContext)
matching Select/Button/Snackbar conventions. Move TreeviewItemContext
from types.ts to TreeviewItem.vue where the createContext call lives.
Add non-null assertions on useTreeviewItem() in 5 sub-components
after context type changed to | null. Add KeepAlive lifecycle hooks
(onDeactivated/onActivated) to TreeviewContent for hasContent state.
Add 21 tests covering keyboard navigation (ArrowUp/Down/Left/Right,
Home, End, *), selection modes (cascade, independent, leaf), open
modes (single), 3-level nesting, expandAll/collapseAll, and Cue
and Indicator component states.
RegistryTicket requires an unregister method. The mock ticket in
TreeviewSelectAll was missing it, causing a CI typecheck failure.
Add 15 tests covering: SelectAll keyboard handling (Enter/Space/
disabled), mixed/indeterminate state (Checkbox aria-checked, Indicator
data-state), Activator role attributes on non-button elements, Cue
visibility on leaf nodes, Item active state (data-active), Indicator
visibility toggle, Checkbox mixed data-mixed, and Item without List.
Add tests for ArrowUp navigation, ArrowRight→child focus on open
parent, onFocusin sync handler, non-treeitem focusin guard, and
Content unmount lifecycle. Closes remaining coverable line gaps.
@johnleider johnleider self-assigned this Mar 24, 2026
@johnleider johnleider added this to the v0.2.0 milestone Mar 24, 2026
@johnleider johnleider merged commit 4937a35 into master Mar 24, 2026
13 of 15 checks passed
@johnleider johnleider deleted the feat/treeview branch March 24, 2026 19:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant