You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/src/uix/soma/components/tree-view/README.md

218 lines
16 KiB

# TreeView
soma: gesture layer, drawer component, full audit fixes across 26 components Gesture Layer: - Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking - VelocityTracker with ring buffer, staleness check, projection - 52 tests (velocity + gesture integration) - setPointerCapture deferred until moveBuffer exceeded (prevents click stealing) Drawer Component: - 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close - Gesture.drag() integration for swipe dismiss - Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle - Modal/non-modal/non-dismissible modes - Logical directions (start/end) RTL-aware via soma presentation - CSS custom properties (--drawer-progress, --drawer-offset-x/y) Architecture: - T1: 219 files migrated from $soma/ alias to relative paths - T2: 35 wrappers — noop replaced with () => {} inline - Translation system: componentLangs + common.buttons.* + idlangref constants - COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns - contracts.ts: case-normalized registerContract/assertContract Audit Fixes (P0 critical): - DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super - TB1: data-table attr on wrapper - CH1/SW1/NF4: hidden input rendering fixes - SP2: panel cleanup on unmount - RG1: roving tabindex fallback to first item - CO1: aria-labelledby on collapsible content Audit Fixes (P1 high): - SafePolygon integrated in dropdown-menu SubProvider + tooltip - 9 langs.ts files with idlangref constants - Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards - Stepper: count decrement + private, aria-label on List - ToggleGroup: roving tabindex in multiple mode - Select: pure aria-activedescendant (no mixed focus), label registry - NumberField: startValue respects min, scrubber commit on pointerup only - Toolbar: element-based focus tracking (not index) Audit Fixes (P2 medium): - A6: timer/listener cleanup in 6 components - A12: getDirectionalKeys in 4 components - A10: DOM queries scoped to root in 3 components - Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern - Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup - Pagination: reactive page clamping, Set-based computePageRange - Scroll-area: thumbSize zero-guard, mount flash prevention - Splitter: collapse/expand respects adjacent constraints, immediate pointer capture 5 issues remain (design decisions): stepper registry, table sub-row IDs, tags-input ARIA model, tags-input paste, toast exit animation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
A hierarchical tree structure with expandable branches and selectable items. Implements the full WAI-ARIA TreeView keyboard pattern including typeahead, expand-all-siblings (\*), and nested navigation.
## Anatomy
```svelte
<TreeView.Provider bind:expandedValue bind:selectedValue>
soma: gesture layer, drawer component, full audit fixes across 26 components Gesture Layer: - Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking - VelocityTracker with ring buffer, staleness check, projection - 52 tests (velocity + gesture integration) - setPointerCapture deferred until moveBuffer exceeded (prevents click stealing) Drawer Component: - 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close - Gesture.drag() integration for swipe dismiss - Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle - Modal/non-modal/non-dismissible modes - Logical directions (start/end) RTL-aware via soma presentation - CSS custom properties (--drawer-progress, --drawer-offset-x/y) Architecture: - T1: 219 files migrated from $soma/ alias to relative paths - T2: 35 wrappers — noop replaced with () => {} inline - Translation system: componentLangs + common.buttons.* + idlangref constants - COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns - contracts.ts: case-normalized registerContract/assertContract Audit Fixes (P0 critical): - DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super - TB1: data-table attr on wrapper - CH1/SW1/NF4: hidden input rendering fixes - SP2: panel cleanup on unmount - RG1: roving tabindex fallback to first item - CO1: aria-labelledby on collapsible content Audit Fixes (P1 high): - SafePolygon integrated in dropdown-menu SubProvider + tooltip - 9 langs.ts files with idlangref constants - Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards - Stepper: count decrement + private, aria-label on List - ToggleGroup: roving tabindex in multiple mode - Select: pure aria-activedescendant (no mixed focus), label registry - NumberField: startValue respects min, scrubber commit on pointerup only - Toolbar: element-based focus tracking (not index) Audit Fixes (P2 medium): - A6: timer/listener cleanup in 6 components - A12: getDirectionalKeys in 4 components - A10: DOM queries scoped to root in 3 components - Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern - Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup - Pagination: reactive page clamping, Set-based computePageRange - Scroll-area: thumbSize zero-guard, mount flash prevention - Splitter: collapse/expand respects adjacent constraints, immediate pointer capture 5 issues remain (design decisions): stepper registry, table sub-row IDs, tags-input ARIA model, tags-input paste, toast exit animation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
<TreeView.Branch value="docs" depth={0}>
<TreeView.BranchControl>
<TreeView.BranchIndicator>▶</TreeView.BranchIndicator>
<TreeView.Label>Documents</TreeView.Label>
</TreeView.BranchControl>
<TreeView.BranchContent>
<TreeView.Item value="readme" depth={1}>README.md</TreeView.Item>
<TreeView.Item value="license" depth={1}>LICENSE</TreeView.Item>
<TreeView.Branch value="src" depth={1}>
<TreeView.BranchControl>
<TreeView.BranchIndicator>▶</TreeView.BranchIndicator>
<TreeView.Label>src</TreeView.Label>
</TreeView.BranchControl>
<TreeView.BranchContent>
<TreeView.Item value="index" depth={2}>index.ts</TreeView.Item>
</TreeView.BranchContent>
</TreeView.Branch>
</TreeView.BranchContent>
</TreeView.Branch>
</TreeView.Provider>
```
Branches can nest arbitrarily deep. Leaf items use `Item`, expandable folders use `Branch`.
## Parts
soma: gesture layer, drawer component, full audit fixes across 26 components Gesture Layer: - Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking - VelocityTracker with ring buffer, staleness check, projection - 52 tests (velocity + gesture integration) - setPointerCapture deferred until moveBuffer exceeded (prevents click stealing) Drawer Component: - 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close - Gesture.drag() integration for swipe dismiss - Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle - Modal/non-modal/non-dismissible modes - Logical directions (start/end) RTL-aware via soma presentation - CSS custom properties (--drawer-progress, --drawer-offset-x/y) Architecture: - T1: 219 files migrated from $soma/ alias to relative paths - T2: 35 wrappers — noop replaced with () => {} inline - Translation system: componentLangs + common.buttons.* + idlangref constants - COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns - contracts.ts: case-normalized registerContract/assertContract Audit Fixes (P0 critical): - DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super - TB1: data-table attr on wrapper - CH1/SW1/NF4: hidden input rendering fixes - SP2: panel cleanup on unmount - RG1: roving tabindex fallback to first item - CO1: aria-labelledby on collapsible content Audit Fixes (P1 high): - SafePolygon integrated in dropdown-menu SubProvider + tooltip - 9 langs.ts files with idlangref constants - Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards - Stepper: count decrement + private, aria-label on List - ToggleGroup: roving tabindex in multiple mode - Select: pure aria-activedescendant (no mixed focus), label registry - NumberField: startValue respects min, scrubber commit on pointerup only - Toolbar: element-based focus tracking (not index) Audit Fixes (P2 medium): - A6: timer/listener cleanup in 6 components - A12: getDirectionalKeys in 4 components - A10: DOM queries scoped to root in 3 components - Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern - Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup - Pagination: reactive page clamping, Set-based computePageRange - Scroll-area: thumbSize zero-guard, mount flash prevention - Splitter: collapse/expand respects adjacent constraints, immediate pointer capture 5 issues remain (design decisions): stepper registry, table sub-row IDs, tags-input ARIA model, tags-input paste, toast exit animation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
| Part | Element | Description |
| ------------------- | ------- | -------------------------------------------------------------------------- |
| `Provider` | `<div>` | Root container. `role="tree"`. Manages expand/select state, keyboard. |
| `Branch` | `<div>` | Expandable node. Contains BranchControl + BranchContent. |
| `BranchControl` | `<div>` | Clickable row for a branch. `role="treeitem"`. Handles selection + expand. |
| `BranchContent` | `<div>` | Children container. `role="group"`. Hidden when collapsed. |
| `BranchIndicator` | `<div>` | Expand/collapse icon (e.g. arrow). Clicking toggles expand. Decorative. |
| `BranchIndentGuide` | `<div>` | Visual indent line. Decorative (`aria-hidden`). |
| `Item` | `<div>` | Leaf node. `role="treeitem"`. Selectable. |
| `Label` | `<div>` | Text label for branch or item. |
## ARIA
soma: gesture layer, drawer component, full audit fixes across 26 components Gesture Layer: - Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking - VelocityTracker with ring buffer, staleness check, projection - 52 tests (velocity + gesture integration) - setPointerCapture deferred until moveBuffer exceeded (prevents click stealing) Drawer Component: - 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close - Gesture.drag() integration for swipe dismiss - Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle - Modal/non-modal/non-dismissible modes - Logical directions (start/end) RTL-aware via soma presentation - CSS custom properties (--drawer-progress, --drawer-offset-x/y) Architecture: - T1: 219 files migrated from $soma/ alias to relative paths - T2: 35 wrappers — noop replaced with () => {} inline - Translation system: componentLangs + common.buttons.* + idlangref constants - COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns - contracts.ts: case-normalized registerContract/assertContract Audit Fixes (P0 critical): - DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super - TB1: data-table attr on wrapper - CH1/SW1/NF4: hidden input rendering fixes - SP2: panel cleanup on unmount - RG1: roving tabindex fallback to first item - CO1: aria-labelledby on collapsible content Audit Fixes (P1 high): - SafePolygon integrated in dropdown-menu SubProvider + tooltip - 9 langs.ts files with idlangref constants - Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards - Stepper: count decrement + private, aria-label on List - ToggleGroup: roving tabindex in multiple mode - Select: pure aria-activedescendant (no mixed focus), label registry - NumberField: startValue respects min, scrubber commit on pointerup only - Toolbar: element-based focus tracking (not index) Audit Fixes (P2 medium): - A6: timer/listener cleanup in 6 components - A12: getDirectionalKeys in 4 components - A10: DOM queries scoped to root in 3 components - Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern - Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup - Pagination: reactive page clamping, Set-based computePageRange - Scroll-area: thumbSize zero-guard, mount flash prevention - Splitter: collapse/expand respects adjacent constraints, immediate pointer capture 5 issues remain (design decisions): stepper registry, table sub-row IDs, tags-input ARIA model, tags-input paste, toast exit animation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
| Part | Attribute | Value |
| ----------------- | ---------------------- | -------------------------------------- |
| Provider | `role` | `tree` |
| Provider | `aria-multiselectable` | `true` (when selectionMode='multiple') |
| Provider | `aria-label` | Configurable (default "Tree") |
| BranchControl | `role` | `treeitem` |
| BranchControl | `aria-expanded` | `true` \| `false` |
| BranchControl | `aria-selected` | `true` \| `false` |
| BranchControl | `aria-level` | Depth + 1 (1-based) |
| BranchControl | `aria-disabled` | `true` (when disabled) |
| BranchContent | `role` | `group` |
| Item | `role` | `treeitem` |
| Item | `aria-selected` | `true` \| `false` |
| Item | `aria-level` | Depth + 1 (1-based) |
| Item | `aria-disabled` | `true` (when disabled) |
| BranchIndicator | `aria-hidden` | `true` |
| BranchIndentGuide | `aria-hidden` | `true` |
## Data Attributes
soma: gesture layer, drawer component, full audit fixes across 26 components Gesture Layer: - Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking - VelocityTracker with ring buffer, staleness check, projection - 52 tests (velocity + gesture integration) - setPointerCapture deferred until moveBuffer exceeded (prevents click stealing) Drawer Component: - 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close - Gesture.drag() integration for swipe dismiss - Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle - Modal/non-modal/non-dismissible modes - Logical directions (start/end) RTL-aware via soma presentation - CSS custom properties (--drawer-progress, --drawer-offset-x/y) Architecture: - T1: 219 files migrated from $soma/ alias to relative paths - T2: 35 wrappers — noop replaced with () => {} inline - Translation system: componentLangs + common.buttons.* + idlangref constants - COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns - contracts.ts: case-normalized registerContract/assertContract Audit Fixes (P0 critical): - DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super - TB1: data-table attr on wrapper - CH1/SW1/NF4: hidden input rendering fixes - SP2: panel cleanup on unmount - RG1: roving tabindex fallback to first item - CO1: aria-labelledby on collapsible content Audit Fixes (P1 high): - SafePolygon integrated in dropdown-menu SubProvider + tooltip - 9 langs.ts files with idlangref constants - Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards - Stepper: count decrement + private, aria-label on List - ToggleGroup: roving tabindex in multiple mode - Select: pure aria-activedescendant (no mixed focus), label registry - NumberField: startValue respects min, scrubber commit on pointerup only - Toolbar: element-based focus tracking (not index) Audit Fixes (P2 medium): - A6: timer/listener cleanup in 6 components - A12: getDirectionalKeys in 4 components - A10: DOM queries scoped to root in 3 components - Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern - Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup - Pagination: reactive page clamping, Set-based computePageRange - Scroll-area: thumbSize zero-guard, mount flash prevention - Splitter: collapse/expand respects adjacent constraints, immediate pointer capture 5 issues remain (design decisions): stepper registry, table sub-row IDs, tags-input ARIA model, tags-input paste, toast exit animation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
| Part | Attribute | Values |
| ----------------- | ------------------------------------ | ----------------------- |
| Provider | `data-tree-view` | Always present |
| Branch | `data-tree-view-branch` | Always present |
| Branch | `data-value` | Branch value string |
| Branch | `data-state` | `open` \| `closed` |
| Branch | `data-selected` | Present when selected |
| Branch | `data-disabled` | Present when disabled |
| Branch | `data-depth` | Nesting depth (0-based) |
| BranchControl | `data-tree-view-branch-control` | Always present |
| BranchControl | `data-value` | Branch value |
| BranchControl | `data-state` | `open` \| `closed` |
| BranchControl | `data-selected` | Present when selected |
| BranchControl | `data-disabled` | Present when disabled |
| BranchControl | `data-depth` | Nesting depth |
| BranchContent | `data-tree-view-branch-content` | Always present |
| BranchContent | `data-state` | `open` \| `closed` |
| BranchContent | `data-depth` | Nesting depth |
| BranchIndicator | `data-tree-view-branch-indicator` | Always present |
| BranchIndicator | `data-state` | `open` \| `closed` |
| BranchIndentGuide | `data-tree-view-branch-indent-guide` | Always present |
| BranchIndentGuide | `data-depth` | Nesting depth |
| Item | `data-tree-view-item` | Always present |
| Item | `data-value` | Item value string |
| Item | `data-selected` | Present when selected |
| Item | `data-disabled` | Present when disabled |
| Item | `data-depth` | Nesting depth |
## CSS Variables
soma: gesture layer, drawer component, full audit fixes across 26 components Gesture Layer: - Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking - VelocityTracker with ring buffer, staleness check, projection - 52 tests (velocity + gesture integration) - setPointerCapture deferred until moveBuffer exceeded (prevents click stealing) Drawer Component: - 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close - Gesture.drag() integration for swipe dismiss - Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle - Modal/non-modal/non-dismissible modes - Logical directions (start/end) RTL-aware via soma presentation - CSS custom properties (--drawer-progress, --drawer-offset-x/y) Architecture: - T1: 219 files migrated from $soma/ alias to relative paths - T2: 35 wrappers — noop replaced with () => {} inline - Translation system: componentLangs + common.buttons.* + idlangref constants - COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns - contracts.ts: case-normalized registerContract/assertContract Audit Fixes (P0 critical): - DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super - TB1: data-table attr on wrapper - CH1/SW1/NF4: hidden input rendering fixes - SP2: panel cleanup on unmount - RG1: roving tabindex fallback to first item - CO1: aria-labelledby on collapsible content Audit Fixes (P1 high): - SafePolygon integrated in dropdown-menu SubProvider + tooltip - 9 langs.ts files with idlangref constants - Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards - Stepper: count decrement + private, aria-label on List - ToggleGroup: roving tabindex in multiple mode - Select: pure aria-activedescendant (no mixed focus), label registry - NumberField: startValue respects min, scrubber commit on pointerup only - Toolbar: element-based focus tracking (not index) Audit Fixes (P2 medium): - A6: timer/listener cleanup in 6 components - A12: getDirectionalKeys in 4 components - A10: DOM queries scoped to root in 3 components - Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern - Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup - Pagination: reactive page clamping, Set-based computePageRange - Scroll-area: thumbSize zero-guard, mount flash prevention - Splitter: collapse/expand respects adjacent constraints, immediate pointer capture 5 issues remain (design decisions): stepper registry, table sub-row IDs, tags-input ARIA model, tags-input paste, toast exit animation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
| Variable | Part | Description |
| ------------------- | ------------ | ------------------------------------------------------------------------------------------------- |
| `--soma-tree-depth` | Branch, Item | Nesting depth (0-based). Use for indentation: `padding-left: calc(var(--soma-tree-depth) * 1rem)` |
## Keyboard
soma: gesture layer, drawer component, full audit fixes across 26 components Gesture Layer: - Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking - VelocityTracker with ring buffer, staleness check, projection - 52 tests (velocity + gesture integration) - setPointerCapture deferred until moveBuffer exceeded (prevents click stealing) Drawer Component: - 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close - Gesture.drag() integration for swipe dismiss - Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle - Modal/non-modal/non-dismissible modes - Logical directions (start/end) RTL-aware via soma presentation - CSS custom properties (--drawer-progress, --drawer-offset-x/y) Architecture: - T1: 219 files migrated from $soma/ alias to relative paths - T2: 35 wrappers — noop replaced with () => {} inline - Translation system: componentLangs + common.buttons.* + idlangref constants - COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns - contracts.ts: case-normalized registerContract/assertContract Audit Fixes (P0 critical): - DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super - TB1: data-table attr on wrapper - CH1/SW1/NF4: hidden input rendering fixes - SP2: panel cleanup on unmount - RG1: roving tabindex fallback to first item - CO1: aria-labelledby on collapsible content Audit Fixes (P1 high): - SafePolygon integrated in dropdown-menu SubProvider + tooltip - 9 langs.ts files with idlangref constants - Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards - Stepper: count decrement + private, aria-label on List - ToggleGroup: roving tabindex in multiple mode - Select: pure aria-activedescendant (no mixed focus), label registry - NumberField: startValue respects min, scrubber commit on pointerup only - Toolbar: element-based focus tracking (not index) Audit Fixes (P2 medium): - A6: timer/listener cleanup in 6 components - A12: getDirectionalKeys in 4 components - A10: DOM queries scoped to root in 3 components - Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern - Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup - Pagination: reactive page clamping, Set-based computePageRange - Scroll-area: thumbSize zero-guard, mount flash prevention - Splitter: collapse/expand respects adjacent constraints, immediate pointer capture 5 issues remain (design decisions): stepper registry, table sub-row IDs, tags-input ARIA model, tags-input paste, toast exit animation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
| Key | Action |
| ----------------- | ---------------------------------------------------------------- |
| `ArrowDown` | Move focus to next visible item |
| `ArrowUp` | Move focus to previous visible item |
| `ArrowRight` | Expand a collapsed branch, or move to first child if expanded |
| `ArrowLeft` | Collapse an expanded branch, or move to parent if leaf/collapsed |
| `Home` | Move focus to first item |
| `End` | Move focus to last visible item |
| `Enter` / `Space` | Select/deselect the focused item |
| `*` | Expand all siblings of the focused item |
| Character keys | Typeahead — focus first matching item by text content |
## Behavior
### Expand/collapse
soma: gesture layer, drawer component, full audit fixes across 26 components Gesture Layer: - Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking - VelocityTracker with ring buffer, staleness check, projection - 52 tests (velocity + gesture integration) - setPointerCapture deferred until moveBuffer exceeded (prevents click stealing) Drawer Component: - 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close - Gesture.drag() integration for swipe dismiss - Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle - Modal/non-modal/non-dismissible modes - Logical directions (start/end) RTL-aware via soma presentation - CSS custom properties (--drawer-progress, --drawer-offset-x/y) Architecture: - T1: 219 files migrated from $soma/ alias to relative paths - T2: 35 wrappers — noop replaced with () => {} inline - Translation system: componentLangs + common.buttons.* + idlangref constants - COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns - contracts.ts: case-normalized registerContract/assertContract Audit Fixes (P0 critical): - DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super - TB1: data-table attr on wrapper - CH1/SW1/NF4: hidden input rendering fixes - SP2: panel cleanup on unmount - RG1: roving tabindex fallback to first item - CO1: aria-labelledby on collapsible content Audit Fixes (P1 high): - SafePolygon integrated in dropdown-menu SubProvider + tooltip - 9 langs.ts files with idlangref constants - Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards - Stepper: count decrement + private, aria-label on List - ToggleGroup: roving tabindex in multiple mode - Select: pure aria-activedescendant (no mixed focus), label registry - NumberField: startValue respects min, scrubber commit on pointerup only - Toolbar: element-based focus tracking (not index) Audit Fixes (P2 medium): - A6: timer/listener cleanup in 6 components - A12: getDirectionalKeys in 4 components - A10: DOM queries scoped to root in 3 components - Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern - Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup - Pagination: reactive page clamping, Set-based computePageRange - Scroll-area: thumbSize zero-guard, mount flash prevention - Splitter: collapse/expand respects adjacent constraints, immediate pointer capture 5 issues remain (design decisions): stepper registry, table sub-row IDs, tags-input ARIA model, tags-input paste, toast exit animation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
Branches expand/collapse via:
soma: gesture layer, drawer component, full audit fixes across 26 components Gesture Layer: - Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking - VelocityTracker with ring buffer, staleness check, projection - 52 tests (velocity + gesture integration) - setPointerCapture deferred until moveBuffer exceeded (prevents click stealing) Drawer Component: - 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close - Gesture.drag() integration for swipe dismiss - Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle - Modal/non-modal/non-dismissible modes - Logical directions (start/end) RTL-aware via soma presentation - CSS custom properties (--drawer-progress, --drawer-offset-x/y) Architecture: - T1: 219 files migrated from $soma/ alias to relative paths - T2: 35 wrappers — noop replaced with () => {} inline - Translation system: componentLangs + common.buttons.* + idlangref constants - COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns - contracts.ts: case-normalized registerContract/assertContract Audit Fixes (P0 critical): - DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super - TB1: data-table attr on wrapper - CH1/SW1/NF4: hidden input rendering fixes - SP2: panel cleanup on unmount - RG1: roving tabindex fallback to first item - CO1: aria-labelledby on collapsible content Audit Fixes (P1 high): - SafePolygon integrated in dropdown-menu SubProvider + tooltip - 9 langs.ts files with idlangref constants - Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards - Stepper: count decrement + private, aria-label on List - ToggleGroup: roving tabindex in multiple mode - Select: pure aria-activedescendant (no mixed focus), label registry - NumberField: startValue respects min, scrubber commit on pointerup only - Toolbar: element-based focus tracking (not index) Audit Fixes (P2 medium): - A6: timer/listener cleanup in 6 components - A12: getDirectionalKeys in 4 components - A10: DOM queries scoped to root in 3 components - Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern - Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup - Pagination: reactive page clamping, Set-based computePageRange - Scroll-area: thumbSize zero-guard, mount flash prevention - Splitter: collapse/expand respects adjacent constraints, immediate pointer capture 5 issues remain (design decisions): stepper registry, table sub-row IDs, tags-input ARIA model, tags-input paste, toast exit animation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
- Arrow Right/Left keys
- Clicking the BranchIndicator
- Clicking BranchControl (when `expandOnClick` is true, default)
- `*` key to expand all siblings at the same level
### Selection
soma: gesture layer, drawer component, full audit fixes across 26 components Gesture Layer: - Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking - VelocityTracker with ring buffer, staleness check, projection - 52 tests (velocity + gesture integration) - setPointerCapture deferred until moveBuffer exceeded (prevents click stealing) Drawer Component: - 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close - Gesture.drag() integration for swipe dismiss - Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle - Modal/non-modal/non-dismissible modes - Logical directions (start/end) RTL-aware via soma presentation - CSS custom properties (--drawer-progress, --drawer-offset-x/y) Architecture: - T1: 219 files migrated from $soma/ alias to relative paths - T2: 35 wrappers — noop replaced with () => {} inline - Translation system: componentLangs + common.buttons.* + idlangref constants - COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns - contracts.ts: case-normalized registerContract/assertContract Audit Fixes (P0 critical): - DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super - TB1: data-table attr on wrapper - CH1/SW1/NF4: hidden input rendering fixes - SP2: panel cleanup on unmount - RG1: roving tabindex fallback to first item - CO1: aria-labelledby on collapsible content Audit Fixes (P1 high): - SafePolygon integrated in dropdown-menu SubProvider + tooltip - 9 langs.ts files with idlangref constants - Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards - Stepper: count decrement + private, aria-label on List - ToggleGroup: roving tabindex in multiple mode - Select: pure aria-activedescendant (no mixed focus), label registry - NumberField: startValue respects min, scrubber commit on pointerup only - Toolbar: element-based focus tracking (not index) Audit Fixes (P2 medium): - A6: timer/listener cleanup in 6 components - A12: getDirectionalKeys in 4 components - A10: DOM queries scoped to root in 3 components - Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern - Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup - Pagination: reactive page clamping, Set-based computePageRange - Scroll-area: thumbSize zero-guard, mount flash prevention - Splitter: collapse/expand respects adjacent constraints, immediate pointer capture 5 issues remain (design decisions): stepper registry, table sub-row IDs, tags-input ARIA model, tags-input paste, toast exit animation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
- `single` mode: one item selected at a time (clicking a new item deselects the previous)
- `multiple` mode: clicking toggles individual selection
### Typeahead
soma: gesture layer, drawer component, full audit fixes across 26 components Gesture Layer: - Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking - VelocityTracker with ring buffer, staleness check, projection - 52 tests (velocity + gesture integration) - setPointerCapture deferred until moveBuffer exceeded (prevents click stealing) Drawer Component: - 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close - Gesture.drag() integration for swipe dismiss - Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle - Modal/non-modal/non-dismissible modes - Logical directions (start/end) RTL-aware via soma presentation - CSS custom properties (--drawer-progress, --drawer-offset-x/y) Architecture: - T1: 219 files migrated from $soma/ alias to relative paths - T2: 35 wrappers — noop replaced with () => {} inline - Translation system: componentLangs + common.buttons.* + idlangref constants - COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns - contracts.ts: case-normalized registerContract/assertContract Audit Fixes (P0 critical): - DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super - TB1: data-table attr on wrapper - CH1/SW1/NF4: hidden input rendering fixes - SP2: panel cleanup on unmount - RG1: roving tabindex fallback to first item - CO1: aria-labelledby on collapsible content Audit Fixes (P1 high): - SafePolygon integrated in dropdown-menu SubProvider + tooltip - 9 langs.ts files with idlangref constants - Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards - Stepper: count decrement + private, aria-label on List - ToggleGroup: roving tabindex in multiple mode - Select: pure aria-activedescendant (no mixed focus), label registry - NumberField: startValue respects min, scrubber commit on pointerup only - Toolbar: element-based focus tracking (not index) Audit Fixes (P2 medium): - A6: timer/listener cleanup in 6 components - A12: getDirectionalKeys in 4 components - A10: DOM queries scoped to root in 3 components - Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern - Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup - Pagination: reactive page clamping, Set-based computePageRange - Scroll-area: thumbSize zero-guard, mount flash prevention - Splitter: collapse/expand respects adjacent constraints, immediate pointer capture 5 issues remain (design decisions): stepper registry, table sub-row IDs, tags-input ARIA model, tags-input paste, toast exit animation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
When `typeahead` is true (default), typing characters focuses the first visible item whose text starts with the typed string. Buffer clears after 500ms of inactivity.
### Depth tracking
soma: gesture layer, drawer component, full audit fixes across 26 components Gesture Layer: - Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking - VelocityTracker with ring buffer, staleness check, projection - 52 tests (velocity + gesture integration) - setPointerCapture deferred until moveBuffer exceeded (prevents click stealing) Drawer Component: - 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close - Gesture.drag() integration for swipe dismiss - Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle - Modal/non-modal/non-dismissible modes - Logical directions (start/end) RTL-aware via soma presentation - CSS custom properties (--drawer-progress, --drawer-offset-x/y) Architecture: - T1: 219 files migrated from $soma/ alias to relative paths - T2: 35 wrappers — noop replaced with () => {} inline - Translation system: componentLangs + common.buttons.* + idlangref constants - COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns - contracts.ts: case-normalized registerContract/assertContract Audit Fixes (P0 critical): - DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super - TB1: data-table attr on wrapper - CH1/SW1/NF4: hidden input rendering fixes - SP2: panel cleanup on unmount - RG1: roving tabindex fallback to first item - CO1: aria-labelledby on collapsible content Audit Fixes (P1 high): - SafePolygon integrated in dropdown-menu SubProvider + tooltip - 9 langs.ts files with idlangref constants - Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards - Stepper: count decrement + private, aria-label on List - ToggleGroup: roving tabindex in multiple mode - Select: pure aria-activedescendant (no mixed focus), label registry - NumberField: startValue respects min, scrubber commit on pointerup only - Toolbar: element-based focus tracking (not index) Audit Fixes (P2 medium): - A6: timer/listener cleanup in 6 components - A12: getDirectionalKeys in 4 components - A10: DOM queries scoped to root in 3 components - Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern - Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup - Pagination: reactive page clamping, Set-based computePageRange - Scroll-area: thumbSize zero-guard, mount flash prevention - Splitter: collapse/expand respects adjacent constraints, immediate pointer capture 5 issues remain (design decisions): stepper registry, table sub-row IDs, tags-input ARIA model, tags-input paste, toast exit animation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
Each Branch and Item receives a `depth` prop (0-based). This becomes:
soma: gesture layer, drawer component, full audit fixes across 26 components Gesture Layer: - Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking - VelocityTracker with ring buffer, staleness check, projection - 52 tests (velocity + gesture integration) - setPointerCapture deferred until moveBuffer exceeded (prevents click stealing) Drawer Component: - 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close - Gesture.drag() integration for swipe dismiss - Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle - Modal/non-modal/non-dismissible modes - Logical directions (start/end) RTL-aware via soma presentation - CSS custom properties (--drawer-progress, --drawer-offset-x/y) Architecture: - T1: 219 files migrated from $soma/ alias to relative paths - T2: 35 wrappers — noop replaced with () => {} inline - Translation system: componentLangs + common.buttons.* + idlangref constants - COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns - contracts.ts: case-normalized registerContract/assertContract Audit Fixes (P0 critical): - DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super - TB1: data-table attr on wrapper - CH1/SW1/NF4: hidden input rendering fixes - SP2: panel cleanup on unmount - RG1: roving tabindex fallback to first item - CO1: aria-labelledby on collapsible content Audit Fixes (P1 high): - SafePolygon integrated in dropdown-menu SubProvider + tooltip - 9 langs.ts files with idlangref constants - Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards - Stepper: count decrement + private, aria-label on List - ToggleGroup: roving tabindex in multiple mode - Select: pure aria-activedescendant (no mixed focus), label registry - NumberField: startValue respects min, scrubber commit on pointerup only - Toolbar: element-based focus tracking (not index) Audit Fixes (P2 medium): - A6: timer/listener cleanup in 6 components - A12: getDirectionalKeys in 4 components - A10: DOM queries scoped to root in 3 components - Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern - Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup - Pagination: reactive page clamping, Set-based computePageRange - Scroll-area: thumbSize zero-guard, mount flash prevention - Splitter: collapse/expand respects adjacent constraints, immediate pointer capture 5 issues remain (design decisions): stepper registry, table sub-row IDs, tags-input ARIA model, tags-input paste, toast exit animation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
- `aria-level` (1-based, as required by ARIA spec)
- `data-depth` attribute
- `--soma-tree-depth` CSS variable for indentation
## Usage
### Basic file tree
```svelte
<script>
soma: gesture layer, drawer component, full audit fixes across 26 components Gesture Layer: - Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking - VelocityTracker with ring buffer, staleness check, projection - 52 tests (velocity + gesture integration) - setPointerCapture deferred until moveBuffer exceeded (prevents click stealing) Drawer Component: - 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close - Gesture.drag() integration for swipe dismiss - Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle - Modal/non-modal/non-dismissible modes - Logical directions (start/end) RTL-aware via soma presentation - CSS custom properties (--drawer-progress, --drawer-offset-x/y) Architecture: - T1: 219 files migrated from $soma/ alias to relative paths - T2: 35 wrappers — noop replaced with () => {} inline - Translation system: componentLangs + common.buttons.* + idlangref constants - COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns - contracts.ts: case-normalized registerContract/assertContract Audit Fixes (P0 critical): - DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super - TB1: data-table attr on wrapper - CH1/SW1/NF4: hidden input rendering fixes - SP2: panel cleanup on unmount - RG1: roving tabindex fallback to first item - CO1: aria-labelledby on collapsible content Audit Fixes (P1 high): - SafePolygon integrated in dropdown-menu SubProvider + tooltip - 9 langs.ts files with idlangref constants - Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards - Stepper: count decrement + private, aria-label on List - ToggleGroup: roving tabindex in multiple mode - Select: pure aria-activedescendant (no mixed focus), label registry - NumberField: startValue respects min, scrubber commit on pointerup only - Toolbar: element-based focus tracking (not index) Audit Fixes (P2 medium): - A6: timer/listener cleanup in 6 components - A12: getDirectionalKeys in 4 components - A10: DOM queries scoped to root in 3 components - Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern - Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup - Pagination: reactive page clamping, Set-based computePageRange - Scroll-area: thumbSize zero-guard, mount flash prevention - Splitter: collapse/expand respects adjacent constraints, immediate pointer capture 5 issues remain (design decisions): stepper registry, table sub-row IDs, tags-input ARIA model, tags-input paste, toast exit animation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
import { TreeView } from '$soma/components';
soma: gesture layer, drawer component, full audit fixes across 26 components Gesture Layer: - Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking - VelocityTracker with ring buffer, staleness check, projection - 52 tests (velocity + gesture integration) - setPointerCapture deferred until moveBuffer exceeded (prevents click stealing) Drawer Component: - 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close - Gesture.drag() integration for swipe dismiss - Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle - Modal/non-modal/non-dismissible modes - Logical directions (start/end) RTL-aware via soma presentation - CSS custom properties (--drawer-progress, --drawer-offset-x/y) Architecture: - T1: 219 files migrated from $soma/ alias to relative paths - T2: 35 wrappers — noop replaced with () => {} inline - Translation system: componentLangs + common.buttons.* + idlangref constants - COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns - contracts.ts: case-normalized registerContract/assertContract Audit Fixes (P0 critical): - DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super - TB1: data-table attr on wrapper - CH1/SW1/NF4: hidden input rendering fixes - SP2: panel cleanup on unmount - RG1: roving tabindex fallback to first item - CO1: aria-labelledby on collapsible content Audit Fixes (P1 high): - SafePolygon integrated in dropdown-menu SubProvider + tooltip - 9 langs.ts files with idlangref constants - Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards - Stepper: count decrement + private, aria-label on List - ToggleGroup: roving tabindex in multiple mode - Select: pure aria-activedescendant (no mixed focus), label registry - NumberField: startValue respects min, scrubber commit on pointerup only - Toolbar: element-based focus tracking (not index) Audit Fixes (P2 medium): - A6: timer/listener cleanup in 6 components - A12: getDirectionalKeys in 4 components - A10: DOM queries scoped to root in 3 components - Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern - Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup - Pagination: reactive page clamping, Set-based computePageRange - Scroll-area: thumbSize zero-guard, mount flash prevention - Splitter: collapse/expand respects adjacent constraints, immediate pointer capture 5 issues remain (design decisions): stepper registry, table sub-row IDs, tags-input ARIA model, tags-input paste, toast exit animation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
let expanded = $state(['src']);
let selected = $state<string[]>([]);
</script>
<TreeView.Provider bind:expandedValue={expanded} bind:selectedValue={selected}>
soma: gesture layer, drawer component, full audit fixes across 26 components Gesture Layer: - Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking - VelocityTracker with ring buffer, staleness check, projection - 52 tests (velocity + gesture integration) - setPointerCapture deferred until moveBuffer exceeded (prevents click stealing) Drawer Component: - 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close - Gesture.drag() integration for swipe dismiss - Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle - Modal/non-modal/non-dismissible modes - Logical directions (start/end) RTL-aware via soma presentation - CSS custom properties (--drawer-progress, --drawer-offset-x/y) Architecture: - T1: 219 files migrated from $soma/ alias to relative paths - T2: 35 wrappers — noop replaced with () => {} inline - Translation system: componentLangs + common.buttons.* + idlangref constants - COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns - contracts.ts: case-normalized registerContract/assertContract Audit Fixes (P0 critical): - DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super - TB1: data-table attr on wrapper - CH1/SW1/NF4: hidden input rendering fixes - SP2: panel cleanup on unmount - RG1: roving tabindex fallback to first item - CO1: aria-labelledby on collapsible content Audit Fixes (P1 high): - SafePolygon integrated in dropdown-menu SubProvider + tooltip - 9 langs.ts files with idlangref constants - Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards - Stepper: count decrement + private, aria-label on List - ToggleGroup: roving tabindex in multiple mode - Select: pure aria-activedescendant (no mixed focus), label registry - NumberField: startValue respects min, scrubber commit on pointerup only - Toolbar: element-based focus tracking (not index) Audit Fixes (P2 medium): - A6: timer/listener cleanup in 6 components - A12: getDirectionalKeys in 4 components - A10: DOM queries scoped to root in 3 components - Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern - Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup - Pagination: reactive page clamping, Set-based computePageRange - Scroll-area: thumbSize zero-guard, mount flash prevention - Splitter: collapse/expand respects adjacent constraints, immediate pointer capture 5 issues remain (design decisions): stepper registry, table sub-row IDs, tags-input ARIA model, tags-input paste, toast exit animation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
<TreeView.Item value="readme" depth={0}>README.md</TreeView.Item>
<TreeView.Branch value="src" depth={0}>
<TreeView.BranchControl>
<TreeView.BranchIndicator>▶</TreeView.BranchIndicator>
src
</TreeView.BranchControl>
<TreeView.BranchContent>
<TreeView.Item value="index" depth={1}>index.ts</TreeView.Item>
<TreeView.Item value="app" depth={1}>App.svelte</TreeView.Item>
</TreeView.BranchContent>
</TreeView.Branch>
</TreeView.Provider>
```
### Multiple selection
```svelte
<TreeView.Provider selectionMode="multiple" bind:selectedValue>
soma: gesture layer, drawer component, full audit fixes across 26 components Gesture Layer: - Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking - VelocityTracker with ring buffer, staleness check, projection - 52 tests (velocity + gesture integration) - setPointerCapture deferred until moveBuffer exceeded (prevents click stealing) Drawer Component: - 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close - Gesture.drag() integration for swipe dismiss - Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle - Modal/non-modal/non-dismissible modes - Logical directions (start/end) RTL-aware via soma presentation - CSS custom properties (--drawer-progress, --drawer-offset-x/y) Architecture: - T1: 219 files migrated from $soma/ alias to relative paths - T2: 35 wrappers — noop replaced with () => {} inline - Translation system: componentLangs + common.buttons.* + idlangref constants - COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns - contracts.ts: case-normalized registerContract/assertContract Audit Fixes (P0 critical): - DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super - TB1: data-table attr on wrapper - CH1/SW1/NF4: hidden input rendering fixes - SP2: panel cleanup on unmount - RG1: roving tabindex fallback to first item - CO1: aria-labelledby on collapsible content Audit Fixes (P1 high): - SafePolygon integrated in dropdown-menu SubProvider + tooltip - 9 langs.ts files with idlangref constants - Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards - Stepper: count decrement + private, aria-label on List - ToggleGroup: roving tabindex in multiple mode - Select: pure aria-activedescendant (no mixed focus), label registry - NumberField: startValue respects min, scrubber commit on pointerup only - Toolbar: element-based focus tracking (not index) Audit Fixes (P2 medium): - A6: timer/listener cleanup in 6 components - A12: getDirectionalKeys in 4 components - A10: DOM queries scoped to root in 3 components - Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern - Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup - Pagination: reactive page clamping, Set-based computePageRange - Scroll-area: thumbSize zero-guard, mount flash prevention - Splitter: collapse/expand respects adjacent constraints, immediate pointer capture 5 issues remain (design decisions): stepper registry, table sub-row IDs, tags-input ARIA model, tags-input paste, toast exit animation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
<!-- Multiple items can be selected -->
</TreeView.Provider>
```
### Indentation via CSS variable
```css
[data-tree-view-branch-control],
[data-tree-view-item] {
soma: gesture layer, drawer component, full audit fixes across 26 components Gesture Layer: - Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking - VelocityTracker with ring buffer, staleness check, projection - 52 tests (velocity + gesture integration) - setPointerCapture deferred until moveBuffer exceeded (prevents click stealing) Drawer Component: - 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close - Gesture.drag() integration for swipe dismiss - Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle - Modal/non-modal/non-dismissible modes - Logical directions (start/end) RTL-aware via soma presentation - CSS custom properties (--drawer-progress, --drawer-offset-x/y) Architecture: - T1: 219 files migrated from $soma/ alias to relative paths - T2: 35 wrappers — noop replaced with () => {} inline - Translation system: componentLangs + common.buttons.* + idlangref constants - COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns - contracts.ts: case-normalized registerContract/assertContract Audit Fixes (P0 critical): - DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super - TB1: data-table attr on wrapper - CH1/SW1/NF4: hidden input rendering fixes - SP2: panel cleanup on unmount - RG1: roving tabindex fallback to first item - CO1: aria-labelledby on collapsible content Audit Fixes (P1 high): - SafePolygon integrated in dropdown-menu SubProvider + tooltip - 9 langs.ts files with idlangref constants - Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards - Stepper: count decrement + private, aria-label on List - ToggleGroup: roving tabindex in multiple mode - Select: pure aria-activedescendant (no mixed focus), label registry - NumberField: startValue respects min, scrubber commit on pointerup only - Toolbar: element-based focus tracking (not index) Audit Fixes (P2 medium): - A6: timer/listener cleanup in 6 components - A12: getDirectionalKeys in 4 components - A10: DOM queries scoped to root in 3 components - Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern - Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup - Pagination: reactive page clamping, Set-based computePageRange - Scroll-area: thumbSize zero-guard, mount flash prevention - Splitter: collapse/expand respects adjacent constraints, immediate pointer capture 5 issues remain (design decisions): stepper registry, table sub-row IDs, tags-input ARIA model, tags-input paste, toast exit animation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
padding-left: calc(var(--soma-tree-depth) * 1.5rem + 0.5rem);
}
```
## Comparison with reference libraries
soma: gesture layer, drawer component, full audit fixes across 26 components Gesture Layer: - Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking - VelocityTracker with ring buffer, staleness check, projection - 52 tests (velocity + gesture integration) - setPointerCapture deferred until moveBuffer exceeded (prevents click stealing) Drawer Component: - 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close - Gesture.drag() integration for swipe dismiss - Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle - Modal/non-modal/non-dismissible modes - Logical directions (start/end) RTL-aware via soma presentation - CSS custom properties (--drawer-progress, --drawer-offset-x/y) Architecture: - T1: 219 files migrated from $soma/ alias to relative paths - T2: 35 wrappers — noop replaced with () => {} inline - Translation system: componentLangs + common.buttons.* + idlangref constants - COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns - contracts.ts: case-normalized registerContract/assertContract Audit Fixes (P0 critical): - DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super - TB1: data-table attr on wrapper - CH1/SW1/NF4: hidden input rendering fixes - SP2: panel cleanup on unmount - RG1: roving tabindex fallback to first item - CO1: aria-labelledby on collapsible content Audit Fixes (P1 high): - SafePolygon integrated in dropdown-menu SubProvider + tooltip - 9 langs.ts files with idlangref constants - Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards - Stepper: count decrement + private, aria-label on List - ToggleGroup: roving tabindex in multiple mode - Select: pure aria-activedescendant (no mixed focus), label registry - NumberField: startValue respects min, scrubber commit on pointerup only - Toolbar: element-based focus tracking (not index) Audit Fixes (P2 medium): - A6: timer/listener cleanup in 6 components - A12: getDirectionalKeys in 4 components - A10: DOM queries scoped to root in 3 components - Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern - Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup - Pagination: reactive page clamping, Set-based computePageRange - Scroll-area: thumbSize zero-guard, mount flash prevention - Splitter: collapse/expand respects adjacent constraints, immediate pointer capture 5 issues remain (design decisions): stepper registry, table sub-row IDs, tags-input ARIA model, tags-input paste, toast exit animation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 months ago
| Feature | Ark UI | Radix Vue | React Aria | Soma |
| --------------------------------- | ------------------------------------------------------------------------------------------- | ----------------- | ----------------- | ----------------------------------------------------------------------------------------------- |
| Parts | Root, Branch, BranchControl, BranchContent, BranchIndicator, BranchIndentGuide, Item, Label | Root, Item (flat) | Tree, TreeItem | Provider, Branch, BranchControl, BranchContent, BranchIndicator, BranchIndentGuide, Item, Label |
| Selection single/multiple | Yes | Yes | Yes | Yes |
| `role="tree"` / `role="treeitem"` | Yes | Yes | Yes | Yes |
| `aria-expanded` | Yes | Yes | Yes | Yes |
| `aria-selected` | Yes | Yes | Yes | Yes |
| `aria-level` | Yes | Yes | No (CSS var) | Yes |
| `aria-setsize` / `aria-posinset` | Yes | Yes | Yes | No (consumer can add) |
| Arrow Up/Down navigate | Yes | Yes | Yes | Yes |
| Arrow Right expand / first child | Yes | Yes | Yes | Yes |
| Arrow Left collapse / parent | Yes | Yes | Yes | Yes |
| Home/End | Yes | Yes | Yes | Yes |
| `*` expand all siblings | Yes | No | No | Yes |
| Typeahead | Yes | No | No | Yes |
| `--depth` CSS variable | Yes | data-indent | --tree-item-level | Yes (`--soma-tree-depth`) |
| `data-state` open/closed | Yes | Yes | No | Yes |
| `data-selected` | Yes | Yes | No | Yes |
| `data-depth` | No | Yes (data-indent) | No | Yes |
| `expandOnClick` | Yes | No | No | Yes |
| `dir` (RTL) | Yes | Yes | No | Yes |
| BranchIndentGuide | Yes | No | No | Yes |
| Inline renaming | Yes (F2) | No | No | No (future) |
| Async child loading | Yes | No | No | No (future) |
| Drag & drop | No | No | Yes | No (future) |
| Checkbox mode | Yes | No | No | No (future) |

Powered by TurnKey Linux.