@truenas/ui-components 0.3.20 → 0.3.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truenas/ui-components",
3
- "version": "0.3.20",
3
+ "version": "0.3.21",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org",
6
6
  "access": "public"
@@ -1,5 +1,5 @@
1
1
  import * as _angular_core from '@angular/core';
2
- import { Signal, InjectionToken, Renderer2, OnDestroy, ElementRef, AfterViewInit, OnInit, TemplateRef, AfterContentInit, Provider, ChangeDetectorRef, PipeTransform, ViewContainerRef, AfterViewChecked, ComponentRef } from '@angular/core';
2
+ import { Signal, InjectionToken, Renderer2, OnDestroy, ElementRef, AfterViewInit, OnInit, TemplateRef, AfterContentInit, Provider, ChangeDetectorRef, TrackByFunction, OnChanges, DoCheck, SimpleChanges, PipeTransform, ViewContainerRef, AfterViewChecked, ComponentRef } from '@angular/core';
3
3
  import { ControlValueAccessor, NgControl, AbstractControl } from '@angular/forms';
4
4
  import { ComponentHarness, BaseHarnessFilters, HarnessPredicate, TestKey, HarnessLoader } from '@angular/cdk/testing';
5
5
  import { SafeHtml, SafeResourceUrl, DomSanitizer } from '@angular/platform-browser';
@@ -7,10 +7,11 @@ import { ComponentFixture } from '@angular/core/testing';
7
7
  import * as _truenas_ui_components from '@truenas/ui-components';
8
8
  import { SelectionModel, DataSource } from '@angular/cdk/collections';
9
9
  import * as rxjs from 'rxjs';
10
- import { Observable } from 'rxjs';
10
+ import { Observable, BehaviorSubject } from 'rxjs';
11
11
  import * as i1 from '@angular/cdk/tree';
12
- import { CdkTree, FlatTreeControl, CdkTreeNode, CdkNestedTreeNode } from '@angular/cdk/tree';
12
+ import { CdkTree, FlatTreeControl, CdkTreeNode, CdkNestedTreeNode, CdkTreeNodeOutletContext, CdkTreeNodeDef } from '@angular/cdk/tree';
13
13
  export { FlatTreeControl } from '@angular/cdk/tree';
14
+ import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
14
15
  import { Overlay } from '@angular/cdk/overlay';
15
16
  import { DialogRef, DialogConfig } from '@angular/cdk/dialog';
16
17
  import { ComponentType } from '@angular/cdk/portal';
@@ -210,6 +211,19 @@ interface TnSelectOptionGroup<T = unknown> {
210
211
  options: TnSelectOption<T>[];
211
212
  disabled?: boolean;
212
213
  }
214
+ /**
215
+ * A keyboard-navigable row in the open dropdown. Either the synthetic
216
+ * "select all" action (multiple mode with `showSelectAll`) or a real option.
217
+ * Both carry the stable DOM `id` used for `aria-activedescendant`.
218
+ */
219
+ type TnSelectNavEntry<T> = {
220
+ kind: 'select-all';
221
+ id: string;
222
+ } | {
223
+ kind: 'option';
224
+ option: TnSelectOption<T>;
225
+ id: string;
226
+ };
213
227
  declare class TnSelectComponent<T = unknown> implements ControlValueAccessor, OnDestroy {
214
228
  options: _angular_core.InputSignal<TnSelectOption<T>[]>;
215
229
  optionGroups: _angular_core.InputSignal<TnSelectOptionGroup<T>[]>;
@@ -239,6 +253,16 @@ declare class TnSelectComponent<T = unknown> implements ControlValueAccessor, On
239
253
  /** Label of the empty option rendered when `allowEmpty` is set. */
240
254
  emptyLabel: _angular_core.InputSignal<string>;
241
255
  disabled: _angular_core.InputSignal<boolean>;
256
+ /**
257
+ * When `true` (multiple mode only), renders a "select all" row at the top of
258
+ * the dropdown that toggles every selectable (non-disabled) option on/off in
259
+ * one click. Mirrors webui ix-select's `[showSelectAll]`. Ignored in single
260
+ * mode. Its checkbox reflects the aggregate state: checked when all are
261
+ * selected, indeterminate when only some are.
262
+ */
263
+ showSelectAll: _angular_core.InputSignal<boolean>;
264
+ /** Label of the select-all row rendered when `showSelectAll` is set. */
265
+ selectAllLabel: _angular_core.InputSignal<string>;
242
266
  testId: _angular_core.InputSignal<TnTestIdValue>;
243
267
  /** Test-id base, falling back to the bound control name when `testId` is unset. */
244
268
  protected resolvedTestId: _angular_core.Signal<TnTestIdValue>;
@@ -310,10 +334,7 @@ declare class TnSelectComponent<T = unknown> implements ControlValueAccessor, On
310
334
  * then groups). Used by keyboard navigation so we can skip disabled
311
335
  * entries and group headers without a separate filter pass.
312
336
  */
313
- navigableOptions: _angular_core.Signal<{
314
- option: TnSelectOption<T>;
315
- id: string;
316
- }[]>;
337
+ navigableOptions: _angular_core.Signal<TnSelectNavEntry<T>[]>;
317
338
  /** Stable DOM id of the currently-highlighted option, for aria-activedescendant. */
318
339
  focusedOptionId: _angular_core.Signal<string | null>;
319
340
  /** Stable DOM id for an option; matches what navigableOptions() assigns. */
@@ -383,6 +404,39 @@ declare class TnSelectComponent<T = unknown> implements ControlValueAccessor, On
383
404
  protected displayText: _angular_core.Signal<string>;
384
405
  private findOptionByValue;
385
406
  protected hasAnyOptions: _angular_core.Signal<boolean>;
407
+ /**
408
+ * Values of every selectable (non-disabled) option, across ungrouped options
409
+ * and enabled groups. This is the set the select-all row operates on —
410
+ * disabled options and options in disabled groups are excluded because they
411
+ * can't be toggled individually either.
412
+ *
413
+ * Values are deduped with `compareValues` so a value that appears both
414
+ * ungrouped and inside a group isn't pushed twice — that would make
415
+ * select-all diverge from `toggleOption()`, which never produces duplicates.
416
+ */
417
+ protected selectableValues: _angular_core.Signal<T[]>;
418
+ /** Whether the select-all row is shown (multiple mode, opted in, with options). */
419
+ protected showSelectAllRow: _angular_core.Signal<boolean>;
420
+ /** Stable DOM id of the select-all row, for aria-activedescendant. */
421
+ protected selectAllId: _angular_core.Signal<string>;
422
+ /** True when every selectable option is currently selected. */
423
+ protected allSelected: _angular_core.Signal<boolean>;
424
+ /** True when some — but not all — selectable options are selected. */
425
+ protected selectAllIndeterminate: _angular_core.Signal<boolean>;
426
+ /** Test-id segments for the select-all row; mirrors ix-select's `[name, 'select-all']`. */
427
+ protected selectAllTestIdParts(): (string | number | null | undefined)[];
428
+ /**
429
+ * Toggles every selectable option: clears them all when they're all already
430
+ * selected, otherwise selects them all. Preserves the multi-select "open"
431
+ * behaviour — the dropdown stays open so the user can keep adjusting.
432
+ *
433
+ * Disabled-but-selected values (e.g. a disabled option pre-selected via
434
+ * `writeValue`) are preserved on both paths: the user can't toggle those
435
+ * rows individually, so select-all must not silently discard them either.
436
+ */
437
+ protected toggleSelectAll(): void;
438
+ /** Whether the select-all row is the keyboard-highlighted item. */
439
+ protected isSelectAllFocused(): boolean;
386
440
  /** One-shot guard so the object-compare warning fires at most once per instance. */
387
441
  private warnedAboutObjectCompare;
388
442
  /**
@@ -422,7 +476,7 @@ declare class TnSelectComponent<T = unknown> implements ControlValueAccessor, On
422
476
  private activateFocusedOption;
423
477
  private scrollFocusedIntoView;
424
478
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<TnSelectComponent<any>, never>;
425
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<TnSelectComponent<any>, "tn-select", never, { "options": { "alias": "options"; "required": false; "isSignal": true; }; "optionGroups": { "alias": "optionGroups"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "noOptionsLabel": { "alias": "noOptionsLabel"; "required": false; "isSignal": true; }; "allowEmpty": { "alias": "allowEmpty"; "required": false; "isSignal": true; }; "emptyLabel": { "alias": "emptyLabel"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "testId": { "alias": "testId"; "required": false; "isSignal": true; }; "multiple": { "alias": "multiple"; "required": false; "isSignal": true; }; "optionTestIdKey": { "alias": "optionTestIdKey"; "required": false; "isSignal": true; }; "compareWith": { "alias": "compareWith"; "required": false; "isSignal": true; }; }, { "selectionChange": "selectionChange"; "multiSelectionChange": "multiSelectionChange"; }, never, never, true, never>;
479
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TnSelectComponent<any>, "tn-select", never, { "options": { "alias": "options"; "required": false; "isSignal": true; }; "optionGroups": { "alias": "optionGroups"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "noOptionsLabel": { "alias": "noOptionsLabel"; "required": false; "isSignal": true; }; "allowEmpty": { "alias": "allowEmpty"; "required": false; "isSignal": true; }; "emptyLabel": { "alias": "emptyLabel"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "showSelectAll": { "alias": "showSelectAll"; "required": false; "isSignal": true; }; "selectAllLabel": { "alias": "selectAllLabel"; "required": false; "isSignal": true; }; "testId": { "alias": "testId"; "required": false; "isSignal": true; }; "multiple": { "alias": "multiple"; "required": false; "isSignal": true; }; "optionTestIdKey": { "alias": "optionTestIdKey"; "required": false; "isSignal": true; }; "compareWith": { "alias": "compareWith"; "required": false; "isSignal": true; }; }, { "selectionChange": "selectionChange"; "multiSelectionChange": "multiSelectionChange"; }, never, never, true, never>;
426
480
  }
427
481
 
428
482
  /**
@@ -5031,6 +5085,27 @@ declare class TnSelectHarness extends ComponentHarness {
5031
5085
  * ```
5032
5086
  */
5033
5087
  getOptions(): Promise<string[]>;
5088
+ /**
5089
+ * Toggles the select-all row (multiple mode with `showSelectAll`). Opens the
5090
+ * dropdown if needed. Throws when the select-all row isn't present.
5091
+ *
5092
+ * @returns Promise that resolves once the row has been clicked.
5093
+ *
5094
+ * @example
5095
+ * ```typescript
5096
+ * const select = await loader.getHarness(TnSelectHarness);
5097
+ * await select.toggleSelectAll(); // selects every option
5098
+ * await select.toggleSelectAll(); // clears them again
5099
+ * ```
5100
+ */
5101
+ toggleSelectAll(): Promise<void>;
5102
+ /**
5103
+ * Whether the select-all checkbox reads as fully checked (all options
5104
+ * selected). Opens the dropdown if needed. Throws when the row isn't present.
5105
+ *
5106
+ * @returns Promise resolving to true when every option is selected.
5107
+ */
5108
+ isSelectAllChecked(): Promise<boolean>;
5034
5109
  }
5035
5110
  /**
5036
5111
  * A set of criteria that can be used to filter a list of `TnSelectHarness` instances.
@@ -6268,6 +6343,349 @@ declare class TnTreeNodeOutletDirective {
6268
6343
  static ɵdir: _angular_core.ɵɵDirectiveDeclaration<TnTreeNodeOutletDirective, "[tnTreeNodeOutlet]", never, {}, {}, never, never, true, [{ directive: typeof i1.CdkTreeNodeOutlet; inputs: {}; outputs: {}; }]>;
6269
6344
  }
6270
6345
 
6346
+ /**
6347
+ * A single flattened tree node prepared for virtual-scroll rendering.
6348
+ *
6349
+ * `TnTreeVirtualScrollViewComponent` intercepts CDK's `renderNodeChanges` and,
6350
+ * instead of letting the CDK tree insert every visible node into its outlet,
6351
+ * wraps each node in this shape so the node can be materialised on demand by the
6352
+ * `cdk-virtual-scroll-viewport` (only rows in view are created in the DOM).
6353
+ */
6354
+ interface TnTreeVirtualNodeData<T> {
6355
+ /** The raw data node. */
6356
+ data: T;
6357
+ /** The outlet context (carries `$implicit`, `level`, etc.) for the node template. */
6358
+ context: CdkTreeNodeOutletContext<T>;
6359
+ /** The matched node definition whose template renders this row. */
6360
+ nodeDef: CdkTreeNodeDef<T>;
6361
+ /** 1-based position within the node's SIBLING set (same parent/level), for `aria-posinset`. */
6362
+ posInSet: number;
6363
+ /** Size of the node's SIBLING set (same parent/level), for `aria-setsize`. */
6364
+ setSize: number;
6365
+ }
6366
+
6367
+ /** Default fixed row height (px) used by the virtual scroll viewport. */
6368
+ declare const defaultTreeItemSize = 48;
6369
+ /**
6370
+ * A `tn-tree` that renders through a `cdk-virtual-scroll-viewport`, so only the
6371
+ * rows currently in view are materialised in the DOM. Drop-in for large trees
6372
+ * (thousands of nodes) where the plain `tn-tree` would render every node.
6373
+ *
6374
+ * Usage mirrors `tn-tree`: provide a `TnTreeFlatDataSource` + `FlatTreeControl`
6375
+ * and one `*cdkTreeNodeDef` template. Rows are a fixed height (`itemSize`).
6376
+ *
6377
+ * ```html
6378
+ * <tn-tree-virtual-scroll-view [dataSource]="dataSource" [treeControl]="treeControl" [itemSize]="52">
6379
+ * <tn-tree-node *cdkTreeNodeDef="let node" cdkTreeNodePadding [routerLink]="...">
6380
+ * {{ node.name }}
6381
+ * </tn-tree-node>
6382
+ * </tn-tree-virtual-scroll-view>
6383
+ * ```
6384
+ *
6385
+ * Accessibility: rows are exposed with `role="treeitem"` plus `aria-level`,
6386
+ * `aria-posinset` and `aria-setsize` (the latter two relative to the node's
6387
+ * siblings — nodes sharing the same parent/level — per the WAI-ARIA tree
6388
+ * pattern, not the flattened list of all visible rows), and the virtual-scroll
6389
+ * wrappers are marked `role="presentation"` so assistive tech still sees the
6390
+ * items as children of the `role="tree"` host.
6391
+ *
6392
+ * Keyboard: expandable rows are focusable and expand/collapse with Enter/Space (see
6393
+ * {@link onTreeKeydown}), so a keyboard/AT user can operate the `aria-expanded` that
6394
+ * each expandable `treeitem` advertises. Roving arrow-key / Home / End navigation
6395
+ * BETWEEN nodes is NOT supported here, though — because rows are materialised (and
6396
+ * recycled) by the virtual scroll viewport rather than registered with CdkTree's node
6397
+ * outlet, the CDK `TreeKeyManager` has no stable node set to drive. Use Tab to move
6398
+ * between rows, or the non-virtual `tn-tree` when full roving navigation is required.
6399
+ */
6400
+ declare class TnTreeVirtualScrollViewComponent<T, K = T> extends CdkTree<T, K> implements AfterViewInit {
6401
+ private destroyRef;
6402
+ private cdr;
6403
+ readonly virtualScrollViewport: _angular_core.Signal<CdkVirtualScrollViewport>;
6404
+ /** Fixed row height in px. Must match the actual rendered node height. */
6405
+ readonly itemSize: _angular_core.InputSignal<number>;
6406
+ /**
6407
+ * Viewport buffer sizes (px). Leave at 0 (the default) to derive them from `itemSize()`
6408
+ * — {@link defaultMinBufferRows} / {@link defaultBufferRows} rows — so the buffers scale
6409
+ * with a custom row height; pass an explicit px value to override. (A fixed px default
6410
+ * would under-buffer a tall `itemSize`, even failing to buffer a single row when
6411
+ * `itemSize > maxBufferPx`.)
6412
+ */
6413
+ readonly minBufferPx: _angular_core.InputSignal<number>;
6414
+ readonly maxBufferPx: _angular_core.InputSignal<number>;
6415
+ /** `minBufferPx` resolved to px, falling back to a row-count default that tracks `itemSize()`. */
6416
+ protected readonly resolvedMinBufferPx: _angular_core.Signal<number>;
6417
+ /** `maxBufferPx` resolved to px, falling back to a row-count default that tracks `itemSize()`. */
6418
+ protected readonly resolvedMaxBufferPx: _angular_core.Signal<number>;
6419
+ /**
6420
+ * When true the viewport scrolls with the window instead of an internal scroll area.
6421
+ * `booleanAttribute` so the bare presence form (`<... scrollWindow>`) coerces to `true`
6422
+ * rather than the empty-string (falsy) an un-transformed input would receive.
6423
+ *
6424
+ * Set once at initialisation — NOT reactive. The scroll listener, presentational roles
6425
+ * and ResizeObserver are wired in `ngAfterViewInit` against the viewport that this input
6426
+ * selected; toggling it later re-renders the viewport but does not re-run that wiring.
6427
+ */
6428
+ readonly scrollWindow: _angular_core.InputSignalWithTransform<boolean, unknown>;
6429
+ /** Whether to show the floating "scroll to top" button once scrolled down. */
6430
+ readonly showScrollToTop: _angular_core.InputSignalWithTransform<boolean, unknown>;
6431
+ /** Accessible label / tooltip for the scroll-to-top button (i18n is the consumer's job). */
6432
+ readonly scrollToTopLabel: _angular_core.InputSignal<string>;
6433
+ /**
6434
+ * Per-row trackBy over the ORIGINAL data node (not the internal wrapper). Strongly
6435
+ * recommended: without it rows track by index, so the recycling viewport reuses a
6436
+ * detached view for whatever node lands at that index on data changes. Pass a stable
6437
+ * key (e.g. `(_, node) => node.id`) as the stories do.
6438
+ */
6439
+ readonly nodeTrackBy: _angular_core.InputSignal<TrackByFunction<T> | undefined>;
6440
+ /** Emits the viewport's horizontal `scrollLeft` (used to sync a sticky column header). */
6441
+ readonly viewportScrolled: _angular_core.OutputEmitterRef<number>;
6442
+ /**
6443
+ * Emits the observed content size whenever it changes (used to size a sticky header).
6444
+ * `width` is the full rendered content width — including horizontal overflow past the
6445
+ * viewport — which is what a horizontally-synced header needs. `height` is the observed
6446
+ * content wrapper's height: the visible viewport height in internal-scroll mode, but the
6447
+ * FULL content height (row count × `itemSize`) in `scrollWindow` mode, where the wrapper
6448
+ * grows with the document. Consumers wanting the visible viewport height should not rely
6449
+ * on this field in window mode.
6450
+ */
6451
+ readonly viewportResized: _angular_core.OutputEmitterRef<{
6452
+ width: number;
6453
+ height: number;
6454
+ }>;
6455
+ /** Last `scrollLeft` emitted via {@link viewportScrolled}; used to skip redundant emits. */
6456
+ private lastEmittedScrollLeft;
6457
+ protected nodes$: BehaviorSubject<TnTreeVirtualNodeData<T>[]>;
6458
+ protected readonly innerTrackBy: _angular_core.Signal<TrackByFunction<TnTreeVirtualNodeData<T>>>;
6459
+ private renderNodeChanges$;
6460
+ private resizeObserver;
6461
+ private scrollViewportElement;
6462
+ private scrollFrameSubscription;
6463
+ constructor();
6464
+ ngAfterViewInit(): void;
6465
+ ngOnDestroy(): void;
6466
+ /**
6467
+ * Cached visibility of the scroll-to-top button. Recomputed only on scroll (see
6468
+ * {@link onViewportScroll}) rather than read as a getter every change-detection
6469
+ * pass, so `measureScrollOffset` — a layout-forcing read — is not called each cycle.
6470
+ */
6471
+ protected isScrollTopButtonVisible: boolean;
6472
+ scrollToTop(): void;
6473
+ /**
6474
+ * Enter/Space on a focused expandable row toggles its expansion. The virtual viewport
6475
+ * recycles rows so CDK's `TreeKeyManager` can't drive them (see class docs); this keeps
6476
+ * the expand/collapse that each `aria-expanded` row advertises keyboard-operable, via
6477
+ * event delegation on the `role="tree"` host that reuses the row's `cdkTreeNodeToggle`
6478
+ * click handler. Ignored when focus is on an inner control (e.g. a `routerLink` anchor)
6479
+ * so that element keeps its own Enter/Space behaviour.
6480
+ */
6481
+ protected onTreeKeydown(event: KeyboardEvent): void;
6482
+ private updateScrollTopButtonVisibility;
6483
+ renderNodeChanges(data: readonly T[]): void;
6484
+ private getNodeLevel;
6485
+ /**
6486
+ * Compute per-row `aria-posinset` / `aria-setsize` scoped to each node's SIBLINGS
6487
+ * (same parent / same level), as the WAI-ARIA tree pattern requires — not the flat
6488
+ * list of all visible rows. The flat node set is depth-first ordered and each node
6489
+ * carries a level, so siblings at level L are the consecutive level-L nodes bounded
6490
+ * by any shallower node (level < L = a parent boundary); deeper nodes in between are
6491
+ * descendants of an earlier sibling and don't split the group. One pass, tracking the
6492
+ * open sibling group at each level.
6493
+ */
6494
+ private computeAriaPositions;
6495
+ private createNode;
6496
+ private buildVirtualNodes;
6497
+ private listenForNodeChanges;
6498
+ private readonly onViewportScroll;
6499
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TnTreeVirtualScrollViewComponent<any, any>, never>;
6500
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TnTreeVirtualScrollViewComponent<any, any>, "tn-tree-virtual-scroll-view", ["tnTreeVirtualScrollView"], { "itemSize": { "alias": "itemSize"; "required": false; "isSignal": true; }; "minBufferPx": { "alias": "minBufferPx"; "required": false; "isSignal": true; }; "maxBufferPx": { "alias": "maxBufferPx"; "required": false; "isSignal": true; }; "scrollWindow": { "alias": "scrollWindow"; "required": false; "isSignal": true; }; "showScrollToTop": { "alias": "showScrollToTop"; "required": false; "isSignal": true; }; "scrollToTopLabel": { "alias": "scrollToTopLabel"; "required": false; "isSignal": true; }; "nodeTrackBy": { "alias": "nodeTrackBy"; "required": false; "isSignal": true; }; }, { "viewportScrolled": "viewportScrolled"; "viewportResized": "viewportResized"; }, never, never, true, [{ directive: typeof TnTestIdDirective; inputs: { "tnTestId": "testId"; }; outputs: {}; }]>;
6501
+ }
6502
+
6503
+ /**
6504
+ * Renders a single virtual tree row.
6505
+ *
6506
+ * `cdk-virtual-scroll-viewport` materialises this outlet for each row that scrolls
6507
+ * into view; the outlet instantiates the node's template with its context and
6508
+ * (re)binds `CdkTreeNode.mostRecentTreeNode.data`, so the row behaves exactly as a
6509
+ * node rendered directly by the CDK tree. When the same DOM view is recycled for a
6510
+ * different node (virtual scrolling reuses views), only the context is patched.
6511
+ */
6512
+ declare class TnTreeVirtualScrollNodeOutletDirective<T> implements OnChanges, DoCheck {
6513
+ private _viewContainerRef;
6514
+ private _viewRef;
6515
+ readonly data: _angular_core.InputSignal<TnTreeVirtualNodeData<T>>;
6516
+ /**
6517
+ * Re-assert the row's aria position every check. The viewport's recycling view
6518
+ * repeater can swap the underlying DOM view for a different row without our
6519
+ * `ngOnChanges` writing the new `aria-setsize`/`aria-posinset` in a way that
6520
+ * survives the swap, so we reconcile the current element against the current data
6521
+ * on each change-detection pass (two cheap attribute writes) — self-healing.
6522
+ */
6523
+ ngDoCheck(): void;
6524
+ ngOnChanges(changes: SimpleChanges): void;
6525
+ /**
6526
+ * Whether the row must be re-instantiated (vs. patched in place). Every wrapper
6527
+ * carries the same fixed key set (`data`/`context`/`nodeDef`/`posInSet`/`setSize`),
6528
+ * so recreation comes down to whether the raw data node is a different reference —
6529
+ * that is what marks a genuinely different row (a missing wrapper also recreates).
6530
+ */
6531
+ private shouldRecreateView;
6532
+ /**
6533
+ * Reflect posinset/setsize onto the row element so screen readers can announce
6534
+ * "item N of M". Runs on every `ngDoCheck` (the hot CD path), so only write when the
6535
+ * attribute actually differs — skipping the redundant `setAttribute` on the common
6536
+ * pass where nothing changed.
6537
+ */
6538
+ private applyAriaPosition;
6539
+ /**
6540
+ * Make expandable rows keyboard-focusable so a user can Tab to a pool/branch and
6541
+ * expand it with Enter/Space (the host `TnTreeVirtualScrollViewComponent` handles the
6542
+ * key). The virtual viewport recycles a row's view between expandable and leaf nodes,
6543
+ * so this reconciles every check; leaf rows are left to the consumer's own interactive
6544
+ * content (e.g. a `routerLink` anchor). Expandability is read from `aria-expanded`,
6545
+ * which `tn-tree-node` sets only on expandable nodes. Only touch the DOM on change —
6546
+ * this runs on the hot CD path.
6547
+ */
6548
+ private applyKeyboardAffordance;
6549
+ private updateExistingContext;
6550
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TnTreeVirtualScrollNodeOutletDirective<any>, never>;
6551
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<TnTreeVirtualScrollNodeOutletDirective<any>, "[tnTreeVirtualScrollNodeOutlet]", never, { "data": { "alias": "data"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
6552
+ }
6553
+
6554
+ /**
6555
+ * Harness for interacting with `tn-tree-virtual-scroll-view` in tests.
6556
+ *
6557
+ * Because the component virtualises its rows, every query below operates over the
6558
+ * currently-MATERIALISED (visible + buffered) rows only — nodes scrolled far out of view
6559
+ * are not in the DOM. Indexes are positions within that visible set, not the full data.
6560
+ *
6561
+ * @example
6562
+ * ```typescript
6563
+ * const tree = await loader.getHarness(TnTreeVirtualScrollViewHarness);
6564
+ * expect(await tree.getRowTexts()).toEqual(['pool', 'other']);
6565
+ *
6566
+ * await tree.expand(0);
6567
+ * expect(await tree.isExpanded(0)).toBe(true);
6568
+ * expect(await tree.getAriaLevel(1)).toBe(2);
6569
+ * ```
6570
+ */
6571
+ declare class TnTreeVirtualScrollViewHarness extends ComponentHarness {
6572
+ static hostSelector: string;
6573
+ /**
6574
+ * Gets a `HarnessPredicate` that can be used to search for a virtual-scroll tree
6575
+ * with specific attributes.
6576
+ *
6577
+ * @param options Options for filtering which instances are considered a match.
6578
+ * @returns A `HarnessPredicate` configured with the given options.
6579
+ */
6580
+ static with(options?: TnTreeVirtualScrollViewHarnessFilters): HarnessPredicate<TnTreeVirtualScrollViewHarness>;
6581
+ private readonly rows;
6582
+ private readonly scrollTopButton;
6583
+ /**
6584
+ * Gets the number of currently-materialised tree rows.
6585
+ *
6586
+ * @returns Promise resolving to the visible row count.
6587
+ */
6588
+ getRowCount(): Promise<number>;
6589
+ /**
6590
+ * Gets the text label of every materialised row (the node's text cell only, excluding
6591
+ * the expand chevron glyph).
6592
+ *
6593
+ * @returns Promise resolving to an array of row label strings.
6594
+ */
6595
+ getRowTexts(): Promise<string[]>;
6596
+ /**
6597
+ * Gets the text label of a single materialised row.
6598
+ *
6599
+ * @param index Zero-based index within the visible rows.
6600
+ * @returns Promise resolving to the row's label.
6601
+ */
6602
+ getRowText(index: number): Promise<string>;
6603
+ /**
6604
+ * Gets the 1-based `aria-level` of a row (root nodes are 1).
6605
+ *
6606
+ * @param index Zero-based index within the visible rows.
6607
+ * @returns Promise resolving to the aria-level, or null if unset.
6608
+ */
6609
+ getAriaLevel(index: number): Promise<number | null>;
6610
+ /**
6611
+ * Gets a row's `aria-posinset` — its 1-based position within its SIBLING set.
6612
+ *
6613
+ * @param index Zero-based index within the visible rows.
6614
+ * @returns Promise resolving to the aria-posinset, or null if unset.
6615
+ */
6616
+ getAriaPosInSet(index: number): Promise<number | null>;
6617
+ /**
6618
+ * Gets a row's `aria-setsize` — the size of its SIBLING set.
6619
+ *
6620
+ * @param index Zero-based index within the visible rows.
6621
+ * @returns Promise resolving to the aria-setsize, or null if unset.
6622
+ */
6623
+ getAriaSetSize(index: number): Promise<number | null>;
6624
+ /**
6625
+ * Whether a row is expandable (advertises `aria-expanded`).
6626
+ *
6627
+ * @param index Zero-based index within the visible rows.
6628
+ * @returns Promise resolving to true if the row is expandable.
6629
+ */
6630
+ isExpandable(index: number): Promise<boolean>;
6631
+ /**
6632
+ * Whether an expandable row is currently expanded.
6633
+ *
6634
+ * @param index Zero-based index within the visible rows.
6635
+ * @returns Promise resolving to true if `aria-expanded="true"`.
6636
+ */
6637
+ isExpanded(index: number): Promise<boolean>;
6638
+ /**
6639
+ * Whether a row is keyboard tab-focusable (`tabindex="0"`). Only expandable rows are.
6640
+ *
6641
+ * @param index Zero-based index within the visible rows.
6642
+ * @returns Promise resolving to true if the row is tab-focusable.
6643
+ */
6644
+ isFocusable(index: number): Promise<boolean>;
6645
+ /**
6646
+ * Toggles a row's expansion by clicking its toggle. No-op semantics are the tree's
6647
+ * (clicking a leaf does nothing).
6648
+ *
6649
+ * @param index Zero-based index within the visible rows.
6650
+ */
6651
+ toggle(index: number): Promise<void>;
6652
+ /**
6653
+ * Expands a row if it is expandable and currently collapsed.
6654
+ *
6655
+ * @param index Zero-based index within the visible rows.
6656
+ */
6657
+ expand(index: number): Promise<void>;
6658
+ /**
6659
+ * Collapses a row if it is currently expanded.
6660
+ *
6661
+ * @param index Zero-based index within the visible rows.
6662
+ */
6663
+ collapse(index: number): Promise<void>;
6664
+ /**
6665
+ * Focuses a row and presses a key on it (Enter/Space toggle an expandable row).
6666
+ *
6667
+ * @param index Zero-based index within the visible rows.
6668
+ * @param key Which key to press — Enter or Space.
6669
+ */
6670
+ pressKeyOnRow(index: number, key: 'enter' | 'space'): Promise<void>;
6671
+ /**
6672
+ * Whether the floating scroll-to-top button is currently visible.
6673
+ *
6674
+ * @returns Promise resolving to true if the button is rendered.
6675
+ */
6676
+ isScrollToTopVisible(): Promise<boolean>;
6677
+ /**
6678
+ * Clicks the scroll-to-top button. Throws if it is not currently visible.
6679
+ */
6680
+ clickScrollToTop(): Promise<void>;
6681
+ private getRow;
6682
+ private getRowNumberAttribute;
6683
+ }
6684
+ /**
6685
+ * Filters for finding `TnTreeVirtualScrollViewHarness` instances.
6686
+ */
6687
+ type TnTreeVirtualScrollViewHarnessFilters = BaseHarnessFilters;
6688
+
6271
6689
  declare enum CommonShortcuts {
6272
6690
  NEW = "\u2318N",
6273
6691
  OPEN = "\u2318O",
@@ -8822,5 +9240,5 @@ declare const TN_THEME_DEFINITIONS: readonly TnThemeDefinition[];
8822
9240
  */
8823
9241
  declare const THEME_MAP: Map<TnTheme, TnThemeDefinition>;
8824
9242
 
8825
- export { CommonShortcuts, DEFAULT_THEME, DiskIconComponent, DiskType, FileSizePipe, InputType, LIGHT_THEME, LabelMarkupPipe, LabelTextPipe, LinuxModifierKeys, LinuxShortcuts, ModifierKeys, QuickShortcuts, ShortcutBuilder, StripMntPrefixPipe, THEME_MAP, THEME_STORAGE_KEY, TN_FORM_FIELD_ERRORS, TN_TABLE_PAGER_DEFAULT_LABELS, TN_TABLE_PAGER_LABELS, TN_TEST_ATTR, TN_THEME_DEFINITIONS, TnAutocompleteComponent, TnAutocompleteHarness, TnBannerActionDirective, TnBannerComponent, TnBannerHarness, TnBrandedSpinnerComponent, TnButtonComponent, TnButtonHarness, TnButtonToggleComponent, TnButtonToggleGroupComponent, TnButtonToggleGroupHarness, TnButtonToggleHarness, TnCalendarComponent, TnCalendarHeaderComponent, TnCardComponent, TnCardFooterActionsDirective, TnCardHeaderActionsDirective, TnCardHeaderDirective, TnCellDefDirective, TnCheckboxComponent, TnCheckboxHarness, TnCheckboxLabelDirective, TnChipComponent, TnChipHarness, TnChipInputComponent, TnChipInputHarness, TnConfirmDialogComponent, TnDateInputComponent, TnDateInputHarness, TnDateRangeInputComponent, TnDateRangeInputHarness, TnDetailRowDefDirective, TnDialog, TnDialogHarness, TnDialogShellComponent, TnDialogTesting, TnDividerComponent, TnDividerDirective, TnDrawerComponent, TnDrawerContainerComponent, TnDrawerContainerHarness, TnDrawerContentComponent, TnDrawerHarness, TnEmptyComponent, TnEmptyHarness, TnExpansionPanelComponent, TnExpansionPanelHarness, TnFileInputComponent, TnFileInputHarness, TnFilePickerComponent, TnFilePickerPopupComponent, TnFormFieldComponent, TnFormFieldHarness, TnFormSectionComponent, TnFormSectionHarness, TnHeaderCellDefDirective, TnIconButtonComponent, TnIconButtonHarness, TnIconComponent, TnIconHarness, TnIconRegistryService, TnIconTesting, TnInputComponent, TnInputDirective, TnInputHarness, TnKeyboardShortcutComponent, TnKeyboardShortcutService, TnListAvatarDirective, TnListComponent, TnListIconDirective, TnListItemComponent, TnListItemLineDirective, TnListItemPrimaryDirective, TnListItemSecondaryDirective, TnListItemTitleDirective, TnListItemTrailingDirective, TnListOptionComponent, TnListSubheaderComponent, TnMenuActivateHoverDirective, TnMenuComponent, TnMenuHarness, TnMenuItemComponent, TnMenuTesting, TnMenuTriggerDirective, TnMonthViewComponent, TnMultiYearViewComponent, TnNestedTreeNodeComponent, TnParticleProgressBarComponent, TnProgressBarComponent, TnRadioComponent, TnRadioHarness, TnSelectComponent, TnSelectHarness, TnSelectionListComponent, TnSidePanelActionDirective, TnSidePanelComponent, TnSidePanelHarness, TnSidePanelHeaderActionDirective, TnSlideToggleComponent, TnSlideToggleHarness, TnSliderComponent, TnSliderThumbDirective, TnSliderWithLabelDirective, TnSpinnerComponent, TnSpriteLoaderService, TnStepComponent, TnStepperComponent, TnStepperHarness, TnStepperNextDirective, TnStepperPreviousDirective, TnTabComponent, TnTabHarness, TnTabPanelComponent, TnTabPanelHarness, TnTableColumnDirective, TnTableComponent, TnTableHarness, TnTablePagerComponent, TnTablePagerHarness, TnTabsComponent, TnTabsHarness, TnTestIdDirective, TnTheme, TnThemeService, TnTimeInputComponent, TnToastComponent, TnToastMock, TnToastPosition, TnToastRef, TnToastService, TnToastTesting, TnToastType, TnTooltipComponent, TnTooltipDirective, TnTreeComponent, TnTreeFlatDataSource, TnTreeFlattener, TnTreeNodeComponent, TnTreeNodeOutletDirective, TruncatePathPipe, WindowsModifierKeys, WindowsShortcuts, composeTestId, controlTestId, createLucideLibrary, createShortcut, defaultSpriteBasePath, defaultSpriteConfigPath, formatSize, kebabTestSegment, labelMarkupToHtml, labelMarkupToText, libIconMarker, parseLabelMarkup, parseSize, registerLucideIcons, scopeTestId, setupLucideIntegration, tnIconMarker, writeTestId };
8826
- export type { AutocompleteHarnessFilters, BannerHarnessFilters, ButtonHarnessFilters, ButtonToggleHarnessFilters, CalendarCell, CheckboxHarnessFilters, ChipColor, ChipHarnessFilters, CreateFolderEvent, DateInputHarnessFilters, DateRange, DateRangeInputHarnessFilters, DialogHarnessFilters, EmptyHarnessFilters, ExpansionPanelHarnessFilters, FileInputHarnessFilters, FilePickerCallbacks, FilePickerError, FilePickerMode, FileSystemItem, FormFieldHarnessFilters, FormSectionHarnessFilters, IconButtonHarnessFilters, IconHarnessFilters, IconLibrary, IconLibraryType, IconResult, IconSize, IconSource, IconTestingMockOverrides, InputHarnessFilters, KeyCombination, LabelMarkupSegment, LabelMarkupSegmentType, LabelType, LucideIconOptions, MenuHarnessFilters, MockIconRegistry, MockSpriteLoader, PathSegment, PlatformType, ProgressBarMode, RadioHarnessFilters, ResolvedIcon, SelectHarnessFilters, ShortcutHandler, SidePanelHarnessFilters, SizeStandard, SlideToggleColor, SlideToggleHarnessFilters, SpinnerMode, SpriteConfig, StepperHarnessFilters, SubscriptSizing, TabChangeEvent, TabHarnessFilters, TabPanelHarnessFilters, TabsHarnessFilters, TnAutocompleteOption, TnBannerType, TnButtonToggleType, TnCardAction, TnCardControl, TnCardFooterLink, TnCardHeaderStatus, TnChipInputHarnessFilters, TnChipInputOption, TnConfirmDialogData, TnDialogDefaults, TnDialogOpenTarget, TnDrawerMode, TnDrawerPosition, TnEmptySize, TnFlatTreeNode, TnFormFieldErrorMessage, TnFormFieldErrorMessages, TnFormFieldErrorResolver, TnMenuItem, TnSelectOption, TnSelectOptionGroup, TnSelectionChange, TnSortEvent, TnTableDataProvider, TnTableDataSource, TnTableHarnessFilters, TnTablePagerHarnessFilters, TnTablePagerLabels, TnTablePagination, TnTestAttrName, TnTestIdValue, TnThemeDefinition, TnToastCall, TnToastConfig, TooltipPosition, YearCell };
9243
+ export { CommonShortcuts, DEFAULT_THEME, DiskIconComponent, DiskType, FileSizePipe, InputType, LIGHT_THEME, LabelMarkupPipe, LabelTextPipe, LinuxModifierKeys, LinuxShortcuts, ModifierKeys, QuickShortcuts, ShortcutBuilder, StripMntPrefixPipe, THEME_MAP, THEME_STORAGE_KEY, TN_FORM_FIELD_ERRORS, TN_TABLE_PAGER_DEFAULT_LABELS, TN_TABLE_PAGER_LABELS, TN_TEST_ATTR, TN_THEME_DEFINITIONS, TnAutocompleteComponent, TnAutocompleteHarness, TnBannerActionDirective, TnBannerComponent, TnBannerHarness, TnBrandedSpinnerComponent, TnButtonComponent, TnButtonHarness, TnButtonToggleComponent, TnButtonToggleGroupComponent, TnButtonToggleGroupHarness, TnButtonToggleHarness, TnCalendarComponent, TnCalendarHeaderComponent, TnCardComponent, TnCardFooterActionsDirective, TnCardHeaderActionsDirective, TnCardHeaderDirective, TnCellDefDirective, TnCheckboxComponent, TnCheckboxHarness, TnCheckboxLabelDirective, TnChipComponent, TnChipHarness, TnChipInputComponent, TnChipInputHarness, TnConfirmDialogComponent, TnDateInputComponent, TnDateInputHarness, TnDateRangeInputComponent, TnDateRangeInputHarness, TnDetailRowDefDirective, TnDialog, TnDialogHarness, TnDialogShellComponent, TnDialogTesting, TnDividerComponent, TnDividerDirective, TnDrawerComponent, TnDrawerContainerComponent, TnDrawerContainerHarness, TnDrawerContentComponent, TnDrawerHarness, TnEmptyComponent, TnEmptyHarness, TnExpansionPanelComponent, TnExpansionPanelHarness, TnFileInputComponent, TnFileInputHarness, TnFilePickerComponent, TnFilePickerPopupComponent, TnFormFieldComponent, TnFormFieldHarness, TnFormSectionComponent, TnFormSectionHarness, TnHeaderCellDefDirective, TnIconButtonComponent, TnIconButtonHarness, TnIconComponent, TnIconHarness, TnIconRegistryService, TnIconTesting, TnInputComponent, TnInputDirective, TnInputHarness, TnKeyboardShortcutComponent, TnKeyboardShortcutService, TnListAvatarDirective, TnListComponent, TnListIconDirective, TnListItemComponent, TnListItemLineDirective, TnListItemPrimaryDirective, TnListItemSecondaryDirective, TnListItemTitleDirective, TnListItemTrailingDirective, TnListOptionComponent, TnListSubheaderComponent, TnMenuActivateHoverDirective, TnMenuComponent, TnMenuHarness, TnMenuItemComponent, TnMenuTesting, TnMenuTriggerDirective, TnMonthViewComponent, TnMultiYearViewComponent, TnNestedTreeNodeComponent, TnParticleProgressBarComponent, TnProgressBarComponent, TnRadioComponent, TnRadioHarness, TnSelectComponent, TnSelectHarness, TnSelectionListComponent, TnSidePanelActionDirective, TnSidePanelComponent, TnSidePanelHarness, TnSidePanelHeaderActionDirective, TnSlideToggleComponent, TnSlideToggleHarness, TnSliderComponent, TnSliderThumbDirective, TnSliderWithLabelDirective, TnSpinnerComponent, TnSpriteLoaderService, TnStepComponent, TnStepperComponent, TnStepperHarness, TnStepperNextDirective, TnStepperPreviousDirective, TnTabComponent, TnTabHarness, TnTabPanelComponent, TnTabPanelHarness, TnTableColumnDirective, TnTableComponent, TnTableHarness, TnTablePagerComponent, TnTablePagerHarness, TnTabsComponent, TnTabsHarness, TnTestIdDirective, TnTheme, TnThemeService, TnTimeInputComponent, TnToastComponent, TnToastMock, TnToastPosition, TnToastRef, TnToastService, TnToastTesting, TnToastType, TnTooltipComponent, TnTooltipDirective, TnTreeComponent, TnTreeFlatDataSource, TnTreeFlattener, TnTreeNodeComponent, TnTreeNodeOutletDirective, TnTreeVirtualScrollNodeOutletDirective, TnTreeVirtualScrollViewComponent, TnTreeVirtualScrollViewHarness, TruncatePathPipe, WindowsModifierKeys, WindowsShortcuts, composeTestId, controlTestId, createLucideLibrary, createShortcut, defaultSpriteBasePath, defaultSpriteConfigPath, defaultTreeItemSize, formatSize, kebabTestSegment, labelMarkupToHtml, labelMarkupToText, libIconMarker, parseLabelMarkup, parseSize, registerLucideIcons, scopeTestId, setupLucideIntegration, tnIconMarker, writeTestId };
9244
+ export type { AutocompleteHarnessFilters, BannerHarnessFilters, ButtonHarnessFilters, ButtonToggleHarnessFilters, CalendarCell, CheckboxHarnessFilters, ChipColor, ChipHarnessFilters, CreateFolderEvent, DateInputHarnessFilters, DateRange, DateRangeInputHarnessFilters, DialogHarnessFilters, EmptyHarnessFilters, ExpansionPanelHarnessFilters, FileInputHarnessFilters, FilePickerCallbacks, FilePickerError, FilePickerMode, FileSystemItem, FormFieldHarnessFilters, FormSectionHarnessFilters, IconButtonHarnessFilters, IconHarnessFilters, IconLibrary, IconLibraryType, IconResult, IconSize, IconSource, IconTestingMockOverrides, InputHarnessFilters, KeyCombination, LabelMarkupSegment, LabelMarkupSegmentType, LabelType, LucideIconOptions, MenuHarnessFilters, MockIconRegistry, MockSpriteLoader, PathSegment, PlatformType, ProgressBarMode, RadioHarnessFilters, ResolvedIcon, SelectHarnessFilters, ShortcutHandler, SidePanelHarnessFilters, SizeStandard, SlideToggleColor, SlideToggleHarnessFilters, SpinnerMode, SpriteConfig, StepperHarnessFilters, SubscriptSizing, TabChangeEvent, TabHarnessFilters, TabPanelHarnessFilters, TabsHarnessFilters, TnAutocompleteOption, TnBannerType, TnButtonToggleType, TnCardAction, TnCardControl, TnCardFooterLink, TnCardHeaderStatus, TnChipInputHarnessFilters, TnChipInputOption, TnConfirmDialogData, TnDialogDefaults, TnDialogOpenTarget, TnDrawerMode, TnDrawerPosition, TnEmptySize, TnFlatTreeNode, TnFormFieldErrorMessage, TnFormFieldErrorMessages, TnFormFieldErrorResolver, TnMenuItem, TnSelectOption, TnSelectOptionGroup, TnSelectionChange, TnSortEvent, TnTableDataProvider, TnTableDataSource, TnTableHarnessFilters, TnTablePagerHarnessFilters, TnTablePagerLabels, TnTablePagination, TnTestAttrName, TnTestIdValue, TnThemeDefinition, TnToastCall, TnToastConfig, TnTreeVirtualNodeData, TnTreeVirtualScrollViewHarnessFilters, TooltipPosition, YearCell };