/** * createTree - the HEADLESS core behind , in the same spirit as * `createSvGrid` for the grid: a runes-based state machine (expand/collapse, * single-select highlight, cascading tri-state checkboxes, full keyboard) with * **prop-getters** you spread onto YOUR OWN markup. The visible tree is * flattened into `rows` so roving-focus keyboard nav stays a flat index walk. * * ```svelte * *
* {#each tree.rows as row (row.node.id)} *
{row.node.label}
* {/each} *
* ``` * * The styled is just one renderer over this core. The cascade math * (`treeDescendantIds`, `treeCheckState`) is exported as pure functions. */ export type TreeNode = { id: string; label: string; children?: TreeNode[]; disabled?: boolean; /** Marks a node whose children are loaded on demand (shows an expand arrow * even with no children yet; the renderer loads them on first expand). */ lazy?: boolean; }; export type CheckState = 'checked' | 'indeterminate' | 'unchecked'; /** A single visible (flattened) tree row. */ export type TreeRow = { node: TreeNode; depth: number; hasChildren: boolean; open: boolean; parentId: string | null; index: number; }; /** All descendant ids of `node` (pure, depth-first). */ export declare function treeDescendantIds(node: TreeNode): string[]; /** Tri-state check status of `node` given the set of checked ids (pure). */ export declare function treeCheckState(node: TreeNode, checked: ReadonlySet): CheckState; /** Where a dragged node lands relative to the drop target. */ export type TreeDropPosition = 'before' | 'after' | 'inside'; /** True if `id` is inside `node`'s subtree (used to block invalid drops). */ export declare function treeContains(node: TreeNode, id: string): boolean; /** * Return a NEW node tree with `dragId` moved before/after/inside `targetId` * (pure - the caller sets it back as the controlled `nodes`). No-ops on invalid * moves (self, or into own descendant). */ export declare function moveTreeNode(nodes: ReadonlyArray, dragId: string, targetId: string, position: TreeDropPosition): TreeNode[]; /** Sort siblings (recursively) by a comparator (pure). */ export declare function sortTreeNodes(nodes: ReadonlyArray, compare: (a: TreeNode, b: TreeNode) => number): TreeNode[]; /** Reactive inputs are passed as getters so the core tracks live prop changes. */ export type TreeConfig = { nodes: () => ReadonlyArray; selected?: () => string | null; onSelect?: (id: string) => void; /** Seed the internally-managed expanded set (read once). */ expandedIds?: () => string[] | undefined; onToggle?: (id: string, expanded: boolean) => void; checkable?: () => boolean; checked?: () => string[]; onCheck?: (ids: string[]) => void; ariaLabel?: () => string | undefined; /** Text direction; under `'rtl'` the Left/Right expand/collapse keys swap. */ dir?: () => import('./editor-contract').EditorDir | undefined; /** Filter query: show only matching nodes + their ancestors, auto-expanded. */ filter?: () => string | undefined; }; export declare function createTree(config: TreeConfig): { /** Internally-managed set of expanded node ids. */ readonly expanded: Set; /** Selected node id (single-select highlight). */ readonly selected: string | null; /** Flattened list of visible rows. */ readonly rows: TreeRow[]; /** Roving-focus row index. */ readonly activeIndex: number; /** Monotonic counter; changes only on keyboard navigation. */ readonly focusTick: number; isExpanded: (id: string) => boolean; isSelected: (id: string) => boolean; checkStateOf: (node: TreeNode) => CheckState; toggle: (id: string) => void; toggleExpand: (node: TreeNode) => void; select: (id: string) => void; toggleCheck: (node: TreeNode) => void; setActive: (i: number, focus?: boolean) => void; onKeydown: (e: KeyboardEvent) => void; /** Spread onto the tree container element. */ treeProps: () => { role: "tree"; 'aria-label': string | undefined; 'aria-multiselectable': boolean; }; /** Spread onto the treeitem element for a flattened `row`. */ itemProps: (row: TreeRow) => { role: "treeitem"; 'aria-level': number; 'aria-selected': boolean; 'aria-expanded': boolean | undefined; 'aria-checked': "true" | "mixed" | "false" | undefined; 'aria-disabled': true | undefined; 'data-row': number; tabindex: number; onclick: () => void; onkeydown: (e: KeyboardEvent) => void; }; }; export type Tree = ReturnType;