import * as _h_k_dev_angular_tree from '@h-k-dev/angular-tree'; import * as _angular_core from '@angular/core'; import { InjectionToken, Signal, TemplateRef, Injector, TrackByFunction } from '@angular/core'; import * as i1$1 from '@angular/cdk/drag-drop'; import { CdkDragMove } from '@angular/cdk/drag-drop'; import { Observable } from 'rxjs'; import * as i1 from '@angular/cdk/menu'; /** * Intent event payloads (Phase 0 contract, see ROADMAP.md). The tree is * controlled: it never mutates consumer data — it emits these intents and the * consumer applies them. */ /** Emitted when a drop completes. Consumer moves the nodes in its own data. */ interface MoveEvent { /** Plural by contract: multi-drag-ready even if v1 ships single-drag. */ readonly dragIds: readonly string[]; readonly dragNodes: readonly T[]; /** `null` = root level. */ readonly parentId: string | null; readonly parentNode: T | null; /** * Insertion index into the target parent's children *as they currently * are* — dragged nodes are still present. Remove them first, adjusting the * index for any removed sibling that sat before it (react-arborist * convention, ROADMAP settled 2026-07-05). */ readonly index: number; /** * `'copy'` when the platform copy modifier was held at drop time (⌥ on * macOS, Ctrl elsewhere — the OS file-manager convention) or the keyboard * move was armed with Ctrl/Cmd+C instead of Ctrl/Cmd+X. The consumer * duplicates instead of moving; `index` semantics are unchanged (v2, * ROADMAP2 settled 2026-07-06). */ readonly dropEffect: 'move' | 'copy'; } /** Emitted when inline editing commits. Consumer renames in its own data. */ interface RenameEvent { readonly id: string; readonly node: T; readonly name: string; } /** * Why a {@link SelectEvent} write occurred — the reason for the write, not * the physical input device. Every path through context-menu preparation * (right-click, Shift+F10 / ContextMenu key, `openContextMenu()`) reports * `'contextmenu'`, so preview-pane consumers can ignore reconciliation: * `if (event.trigger && event.cause !== 'contextmenu') …`. */ type SelectCause = 'pointer' | 'keyboard' | 'contextmenu'; /** * Emitted on every selection interaction (checkbox or ctrl/shift semantics). * Fires even when the resulting set is unchanged — re-clicking the already * selected row under `clickAction="select"` still identifies itself via * `trigger` (`added`/`removed` empty), so "active row" consumers (preview * panes) can refocus without guessing from the set. * * External `[(selectedKeys)]` writes update state but never emit — only * tree-initiated interactions produce a {@link SelectEvent}. */ interface SelectEvent { readonly ids: readonly string[]; readonly nodes: readonly T[]; /** * The row whose interaction caused this write — present for row-addressed * gestures (click, Shift/Ctrl-click, checkbox, Space, `'follow'`-mode focus * moves, right-click reconciliation; ranges report the row the gesture * ended on). Absent for set-level operations: Ctrl/Cmd+A and the Escape / * outside-click clears. */ readonly trigger?: T; /** * Why this write occurred. Always present on tree-emitted events (including * set-level clears where `trigger` is absent). `'contextmenu'` covers every * selection reconciliation that precedes a menu open — not only the pointer * right-click path. */ readonly cause: SelectCause; /** Keys that entered the set with this write (empty on a no-op re-click). */ readonly added: readonly string[]; /** Keys that left the set with this write. */ readonly removed: readonly string[]; } /** Emitted when a node expands or collapses. */ interface ToggleEvent { readonly id: string; readonly node: T; readonly expanded: boolean; } /** * Notification of an async `childrenAccessor` resolution — loading is driven * by the accessor itself (ROADMAP settled: no separate `loadChildren` output); * this only reports the outcome so consumers can react (telemetry, toasts). */ interface LoadChildrenEvent { readonly id: string; readonly node: T; readonly status: 'loaded' | 'error'; /** Present when `status` is `'error'`; pair with `tree.retryChildren(node)`. */ readonly error?: unknown; } /** * Screen-reader messages for the tree's polite live region (v2, ROADMAP2 * Phase 9 — announced via CDK `LiveAnnouncer`, no DOM shipped). Every field * is optional: omitted fields fall back to terse English defaults; pass the * whole input as `null` to silence the tree entirely. Returning `''` from a * field suppresses just that announcement. */ interface TreeAnnouncements { /** After a completed move/copy (pointer or keyboard). */ moved?: (event: MoveEvent) => string; /** After an async `childrenAccessor` resolves or fails. */ childrenLoaded?: (event: LoadChildrenEvent) => string; /** When the search term or its match count changes (term non-empty). */ searchResults?: (count: number, term: string) => string; /** After Escape clears the selection — a mass deselect is otherwise silent. */ selectionCleared?: () => string; } /** * Emitted on right-click / ContextMenu key / Shift+F10 (Phase 7). Selection * has already been reconciled per OS convention when this fires. */ interface ContextRequestedEvent { /** The full selection the menu should act on. */ readonly ids: readonly string[]; /** The row that was invoked. */ readonly node: T; /** Viewport coordinates for overlay positioning. */ readonly position: { readonly x: number; readonly y: number; }; } /** Tri-state of a row under `checkboxSelection` (ARIA checkbox-tree pattern). */ type CheckState = 'checked' | 'unchecked' | 'indeterminate'; /** * Template context for `treeNodeDef`. `S` narrows to the union member matched * by a type-guard `when` predicate (Phase 0 spike, see ROADMAP.md). */ interface TreeNodeContext { $implicit: S; /** The node's `expansionKey` — parity with PrimeNG/jsTree templates (v2). */ key: string; /** Zero-based depth in the flattened model. */ level: number; /** Whether the node reports children via `childrenAccessor`. */ expandable: boolean; isExpanded: boolean; /** Index within the visible flat array. */ index: number; /** Row is in the selection set (checkbox or ctrl/shift semantics). */ isSelected: boolean; /** Row is being renamed — consumer renders its input (tree owns state only). */ isEditing: boolean; /** Async `childrenAccessor` in flight for this node. */ isLoading: boolean; /** Async `childrenAccessor` rejected — pair with `tree.retryChildren(node)`. */ hasError: boolean; /** * Tri-state under `checkboxSelection` — drives the icon-as-checkbox swap * (icon while `'unchecked'`, checkbox visual otherwise) in consumer templates. */ checkState: CheckState; } /** * Per-row handle injected into node content (e.g. `treeNodeToggle`). * Row-scoped counterpart to the tree-level `TreeApi`. */ interface TreeNodeHandle { readonly expandable: boolean; /** Per-row signals: equality stops propagation — DOM updates stay O(visible). */ readonly isSelected: Signal; readonly checkState: Signal; toggle(): void; /** * Cascades over the loaded subtree when `checkboxSelection` is on. * `range = true` (Shift+checkbox, v2): additive range from the selection * anchor over visible order instead of a toggle. */ toggleSelection(range?: boolean): void; /** Starts inline rename (respects `disableEdit`) — the row-scoped `edit()`. */ beginEdit(): void; /** Ends editing and emits the `renamed` intent (no-op unless editing). */ commitEdit(name: string): void; /** Ends editing without emitting. */ cancelEdit(): void; } /** DI token providing the row's {@link TreeNodeHandle} to content directives. */ declare const TREE_NODE: InjectionToken; /** * Accessor contracts (Material `CdkTree` pattern — no forced node shape). * An async return (`Promise`/`Observable`) marks the node lazy: the tree sets * `isLoading` in the row context until it resolves (ROADMAP Phase 3). * * **Remote children: return a COLD `Observable` (`defer`), not a `Promise`.** * The tree also *probes* the accessor while flattening — once per loaded node, * expanded or not — just to learn expandability. A `Promise` starts its fetch * at probe time (one request per visible branch before any expand); an * `Observable` is only subscribed on expand intent, so probing stays free. * * Cancellation (v2) is opt-in by declaring the second parameter: accessors * written as `(node, signal) => fetch(url, { signal })` get an `AbortSignal` * the tree aborts on destroy and on `invalidateChildren` while in flight * (incl. collapse under `collapseBehavior: 'invalidate'`). Single-parameter * accessors are detected via `Function.length` and skip the allocation — * note that default/rest parameters reduce `length` and would opt out too. */ type TreeChildrenAccessor = (node: T, signal?: AbortSignal) => readonly T[] | null | undefined | Promise | Observable; type TreeExpansionKey = (node: T) => string; /** Argument to the `disableDrop` predicate (Phase 4 three-zone drop math). */ interface TreeDropContext { readonly dragNodes: readonly T[]; /** `null` = root level. */ readonly parentNode: T | null; readonly index: number; } /** Purely visual drop marker — never reorders DOM mid-drag (ROADMAP Phase 4). */ interface DropIndicator { /** Viewport-relative px (the indicator overlays the viewport, not the content). */ readonly top: number; readonly height: number; readonly inside: boolean; readonly level: number; } /** A guide clamped to the rendered range, in content-wrapper px. Internal. */ interface GuideOverlay { readonly key: string; readonly level: number; readonly top: number; readonly height: number; /** True when the group's real end is rendered — the elbow may draw. */ readonly elbow: boolean; } /** What a `treeContextMenu` template receives — act on `ids`, branch on the node. */ interface TreeContextMenuContext { /** The clicked / focused node. */ $implicit: T; /** Alias of `$implicit` for `let-node="node"` readers. */ node: T; /** Post-reconciliation selection as nodes — what the menu should act on. */ nodes: readonly T[]; /** …the same selection as keys. */ ids: readonly string[]; /** Where the menu opened (pointer, or the focused row's rect for keyboard). */ position: { x: number; y: number; }; } /** * Declares the tree's built-in context menu content (ROADMAP settled * 2026-07-06): the consumer projects menu *items*; the tree owns the * mechanics — trigger, positioning, keyboard access, close-on-scroll, and a * `cdkMenu` shell wrapping this template (so `cdkMenuItem` children get menu * keyboard navigation for free). * * ```html * * @switch (node.kind) { … } * * ``` */ declare class TreeContextMenu { readonly template: TemplateRef>; static ngTemplateContextGuard(_directive: TreeContextMenu, context: unknown): context is TreeContextMenuContext; static ɵfac: _angular_core.ɵɵFactoryDeclaration, never>; static ɵdir: _angular_core.ɵɵDirectiveDeclaration, "ng-template[treeContextMenu]", never, {}, {}, never, never, true, never>; } /** One entry of the visible flat render array. Internal. */ interface FlatRow { readonly node: T; readonly key: string; readonly level: number; readonly expandable: boolean; readonly setSize: number; readonly posInSet: number; /** Roving tabindex: 0 on the (effective) focused row, -1 elsewhere. */ readonly tabIndex: Signal; /** Row is marked by Ctrl+X, awaiting a keyboard drop. */ readonly moveSource: Signal; /** Tri-state for `aria-checked` under `checkboxSelection`. */ readonly checkState: Signal<'checked' | 'unchecked' | 'indeterminate'>; readonly dragDisabled: boolean; readonly context: TreeNodeContext; readonly injector: Injector; } /** * Virtualized tree. Consumer data stays untouched — `childrenAccessor` + * `expansionKey` describe it (Material `CdkTree` pattern). Rendering is a flat * virtual list (react-arborist internals); all state lives in the internal * `TreeController` (one source of truth, no event bubbling). See ROADMAP.md. */ declare class AngularTree { #private; /** Roots of the nested consumer data. The consumer owns it (controlled). */ readonly dataSource: _angular_core.InputSignal; /** Returns a node's children; `null`/`undefined` marks a leaf, async = lazy. */ readonly childrenAccessor: _angular_core.InputSignal>; /** Stable string key per node — expansion, trackBy, DOM marking. */ readonly expansionKey: _angular_core.InputSignal>; /** Fixed row height in px — required for virtualization. */ readonly itemSize: _angular_core.InputSignal; /** Keys expanded on first render; inert while `[expandedKeys]` is bound. */ readonly defaultExpandedKeys: _angular_core.InputSignal; /** * Controlled expansion over node keys (v2, Phase 15 — supersedes the * `expandedKeys()` snapshot method). Unbound (`undefined`) = the tree owns * expansion state (seeded by `defaultExpandedKeys`). Bound: external value * changes replace the expansion set (set-equality guarded — write-backs * never echo) and `defaultExpandedKeys` is inert; every tree-initiated * expansion write (toggle, expandAll/collapseAll, expandDescendants, * setExpanded) updates the model → `(expandedKeysChange)`. `(toggled)` * stays the per-node intent; this is the whole-set state channel. * * A key naming a lazy, not-yet-loaded node counts as load intent (decision * 14): the reconciler runs the accessor exactly as a toggle would, so * restores and external writes never render aria-expanded over nothing. */ expandedKeys: _angular_core.ModelSignal; /** Initial roving-tabindex target (v2) — unknown keys fall back to row 1. */ readonly defaultFocusedKey: _angular_core.InputSignal; /** * What collapse does to a lazy node's resolved children (v2): `'keep'` * reuses them on re-expand; `'invalidate'` marks them stale and aborts an * in-flight load — the next expand shows the stale children immediately * while the accessor re-runs and swaps them (decision 15). */ readonly collapseBehavior: _angular_core.InputSignal<"keep" | "invalidate">; /** * Declarative children-cache invalidation (v2, Phase 15 — mirrors * `resource({ params })`): bind the parameters your `childrenAccessor` * reads (filters, refs, locale). Whenever the value changes (reference * equality, like any input), the tree behaves exactly like * `invalidateChildren()` — resolved children go stale (kept on screen * until their replacement resolves, decision 15), in-flight loads abort, * expanded nodes re-run the accessor now, collapsed ones on their next * expand — so a cached child list can never outlive the parameters it was * fetched with. The tree still never fetches; it only re-asks YOUR accessor. */ readonly childrenDeps: _angular_core.InputSignal; /** * Controlled selection over node keys (v2, Phase 15). Unbound * (`undefined`) = the tree owns selection state internally. Bound: * external value changes replace the selection (set-equality guarded, so * writing our own emission back never echoes); tree interactions — which * the tree drives, only it knows the visible flat order — update the model * → `(selectedKeysChange)`. `[(selectedKeys)]` shares state; one-way * `[selectedKeys]` + write-back is the strictly controlled shape. */ selectedKeys: _angular_core.ModelSignal; /** Multi-selection (naming aligned with `@angular/aria/tree`). */ readonly multi: _angular_core.InputSignal; /** * Clear the selection when the user clicks outside any row — empty viewport * space or outside the tree (file-manager semantics). Clicks inside CDK * overlays (context menu, dialogs) never clear: their actions operate ON * the selection. Turn off when a toolbar outside the tree acts on the * selection, or manage clearing yourself. */ readonly deselectOnOutsideClick: _angular_core.InputSignal; /** Cascade checkbox semantics over *loaded* nodes (ROADMAP settled). */ readonly checkboxSelection: _angular_core.InputSignal; /** Matching child keeps its ancestor chain visible (react-arborist behavior). */ readonly searchTerm: _angular_core.InputSignal; /** Required for search — `T` has no shape to match against (ROADMAP settled). */ readonly searchMatch: _angular_core.InputSignal<((node: T, term: string) => boolean) | undefined>; /** Required for type-ahead — same rationale as `searchMatch`; inert without it. */ readonly typeaheadText: _angular_core.InputSignal<((node: T) => string) | undefined>; /** What Enter does on the focused row. */ readonly enterAction: _angular_core.InputSignal<"activate" | "edit">; /** * Accessible name for the `role="tree"` element (APG: a tree MUST be * labelled). Forwarded to the internal viewport — the role doesn't sit on * the host, so a plain host attribute would be invisible to AT. Prefer * `aria-labelledby` pointing at a visible heading; `aria-label` otherwise. */ readonly ariaLabel: _angular_core.InputSignal; /** id of a visible element labelling the tree — wins over `aria-label`. */ readonly ariaLabelledby: _angular_core.InputSignal; /** * What a plain row click does (v2, reopened v1 lock — ROADMAP2 decisions * table). `'activate'` (default, v1 behavior): click activates, selection * only via checkbox/Ctrl/Shift. `'select'`: file-manager semantics — click * replaces the selection with the row, double-click activates. Ctrl/Shift * power shortcuts are identical in both modes. */ readonly clickAction: _angular_core.InputSignal<"select" | "activate">; /** * Screen-reader messages for moves, lazy-load outcomes, and search result * counts (v2) — announced politely via CDK `LiveAnnouncer`, so the tree * ships no live-region DOM. Omitted = terse English defaults; partial * objects override per message; `null` silences everything. */ readonly announcements: _angular_core.InputSignal | null | undefined>; /** `'follow'` = selection tracks focus (aria alignment); default explicit. */ readonly selectionMode: _angular_core.InputSignal<"explicit" | "follow">; /** * `'activedescendant'` keeps DOM focus on the tree and points * `aria-activedescendant` at the focused row — the virtualization-friendly * mode (no focus loss when the focused row's DOM is recycled). */ readonly focusMode: _angular_core.InputSignal<"roving" | "activedescendant">; /** One guide line per ancestor level; clicking a guide collapses that group. */ readonly indentGuides: _angular_core.InputSignal; /** * How rows behave when a nowrap label outgrows the viewport. Under `'scroll'` * (default) the scroll content grows to the widest row — CDK's content * wrapper shrink-wraps, its `min-width: 100%` is only a floor — so the tree * scrolls horizontally and a consumer `text-overflow: ellipsis` never * engages (the label never meets an edge). `'ellipsis'` caps rows at the * visible viewport width so consumer label truncation works; horizontal * scrolling is gone in that mode, so deep trees with wide rows should stay * on `'scroll'`. The label CSS itself (`overflow: hidden; text-overflow: * ellipsis; white-space: nowrap; min-inline-size: 0`) is the consumer's. */ readonly labelOverflow: _angular_core.InputSignal<"scroll" | "ellipsis">; /** * Root-level load in flight — shows the projected `treeLoadingDef` over the * tree. Consumer-driven (the data is controlled); distinct from a lazy * *child* load, which drives per-row `isLoading`. */ readonly loading: _angular_core.InputSignal; /** * Per-node classes for the tree-owned row element (v2, Phase 15 — accessor * -shaped like the behavior predicates). Def content renders *inside* the * row, so consumer templates can't reach it; this can. Row element only — * never the guide overlays (a row-designed class would wreck them). */ readonly rowClass: _angular_core.InputSignal<((node: T) => string | readonly string[] | undefined) | undefined>; /** * Per-node inline styles for the row element (v2, Phase 15) — the custom- * property hook: `--tree-*` chains resolve at point of use, so returning * e.g. `{ '--tree-guide': node.color }` retunes tokens per node. The GROUP * PARENT's result is additionally applied to that group's indent-guide * overlay — guides are siblings of rows, not children, so row-applied * variables can never reach them on their own. `height` stays the tree's * (fixed-row virtualization is a locked contract). */ readonly rowStyle: _angular_core.InputSignal<((node: T) => Record | undefined) | undefined>; readonly disableDrag: _angular_core.InputSignal<((node: T) => boolean) | undefined>; readonly disableDrop: _angular_core.InputSignal<((ctx: TreeDropContext) => boolean) | undefined>; readonly disableEdit: _angular_core.InputSignal<((node: T) => boolean) | undefined>; readonly isSelectable: _angular_core.InputSignal<((node: T) => boolean) | undefined>; /** Plain row click = activate; never mutates selection (Gmail semantics). */ readonly activated: _angular_core.OutputEmitterRef; /** Drop completed (Phase 4). */ readonly moved: _angular_core.OutputEmitterRef>; /** Inline edit committed (Phase 3). */ readonly renamed: _angular_core.OutputEmitterRef>; /** Selection set changed through tree interaction. */ readonly selectionChange: _angular_core.OutputEmitterRef>; /** Node expanded or collapsed. */ readonly toggled: _angular_core.OutputEmitterRef>; /** Async `childrenAccessor` resolved or rejected (Phase 3). */ readonly childrenLoaded: _angular_core.OutputEmitterRef>; /** Right-click / ContextMenu key / Shift+F10 (Phase 7). */ readonly contextRequested: _angular_core.OutputEmitterRef>; private readonly defs; private readonly viewport; protected readonly contextMenuDef: Signal | undefined>; private readonly contextMenuShell; private readonly emptyDef; private readonly loadingDef; /** Context handed to the projected treeContextMenu template. */ protected readonly contextMenuContext: Signal<_h_k_dev_angular_tree.TreeContextMenuContext | null>; /** Gmail-style icon↔checkbox swap driver — reactive via the bridged mirror. */ readonly selectionActive: Signal; protected readonly dragStartDelay: { mouse: number; touch: number; }; protected readonly dragCount: Signal; protected readonly dropIndicator: Signal; protected rowId(key: string): string; protected readonly activeDescendantId: Signal; constructor(); /** The 1D array actually rendered — built from the controller's walk. */ readonly visibleRows: Signal[]>; readonly trackByKey: TrackByFunction>; /** * The empty/loading overlay content, or `null` for neither. Loading wins * over empty (a root load in flight shouldn't flash "no items"); each shows * only when its def is projected. */ protected readonly stateTemplate: Signal | null>; /** * `'activate'` (default): plain click activates, never mutates selection — * Gmail. `'select'` (v2 opt-in): plain click replaces the selection — * file manager; activation moves to double-click. Ctrl/Cmd+click toggles, * Shift+click range-selects over visible order in both modes (power-user * shortcuts, ROADMAP settled). */ protected onRowClick(row: FlatRow, event: MouseEvent): void; /** * Activation gesture under `clickAction: 'select'` — inert otherwise so * double-click stays entirely the consumer's (v1 rename-gesture decision). */ protected onRowDoubleClick(row: FlatRow): void; /** Guides clamped to the rendered range, in content-wrapper px (see template). */ protected readonly guideOverlays: Signal; /** A guide click collapses — and focuses — the group's expanded parent. */ protected onGuideClick(parentKey: string): void; /** * Right-click contract (OS convention, ROADMAP Phase 7): an unselected row * is selected first (replace); a row inside a multi-selection keeps the * selection intact. With a projected treeContextMenu the tree owns the * trigger, so it suppresses the browser menu on rows — but never inside * inputs (a rename field keeps its paste menu). Without a def, suppression * stays the consumer trigger's job (the tree never assumes a menu exists). */ protected onContextMenu(row: FlatRow, event: MouseEvent): void; /** Focus bookkeeping lives in the engine (tree-focus-engine.ts). */ protected onFocusIn(event: FocusEvent): void; protected onFocusOut(event: FocusEvent): void; /** * One handler over the whole viewport (controller-driven focus — ROADMAP * Phase 3 decision): works for targets virtualization hasn't rendered. * The key map itself is the pure `interpretTreeKey` (tree-keyboard.ts); * this is only the exhaustive dispatch. */ protected onKeydown(event: KeyboardEvent): void; protected previewLabel(node: T): string; protected onDragStart(row: FlatRow): void; protected onDragMove(event: CdkDragMove): void; protected onDragEnd(): void; /** First def whose `when` matches wins; a def without `when` is the fallback. */ templateFor(row: FlatRow): TemplateRef>; isExpanded(node: T): boolean; expand(node: T): void; collapse(node: T): void; toggle(node: T): void; /** Expands `node` and every (sync-loaded) descendant beneath it. */ expandDescendants(node: T): void; /** * Expands every loaded node. `loadLazy` (v2, opt-in — a 100k lazy tree * must never fetch-storm by accident): additionally resolves unloaded lazy * subtrees in batched frontier waves, expanding each wave as it lands; * per-load `childrenLoaded` events fire as usual. Nodes in `error` state * are left alone — `retryChildren` stays the explicit recovery path. */ expandAll(options?: { loadLazy?: boolean; }): void; collapseAll(): void; /** Bulk-set for unbound trees; a bound `[(expandedKeys)]` covers this reactively. */ setExpanded(keys: Iterable): void; /** * Starts inline rename; the consumer renders the input (`isEditing` context). * The tree ships NO rename gesture — wire this to your own trigger (a * keybinding on the tree element, a context-menu item, a row button, …). * Respects `disableEdit`. */ edit(node: T): void; focus(node: T): void; scrollTo(node: T): void; /** * Opens the projected `treeContextMenu` anchored to the node's row — the * `more_vert` row-button pattern. No-op when the node isn't visible or no * def is projected. */ openContextMenu(node: T): void; /** Re-runs a failed async `childrenAccessor` (never leave a node stuck). */ retryChildren(node: T): void; /** * Lazy invalidation (v2): mark resolved children stale and re-ask the * accessor. Stale-while-revalidate (decision 15): the old subtree STAYS * rendered — per-row `isLoading` alongside the stale rows — until the * replacement resolves and swaps in; nothing blanks. Expanded nodes * revalidate immediately; collapsed nodes on their next expand (showing * their stale children instantly while the refetch runs). No argument * invalidates tree-wide. The tree still never fetches — it only re-runs * *your* accessor; batching and caching stay on your side of it. * * Nodes NOT materialised at call time — a resource-backed `dataSource` * that flashes empty mid-refresh and re-mints objects under the same keys * — are caught by the expanded⇒load reconciler once they appear (decision * 14), so an open branch survives a refresh without collapsing. */ invalidateChildren(node?: T): void; /** * Key-addressed facade over the node-addressed TreeApi (v2, Phase 15 — * decision 11: a facade, not `T | string` unions, since `T` may itself be * `string`). Keys are the tree's identity currency — consumers naturally * store `parentKey`/`id` strings for post-intent work; this resolves them * through the internal flat model so nobody rebuilds a key→node map * outside. A key that is unknown or not currently loaded is a no-op * (`isExpanded` reports the raw expansion set, which may hold keys of * not-yet-loaded nodes — e.g. a restore before the lazy branch resolves; * such keys load via the expanded⇒load reconciler once their node * materialises, decision 14). */ readonly byKey: { expand: (key: string) => void; collapse: (key: string) => void; toggle: (key: string) => void; expandDescendants: (key: string) => void; isExpanded: (key: string) => boolean; edit: (key: string) => void; focus: (key: string) => void; scrollTo: (key: string) => void; openContextMenu: (key: string) => void; retryChildren: (key: string) => void; /** No argument = tree-wide, exactly like the node-addressed form. */ invalidateChildren: (key?: string) => void; }; protected rowClassFor(row: FlatRow): string | readonly string[] | undefined; protected rowStyleFor(row: FlatRow): Record | undefined; /** A guide belongs to its group's PARENT — it carries that node's rowStyle. */ protected guideStyleFor(parentKey: string): Record | undefined; static ɵfac: _angular_core.ɵɵFactoryDeclaration, never>; static ɵcmp: _angular_core.ɵɵComponentDeclaration, "angular-tree", ["angularTree"], { "dataSource": { "alias": "dataSource"; "required": true; "isSignal": true; }; "childrenAccessor": { "alias": "childrenAccessor"; "required": true; "isSignal": true; }; "expansionKey": { "alias": "expansionKey"; "required": true; "isSignal": true; }; "itemSize": { "alias": "itemSize"; "required": false; "isSignal": true; }; "defaultExpandedKeys": { "alias": "defaultExpandedKeys"; "required": false; "isSignal": true; }; "expandedKeys": { "alias": "expandedKeys"; "required": false; "isSignal": true; }; "defaultFocusedKey": { "alias": "defaultFocusedKey"; "required": false; "isSignal": true; }; "collapseBehavior": { "alias": "collapseBehavior"; "required": false; "isSignal": true; }; "childrenDeps": { "alias": "childrenDeps"; "required": false; "isSignal": true; }; "selectedKeys": { "alias": "selectedKeys"; "required": false; "isSignal": true; }; "multi": { "alias": "multi"; "required": false; "isSignal": true; }; "deselectOnOutsideClick": { "alias": "deselectOnOutsideClick"; "required": false; "isSignal": true; }; "checkboxSelection": { "alias": "checkboxSelection"; "required": false; "isSignal": true; }; "searchTerm": { "alias": "searchTerm"; "required": false; "isSignal": true; }; "searchMatch": { "alias": "searchMatch"; "required": false; "isSignal": true; }; "typeaheadText": { "alias": "typeaheadText"; "required": false; "isSignal": true; }; "enterAction": { "alias": "enterAction"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "aria-label"; "required": false; "isSignal": true; }; "ariaLabelledby": { "alias": "aria-labelledby"; "required": false; "isSignal": true; }; "clickAction": { "alias": "clickAction"; "required": false; "isSignal": true; }; "announcements": { "alias": "announcements"; "required": false; "isSignal": true; }; "selectionMode": { "alias": "selectionMode"; "required": false; "isSignal": true; }; "focusMode": { "alias": "focusMode"; "required": false; "isSignal": true; }; "indentGuides": { "alias": "indentGuides"; "required": false; "isSignal": true; }; "labelOverflow": { "alias": "labelOverflow"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "rowClass": { "alias": "rowClass"; "required": false; "isSignal": true; }; "rowStyle": { "alias": "rowStyle"; "required": false; "isSignal": true; }; "disableDrag": { "alias": "disableDrag"; "required": false; "isSignal": true; }; "disableDrop": { "alias": "disableDrop"; "required": false; "isSignal": true; }; "disableEdit": { "alias": "disableEdit"; "required": false; "isSignal": true; }; "isSelectable": { "alias": "isSelectable"; "required": false; "isSignal": true; }; }, { "expandedKeys": "expandedKeysChange"; "selectedKeys": "selectedKeysChange"; "activated": "activated"; "moved": "moved"; "renamed": "renamed"; "selectionChange": "selectionChange"; "toggled": "toggled"; "childrenLoaded": "childrenLoaded"; "contextRequested": "contextRequested"; }, ["defs", "contextMenuDef", "emptyDef", "loadingDef"], never, true, [{ directive: typeof i1.CdkContextMenuTrigger; inputs: {}; outputs: {}; }]>; } /** * Wires any element to the row's derived tri-state and toggle — the tree * ships no checkbox UI (ROADMAP settled). Writes native `checked`/ * `indeterminate` properties (host binding can't target them on a directive: * NG8002). For `mat-checkbox`, bind its inputs from the template context * instead — see docs/RECIPES.md (settled 2026-07-07: pattern, not adapter). * * Shift+click range-selects from the selection anchor over visible order * (Gmail semantics). The host leaves the tab order: `Space` on the focused * row is the keyboard equivalent (APG — treeitem content is not a tab stop). */ declare class TreeNodeCheckbox { #private; constructor(); protected onClick(event: MouseEvent): void; static ɵfac: _angular_core.ɵɵFactoryDeclaration; static ɵdir: _angular_core.ɵɵDirectiveDeclaration; } /** * Declares a node template. Multiple defs may coexist; the first whose `when` * predicate matches wins, and a def without `when` is the fallback (Material * `matTreeNodeDef` convention). * * When `when` is a type guard, the template context narrows to the guarded * union member under `strictTemplates`: * * ```html * * * * ``` * * `S` defaults to `any` (not `unknown`) so guard-less fallback defs stay * usable — same trade-off CDK Table makes. Phase 0 spike, see ROADMAP.md. */ declare class TreeNodeDef { readonly template: TemplateRef>; /** Type-guard predicate selecting which nodes this template renders. */ readonly when: _angular_core.InputSignal<((node: T) => node is S) | undefined>; static ngTemplateContextGuard(_dir: TreeNodeDef, _ctx: unknown): _ctx is TreeNodeContext; static ɵfac: _angular_core.ɵɵFactoryDeclaration, never>; static ɵdir: _angular_core.ɵɵDirectiveDeclaration, "[treeNodeDef]", never, { "when": { "alias": "treeNodeDefWhen"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>; } /** Width of a single-line string in CSS px, in the label's own font. */ type TextMeasure = (text: string) => number; interface MiddleEllipsisOptions { /** * `'balanced'` (default) keeps roughly equal halves — AppKit's * `NSLineBreakByTruncatingMiddle`. `'extension'` cuts the STEM balanced and * keeps everything after the last `.` intact on the tail (Finder never * truncates the extension — but both ends of the name still survive: * `virtualized-expl…ering.component.spec.ts`, never `virtualized-exp….ts`); * names without a `.` fall back to balanced. */ readonly tail?: 'balanced' | 'extension'; } /** Grapheme clusters — a naive slice() bisects emoji ZWJ sequences and * combining marks; code points (`[...text]`) are the degraded fallback. */ declare function graphemesOf(text: string): readonly string[]; /** * macOS-style middle truncation: `head…tail` capped at `maxWidth`. * * Every candidate is measured as the COMPOSED string — summing half-widths * lies whenever kerning or ligatures cross the cut. Both tail policies cut * BALANCED halves — extension mode cuts the STEM balanced and appends the * whole extension (a bare-extension tail would read as end-ellipsis with the * extension stapled on, not a middle cut). Collapse ladder as width shrinks: * balanced middle cut → (extension mode) the stem gives way around the held * extension → the extension gives way too → bare `…`. `maxWidth <= 0` means * "layout hasn't happened" (SSR, jsdom, display:none) — the full text returns * untouched rather than everything collapsing to `…`. */ declare function middleEllipsis(text: string, maxWidth: number, measure: TextMeasure, options?: MiddleEllipsisOptions): string; /** * A `TextMeasure` in the element's computed font. The font is (re)applied on * every call — the context is shared across all directive instances. */ declare function cssTextMeasure(element: Element): TextMeasure | null; /** * macOS-Finder-style middle truncation for node labels: `head…tail` instead * of CSS's end-only `text-overflow`. The directive OWNS the element's text — * leave the element empty and bind the full string: * * ```html * * ``` * * Contract: * - The element's inline size must be content-independent (`flex: 1 1 auto; * min-inline-size: 0`, or a fixed width) — a shrink-to-content box resizes * when its text is replaced, and the re-truncation loop would chase its own * output. Pair with the tree's `labelOverflow: 'ellipsis'`, which caps rows * at the viewport; without it the row grows with the text and nothing ever * overflows. * - The full text stays reachable: `title` (hover tooltip) and `aria-label` * always carry the untruncated string, and the tree's type-ahead reads the * `typeaheadText` accessor, never the rendered DOM. * - Re-derives on text change, element resize, and web-font arrival * (`document.fonts` — measuring before the font loads is confidently * wrong). Measurement is canvas-based and layout-free; a ~1px margin * absorbs canvas-vs-DOM rendering drift. */ declare class MiddleEllipsis { #private; /** The full, untruncated label text. */ readonly middleEllipsis: _angular_core.InputSignal; /** Tail policy — see {@link MiddleEllipsisOptions}. */ readonly middleEllipsisTail: _angular_core.InputSignal<"balanced" | "extension">; constructor(); static ɵfac: _angular_core.ɵɵFactoryDeclaration; static ɵdir: _angular_core.ɵɵDirectiveDeclaration; } /** * Opt-in drag handle inside a node template (v2, ROADMAP2 Phase 9): the row * then drags *only* from this element, and the start delay drops to zero — * including touch, where row drags are otherwise disabled because long-press * belongs to the context menu (v1 decision). Grabbing a dedicated handle IS * the drag intent, so no delay disambiguation is needed. * * ```html * * drag_indicator * {{ node.name }} * * ``` */ declare class TreeNodeDragHandle { #private; constructor(); static ɵfac: _angular_core.ɵɵFactoryDeclaration; static ɵdir: _angular_core.ɵɵDirectiveDeclaration; } /** * The consumer-rendered rename input (the tree owns editing *state* only — * ROADMAP settled). Enter commits → the tree emits `renamed`; Escape cancels; * blur commits (file-explorer convention). Auto-focuses and selects on mount. */ declare class TreeNodeEditInput { #private; constructor(); protected commit(): void; protected cancel(): void; static ɵfac: _angular_core.ɵɵFactoryDeclaration; static ɵdir: _angular_core.ɵɵDirectiveDeclaration; } /** * Wires any element inside a node template to expand/collapse its row. * The tree ships no toggle UI — the consumer supplies the element. * * ```html * * ``` */ declare class TreeNodeToggle { #private; toggle(event: Event): void; static ɵfac: _angular_core.ɵɵFactoryDeclaration; static ɵdir: _angular_core.ɵɵDirectiveDeclaration; } /** * Content for the tree's **empty state** — shown when there are zero visible * rows (no data, or search filtered everything out). The tree owns the slot; * the consumer projects the message. Absent by default → the tree renders * nothing (sensible blank default). * * The template lives in the consumer's component, so it already has their own * state in scope (e.g. a `search()` signal to say "no results for …" vs * "no items") — hence no template context. * * ```html * No documents yet. * ``` */ declare class TreeEmptyDef { readonly template: TemplateRef; static ɵfac: _angular_core.ɵɵFactoryDeclaration; static ɵdir: _angular_core.ɵɵDirectiveDeclaration; } /** * Content for the tree's **root-loading state** — shown while the consumer's * `[loading]` input is `true` (the whole `dataSource` is being fetched; this * is distinct from a lazy *child* load, which drives per-row `isLoading`). * Takes precedence over the empty state. Absent by default → nothing. * * ```html * * ``` */ declare class TreeLoadingDef { readonly template: TemplateRef; static ɵfac: _angular_core.ɵɵFactoryDeclaration; static ɵdir: _angular_core.ɵɵDirectiveDeclaration; } export { AngularTree, MiddleEllipsis, TREE_NODE, TreeContextMenu, TreeEmptyDef, TreeLoadingDef, TreeNodeCheckbox, TreeNodeDef, TreeNodeDragHandle, TreeNodeEditInput, TreeNodeToggle, cssTextMeasure, graphemesOf, middleEllipsis }; export type { CheckState, ContextRequestedEvent, LoadChildrenEvent, MiddleEllipsisOptions, MoveEvent, RenameEvent, SelectCause, SelectEvent, TextMeasure, ToggleEvent, TreeAnnouncements, TreeChildrenAccessor, TreeContextMenuContext, TreeDropContext, TreeExpansionKey, TreeNodeContext, TreeNodeHandle };