@truenas/ui-components 0.3.23 → 0.3.25
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.
|
@@ -23,9 +23,9 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
|
23
23
|
import { trigger, state, transition, style, animate } from '@angular/animations';
|
|
24
24
|
import { SelectionModel, DataSource } from '@angular/cdk/collections';
|
|
25
25
|
import * as i2 from '@angular/cdk/tree';
|
|
26
|
-
import { CdkTree, CdkTreeModule, CdkTreeNode, CDK_TREE_NODE_OUTLET_NODE, CdkTreeNodeOutlet,
|
|
26
|
+
import { CdkTree, CdkTreeModule, CdkTreeNode, CDK_TREE_NODE_OUTLET_NODE, CdkNestedTreeNode, CdkTreeNodeOutlet, FlatTreeControl, NestedTreeControl, CdkTreeNodeOutletContext } from '@angular/cdk/tree';
|
|
27
27
|
export { FlatTreeControl } from '@angular/cdk/tree';
|
|
28
|
-
import { map, auditTime } from 'rxjs/operators';
|
|
28
|
+
import { map, filter, debounceTime, distinctUntilChanged, auditTime } from 'rxjs/operators';
|
|
29
29
|
import { CdkVirtualScrollViewport, CdkVirtualScrollableWindow, CdkFixedSizeVirtualScroll, CdkVirtualForOf, ScrollingModule } from '@angular/cdk/scrolling';
|
|
30
30
|
import { DialogRef, DIALOG_DATA, Dialog } from '@angular/cdk/dialog';
|
|
31
31
|
|
|
@@ -11676,23 +11676,41 @@ class TnTreeFlattener {
|
|
|
11676
11676
|
}
|
|
11677
11677
|
/**
|
|
11678
11678
|
* Data source for flat tree.
|
|
11679
|
+
*
|
|
11680
|
+
* Optionally supports client-side filtering and sorting: set `filterPredicate`
|
|
11681
|
+
* (and call `filter(query)`) and/or `sortComparer`. Both are opt-in; when unset
|
|
11682
|
+
* the datasource behaves exactly as before.
|
|
11679
11683
|
*/
|
|
11680
11684
|
class TnTreeFlatDataSource extends DataSource {
|
|
11681
11685
|
_treeControl;
|
|
11682
11686
|
_treeFlattener;
|
|
11687
|
+
/** When set, `filter(query)` re-renders the tree from `filterPredicate(data, query)`. */
|
|
11688
|
+
filterPredicate;
|
|
11689
|
+
/** When set, incoming `data` is sorted (top level) before flattening. */
|
|
11690
|
+
sortComparer;
|
|
11683
11691
|
_flattenedData = new BehaviorSubject([]);
|
|
11684
11692
|
_expandedData = new BehaviorSubject([]);
|
|
11685
11693
|
_data = new BehaviorSubject([]);
|
|
11694
|
+
_filteredData = new BehaviorSubject([]);
|
|
11695
|
+
filterValue = '';
|
|
11696
|
+
filterChanged$ = new BehaviorSubject('');
|
|
11686
11697
|
constructor(_treeControl, _treeFlattener) {
|
|
11687
11698
|
super();
|
|
11688
11699
|
this._treeControl = _treeControl;
|
|
11689
11700
|
this._treeFlattener = _treeFlattener;
|
|
11701
|
+
this.detectFilterChanges();
|
|
11690
11702
|
}
|
|
11691
11703
|
get data() { return this._data.value; }
|
|
11692
11704
|
set data(value) {
|
|
11693
|
-
this._data.next(value);
|
|
11694
|
-
|
|
11695
|
-
|
|
11705
|
+
this._data.next(this.sortComparer ? [...value].sort(this.sortComparer) : value);
|
|
11706
|
+
if (this.filterValue && this.filterPredicate) {
|
|
11707
|
+
this._filteredData.next(this.filterPredicate(this.data, this.filterValue));
|
|
11708
|
+
}
|
|
11709
|
+
this.flattenData();
|
|
11710
|
+
}
|
|
11711
|
+
/** The currently filtered (unflattened) data; equals `data` while no filter query is active. */
|
|
11712
|
+
get filteredData() {
|
|
11713
|
+
return this.filterValue ? this._filteredData.value : this.data;
|
|
11696
11714
|
}
|
|
11697
11715
|
connect() {
|
|
11698
11716
|
return merge(this._treeControl.expansionModel.changed, this._flattenedData).pipe(map(() => {
|
|
@@ -11701,6 +11719,31 @@ class TnTreeFlatDataSource extends DataSource {
|
|
|
11701
11719
|
}));
|
|
11702
11720
|
}
|
|
11703
11721
|
disconnect() { }
|
|
11722
|
+
/** Filters the tree using `filterPredicate` (debounced). No-op until `filterPredicate` is set. */
|
|
11723
|
+
filter(query) {
|
|
11724
|
+
this.filterChanged$.next(query);
|
|
11725
|
+
}
|
|
11726
|
+
flattenData() {
|
|
11727
|
+
this._flattenedData.next(this._treeFlattener.flattenNodes(this.filterValue ? this._filteredData.value : this.data));
|
|
11728
|
+
this._treeControl.dataNodes = this._flattenedData.value;
|
|
11729
|
+
}
|
|
11730
|
+
/**
|
|
11731
|
+
* Deliberately NOT torn down in `disconnect()`: CdkTree disconnects the
|
|
11732
|
+
* datasource when the tree is destroyed, but the same instance may be
|
|
11733
|
+
* reconnected (e.g. a tree behind an `@if`), and filtering must survive that.
|
|
11734
|
+
* The pipeline only references the datasource's own subjects, so it holds no
|
|
11735
|
+
* external resources and is collected with the instance.
|
|
11736
|
+
*/
|
|
11737
|
+
detectFilterChanges() {
|
|
11738
|
+
this.filterChanged$.pipe(filter(() => !!this.filterPredicate), debounceTime(200), distinctUntilChanged()).subscribe((changedValue) => {
|
|
11739
|
+
if (this.filterValue === changedValue || !this.filterPredicate) {
|
|
11740
|
+
return;
|
|
11741
|
+
}
|
|
11742
|
+
this.filterValue = changedValue;
|
|
11743
|
+
this._filteredData.next(this.filterPredicate(this.data, changedValue));
|
|
11744
|
+
this.flattenData();
|
|
11745
|
+
});
|
|
11746
|
+
}
|
|
11704
11747
|
_getExpandedNodesWithLevel() {
|
|
11705
11748
|
const expandedNodes = [];
|
|
11706
11749
|
const flatNodes = this._flattenedData.value;
|
|
@@ -11772,26 +11815,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
|
|
|
11772
11815
|
}, encapsulation: ViewEncapsulation.Emulated, changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- The `role=\"treeitem\"` (plus aria-level/aria-expanded) lives on the host\n `.tn-tree-node-wrapper`, so this inner div is a presentational container \u2014\n no role or aria-* here, to avoid exposing a second, nested treeitem to AT. -->\n<div class=\"tn-tree-node\"\n cdkTreeNodeToggle\n [class.tn-tree-node--expandable]=\"isExpandable\"\n [style.cursor]=\"isExpandable ? 'pointer' : 'default'\">\n \n <div class=\"tn-tree-node__content\">\n <!-- Arrow icon for expandable nodes -->\n @if (isExpandable) {\n <div\n class=\"tn-tree-node__toggle\"\n [class.tn-tree-node__toggle--expanded]=\"isExpanded\">\n <tn-icon\n library=\"mdi\"\n size=\"sm\"\n style=\"transition: transform 0.2s ease;\"\n [name]=\"isExpanded ? 'chevron-down' : 'chevron-right'\" />\n </div>\n }\n\n <!-- Spacer for non-expandable nodes -->\n @if (!isExpandable) {\n <div class=\"tn-tree-node__spacer\"></div>\n }\n \n <!-- Node content -->\n <div class=\"tn-tree-node__text\">\n <ng-content />\n </div>\n </div>\n</div>", styles: [":host{display:block}.tn-tree-node{border-bottom:1px solid var(--tn-lines);transition:background-color .2s ease}.tn-tree-node:hover{background-color:var(--tn-alt-bg2)}.tn-tree-node:last-child{border-bottom:none}.tn-tree-node--expandable{cursor:pointer}.tn-tree-node--expandable:hover{background-color:var(--tn-alt-bg2)}.tn-tree-node--expandable:active{background-color:var(--tn-alt-bg1)}.tn-tree-node__content{display:flex;align-items:center;gap:8px;min-height:48px;padding:12px 16px}.tn-tree-node__toggle{display:flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;border:none;background:none;color:var(--tn-fg2);cursor:pointer;border-radius:3px;transition:all .2s ease;flex-shrink:0}.tn-tree-node__toggle:hover{background-color:var(--tn-alt-bg2);color:var(--tn-fg1)}.tn-tree-node__toggle:focus{outline:2px solid var(--tn-primary);outline-offset:1px}.tn-tree-node__toggle svg{transition:transform .2s ease;transform:rotate(0)}.tn-tree-node__toggle--expanded svg{transform:rotate(90deg)}.tn-tree-node__spacer{width:24px;height:24px;flex-shrink:0}.tn-tree-node__text{flex:1;min-width:0;color:var(--tn-fg1)}.tn-tree-node__children{padding-left:24px}.tn-tree-invisible{display:none}\n"] }]
|
|
11773
11816
|
}], ctorParameters: () => [] });
|
|
11774
11817
|
|
|
11775
|
-
class TnTreeNodeOutletDirective {
|
|
11776
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnTreeNodeOutletDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
11777
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.0", type: TnTreeNodeOutletDirective, isStandalone: true, selector: "[tnTreeNodeOutlet]", hostDirectives: [{ directive: i2.CdkTreeNodeOutlet }], ngImport: i0 });
|
|
11778
|
-
}
|
|
11779
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnTreeNodeOutletDirective, decorators: [{
|
|
11780
|
-
type: Directive,
|
|
11781
|
-
args: [{
|
|
11782
|
-
selector: '[tnTreeNodeOutlet]',
|
|
11783
|
-
standalone: true,
|
|
11784
|
-
hostDirectives: [{
|
|
11785
|
-
directive: CdkTreeNodeOutlet,
|
|
11786
|
-
inputs: [],
|
|
11787
|
-
outputs: []
|
|
11788
|
-
}]
|
|
11789
|
-
}]
|
|
11790
|
-
}] });
|
|
11791
|
-
|
|
11792
11818
|
class TnNestedTreeNodeComponent extends CdkNestedTreeNode {
|
|
11819
|
+
/**
|
|
11820
|
+
* Accessible label for the built-in toggle button. Pass a translated string;
|
|
11821
|
+
* defaults to the previous hardcoded value.
|
|
11822
|
+
*/
|
|
11823
|
+
toggleAriaLabel = input('Toggle node', ...(ngDevMode ? [{ debugName: "toggleAriaLabel" }] : []));
|
|
11824
|
+
/** Semantic test-id base applied to the built-in toggle button (`button-` prefixed). */
|
|
11825
|
+
toggleTestId = input(...(ngDevMode ? [undefined, { debugName: "toggleTestId" }] : []));
|
|
11826
|
+
/**
|
|
11827
|
+
* Suppresses the built-in toggle button (and its alignment spacer) so the
|
|
11828
|
+
* consumer can render a fully custom toggle in the projected content.
|
|
11829
|
+
*
|
|
11830
|
+
* The built-in button is the only keyboard/AT-operable expand control this
|
|
11831
|
+
* component guarantees — when hiding it, the projected replacement must be
|
|
11832
|
+
* an accessible control (a real button with an aria-label, not a bare icon).
|
|
11833
|
+
*/
|
|
11834
|
+
hideToggle = input(false, { ...(ngDevMode ? { debugName: "hideToggle" } : {}), transform: booleanAttribute });
|
|
11835
|
+
changeDetectorRef = inject(ChangeDetectorRef);
|
|
11836
|
+
destroyed = false;
|
|
11793
11837
|
constructor() {
|
|
11794
11838
|
super(inject((ElementRef)), inject(CdkTree, { optional: true }), inject(CDK_TREE_NODE_OUTLET_NODE, { optional: true }), inject(ChangeDetectorRef, { optional: true }));
|
|
11839
|
+
inject(DestroyRef).onDestroy(() => this.destroyed = true);
|
|
11795
11840
|
}
|
|
11796
11841
|
/** The tree node's level in the tree */
|
|
11797
11842
|
get level() {
|
|
@@ -11799,11 +11844,10 @@ class TnNestedTreeNodeComponent extends CdkNestedTreeNode {
|
|
|
11799
11844
|
// Legacy treeControl approach
|
|
11800
11845
|
return this._tree.treeControl.getLevel(this.data);
|
|
11801
11846
|
}
|
|
11802
|
-
|
|
11803
|
-
|
|
11804
|
-
|
|
11805
|
-
|
|
11806
|
-
return 0;
|
|
11847
|
+
// CdkTreeNode's own getter: levelAccessor when available, else the parent
|
|
11848
|
+
// node's aria-level from the DOM — which is what makes nested trees (whose
|
|
11849
|
+
// NestedTreeControl has no getLevel) report correct levels.
|
|
11850
|
+
return this._tree ? super.level : 0;
|
|
11807
11851
|
}
|
|
11808
11852
|
/** Whether the tree node is expandable */
|
|
11809
11853
|
get isExpandable() {
|
|
@@ -11811,6 +11855,12 @@ class TnNestedTreeNodeComponent extends CdkNestedTreeNode {
|
|
|
11811
11855
|
// Legacy treeControl approach
|
|
11812
11856
|
return this._tree.treeControl.isExpandable(this.data);
|
|
11813
11857
|
}
|
|
11858
|
+
else if (this._tree?.treeControl) {
|
|
11859
|
+
// NestedTreeControl leaves `isExpandable` undefined unless configured —
|
|
11860
|
+
// fall back to its getChildren (synchronous arrays only).
|
|
11861
|
+
const children = this._tree.treeControl.getChildren?.(this.data);
|
|
11862
|
+
return Array.isArray(children) && children.length > 0;
|
|
11863
|
+
}
|
|
11814
11864
|
else if (this._tree && 'childrenAccessor' in this._tree && this._tree.childrenAccessor) {
|
|
11815
11865
|
// Modern childrenAccessor approach
|
|
11816
11866
|
const childrenAccessor = this._tree.childrenAccessor;
|
|
@@ -11835,24 +11885,348 @@ class TnNestedTreeNodeComponent extends CdkNestedTreeNode {
|
|
|
11835
11885
|
}
|
|
11836
11886
|
return false;
|
|
11837
11887
|
}
|
|
11888
|
+
/**
|
|
11889
|
+
* CDK inserts child node views synchronously from `ngAfterContentInit`, i.e.
|
|
11890
|
+
* mid-change-detection. Because the outlet here lives in PROJECTED content
|
|
11891
|
+
* whose view container has already been traversed for the current pass, the
|
|
11892
|
+
* new views would miss their first check and trip dev-mode NG0100. Defer the
|
|
11893
|
+
* insertion to a microtask so the views are created outside change detection
|
|
11894
|
+
* and get a normal first check on the pass that `markForCheck` schedules.
|
|
11895
|
+
*/
|
|
11896
|
+
updateChildrenNodes(children) {
|
|
11897
|
+
queueMicrotask(() => {
|
|
11898
|
+
if (this.destroyed) {
|
|
11899
|
+
return;
|
|
11900
|
+
}
|
|
11901
|
+
super.updateChildrenNodes(children);
|
|
11902
|
+
this.changeDetectorRef.markForCheck();
|
|
11903
|
+
});
|
|
11904
|
+
}
|
|
11905
|
+
/**
|
|
11906
|
+
* Toggles the node; with the Alt key held, toggles the node together with all
|
|
11907
|
+
* of its descendants. Replaces `cdkTreeNodeToggle` on the built-in button so
|
|
11908
|
+
* the Alt behavior is deterministic (a stacked template listener would run in
|
|
11909
|
+
* an unspecified order relative to the CDK toggle's own click handler).
|
|
11910
|
+
*/
|
|
11911
|
+
toggleNode(event) {
|
|
11912
|
+
if (!this._tree) {
|
|
11913
|
+
return;
|
|
11914
|
+
}
|
|
11915
|
+
if ('altKey' in event && event.altKey) {
|
|
11916
|
+
this._tree.toggleDescendants(this.data);
|
|
11917
|
+
}
|
|
11918
|
+
else {
|
|
11919
|
+
this._tree.toggle(this.data);
|
|
11920
|
+
}
|
|
11921
|
+
// Mirrors CdkTreeNodeToggle's focus handling. `_keyManager` is a CDK
|
|
11922
|
+
// underscore member, so a CDK upgrade may rename it — the optional call
|
|
11923
|
+
// degrades to "focus not moved" rather than breaking the toggle.
|
|
11924
|
+
this._tree._keyManager?.focusItem(this);
|
|
11925
|
+
}
|
|
11838
11926
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnNestedTreeNodeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11839
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnNestedTreeNodeComponent, isStandalone: true, selector: "tn-nested-tree-node", host: { attributes: { "role": "treeitem" }, properties: { "attr.aria-level": "level + 1", "attr.aria-expanded": "isExpandable ? isExpanded : null" }, classAttribute: "tn-nested-tree-node-wrapper" }, providers: [
|
|
11927
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnNestedTreeNodeComponent, isStandalone: true, selector: "tn-nested-tree-node", inputs: { toggleAriaLabel: { classPropertyName: "toggleAriaLabel", publicName: "toggleAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, toggleTestId: { classPropertyName: "toggleTestId", publicName: "toggleTestId", isSignal: true, isRequired: false, transformFunction: null }, hideToggle: { classPropertyName: "hideToggle", publicName: "hideToggle", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "treeitem" }, properties: { "attr.aria-level": "level + 1", "attr.aria-expanded": "isExpandable ? isExpanded : null" }, classAttribute: "tn-nested-tree-node-wrapper" }, providers: [
|
|
11840
11928
|
{ provide: CdkNestedTreeNode, useExisting: TnNestedTreeNodeComponent },
|
|
11841
11929
|
{ provide: CdkTreeNode, useExisting: TnNestedTreeNodeComponent }
|
|
11842
|
-
], exportAs: ["tnNestedTreeNode"], usesInheritance: true, ngImport: i0, template: "<div class=\"tn-nested-tree-node__content\">\n <!-- Toggle button for expandable nodes (provided by component) -->\n
|
|
11930
|
+
], exportAs: ["tnNestedTreeNode"], usesInheritance: true, hostDirectives: [{ directive: TnTestIdDirective, inputs: ["tnTestId", "testId"] }], ngImport: i0, template: "<div class=\"tn-nested-tree-node__content\">\n @if (!hideToggle()) {\n <!-- Toggle button for expandable nodes (provided by component).\n Alt+click / Alt+Enter toggles the node together with all descendants.\n tabindex=\"-1\" keeps it out of the tab order \u2014 the tree's key manager\n drives focus at the treeitem level, matching cdkTreeNodeToggle. -->\n @if (isExpandable) {\n <button\n class=\"tn-nested-tree-node__toggle\"\n type=\"button\"\n tabindex=\"-1\"\n tnTestIdType=\"button\"\n [tnTestId]=\"toggleTestId()\"\n [class.tn-nested-tree-node__toggle--expanded]=\"isExpanded\"\n [attr.aria-label]=\"toggleAriaLabel()\"\n (click)=\"toggleNode($event); $event.stopPropagation()\"\n (keydown.enter)=\"toggleNode($event); $event.preventDefault()\"\n (keydown.space)=\"toggleNode($event); $event.preventDefault()\">\n <tn-icon\n library=\"mdi\"\n size=\"sm\"\n style=\"transition: transform 0.2s ease;\"\n [name]=\"isExpanded ? 'chevron-down' : 'chevron-right'\" />\n </button>\n }\n\n <!-- Spacer for non-expandable nodes to maintain alignment -->\n @if (!isExpandable) {\n <div class=\"tn-nested-tree-node__spacer\"></div>\n }\n }\n\n <!-- Consumer content -->\n <ng-content />\n</div>\n\n<!-- Children container -->\n@if (isExpandable) {\n <div class=\"tn-nested-tree-node-container\" role=\"group\" [class.tn-tree-invisible]=\"!isExpanded\">\n <ng-content select=\"[slot=children]\" />\n </div>\n}\n", styles: [".tn-nested-tree-node-wrapper{display:block;width:100%}.tn-nested-tree-node{display:block;width:100%;font-family:var(--tn-font-family-body);font-size:1rem;line-height:1.4;color:var(--tn-fg1)}.tn-nested-tree-node--expandable .tn-nested-tree-node__content{cursor:pointer}.tn-nested-tree-node__content{display:flex;align-items:center;gap:8px;min-height:48px;padding:12px 16px;border-bottom:1px solid var(--tn-lines);transition:background-color .2s ease}.tn-nested-tree-node__content:hover{background-color:var(--tn-alt-bg2)}.tn-nested-tree-node__content:focus-within{background-color:var(--tn-alt-bg2);outline:2px solid var(--tn-primary);outline-offset:-2px}.tn-tree-invisible{display:none}.tn-nested-tree-node__toggle{display:flex;align-items:center;justify-content:center;width:24px;height:24px;margin-right:8px;padding:0;border:none;background:transparent;border-radius:4px;cursor:pointer;color:var(--tn-fg2);transition:background-color .2s ease,color .2s ease}.tn-nested-tree-node__toggle:hover{background-color:var(--tn-bg3);color:var(--tn-fg1)}.tn-nested-tree-node__toggle:focus{outline:2px solid var(--tn-primary);outline-offset:2px}.tn-nested-tree-node__toggle svg{transition:transform .2s ease}.tn-nested-tree-node__toggle--expanded svg{transform:rotate(90deg)}.tn-nested-tree-node__spacer{width:24px;height:24px;flex-shrink:0}.tn-nested-tree-node__text{flex:1;display:flex;align-items:center;gap:8px;min-width:0;color:var(--tn-fg1)}div.tn-nested-tree-node-container{padding-left:40px}@media(prefers-reduced-motion:reduce){.tn-nested-tree-node__toggle svg,.tn-nested-tree-node__content,.tn-nested-tree-node__children{transition:none}}@media(prefers-contrast:high){.tn-nested-tree-node__content{border:1px solid transparent}.tn-nested-tree-node__content:hover,.tn-nested-tree-node__content:focus-within{border-color:var(--tn-fg1)}.tn-nested-tree-node__toggle{border:1px solid var(--tn-fg2)}.tn-nested-tree-node__toggle:hover,.tn-nested-tree-node__toggle:focus{border-color:var(--tn-fg1)}}\n"], dependencies: [{ kind: "component", type: TnIconComponent, selector: "tn-icon", inputs: ["name", "size", "color", "tooltip", "ariaLabel", "library", "testId", "fullSize", "customSize"] }, { kind: "directive", type: TnTestIdDirective, selector: "[tnTestId]", inputs: ["tnTestId", "tnTestIdType"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
11843
11931
|
}
|
|
11844
11932
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnNestedTreeNodeComponent, decorators: [{
|
|
11845
11933
|
type: Component,
|
|
11846
|
-
args: [{ selector: 'tn-nested-tree-node', standalone: true, imports: [
|
|
11934
|
+
args: [{ selector: 'tn-nested-tree-node', standalone: true, imports: [TnIconComponent, TnTestIdDirective], exportAs: 'tnNestedTreeNode', providers: [
|
|
11847
11935
|
{ provide: CdkNestedTreeNode, useExisting: TnNestedTreeNodeComponent },
|
|
11848
11936
|
{ provide: CdkTreeNode, useExisting: TnNestedTreeNodeComponent }
|
|
11849
|
-
], host: {
|
|
11937
|
+
], hostDirectives: [{ directive: TnTestIdDirective, inputs: ['tnTestId: testId'] }], host: {
|
|
11850
11938
|
'class': 'tn-nested-tree-node-wrapper',
|
|
11851
11939
|
'[attr.aria-level]': 'level + 1',
|
|
11852
11940
|
'[attr.aria-expanded]': 'isExpandable ? isExpanded : null',
|
|
11853
11941
|
'role': 'treeitem'
|
|
11854
|
-
}, encapsulation: ViewEncapsulation.Emulated, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"tn-nested-tree-node__content\">\n <!-- Toggle button for expandable nodes (provided by component) -->\n
|
|
11855
|
-
}], ctorParameters: () => [] });
|
|
11942
|
+
}, encapsulation: ViewEncapsulation.Emulated, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"tn-nested-tree-node__content\">\n @if (!hideToggle()) {\n <!-- Toggle button for expandable nodes (provided by component).\n Alt+click / Alt+Enter toggles the node together with all descendants.\n tabindex=\"-1\" keeps it out of the tab order \u2014 the tree's key manager\n drives focus at the treeitem level, matching cdkTreeNodeToggle. -->\n @if (isExpandable) {\n <button\n class=\"tn-nested-tree-node__toggle\"\n type=\"button\"\n tabindex=\"-1\"\n tnTestIdType=\"button\"\n [tnTestId]=\"toggleTestId()\"\n [class.tn-nested-tree-node__toggle--expanded]=\"isExpanded\"\n [attr.aria-label]=\"toggleAriaLabel()\"\n (click)=\"toggleNode($event); $event.stopPropagation()\"\n (keydown.enter)=\"toggleNode($event); $event.preventDefault()\"\n (keydown.space)=\"toggleNode($event); $event.preventDefault()\">\n <tn-icon\n library=\"mdi\"\n size=\"sm\"\n style=\"transition: transform 0.2s ease;\"\n [name]=\"isExpanded ? 'chevron-down' : 'chevron-right'\" />\n </button>\n }\n\n <!-- Spacer for non-expandable nodes to maintain alignment -->\n @if (!isExpandable) {\n <div class=\"tn-nested-tree-node__spacer\"></div>\n }\n }\n\n <!-- Consumer content -->\n <ng-content />\n</div>\n\n<!-- Children container -->\n@if (isExpandable) {\n <div class=\"tn-nested-tree-node-container\" role=\"group\" [class.tn-tree-invisible]=\"!isExpanded\">\n <ng-content select=\"[slot=children]\" />\n </div>\n}\n", styles: [".tn-nested-tree-node-wrapper{display:block;width:100%}.tn-nested-tree-node{display:block;width:100%;font-family:var(--tn-font-family-body);font-size:1rem;line-height:1.4;color:var(--tn-fg1)}.tn-nested-tree-node--expandable .tn-nested-tree-node__content{cursor:pointer}.tn-nested-tree-node__content{display:flex;align-items:center;gap:8px;min-height:48px;padding:12px 16px;border-bottom:1px solid var(--tn-lines);transition:background-color .2s ease}.tn-nested-tree-node__content:hover{background-color:var(--tn-alt-bg2)}.tn-nested-tree-node__content:focus-within{background-color:var(--tn-alt-bg2);outline:2px solid var(--tn-primary);outline-offset:-2px}.tn-tree-invisible{display:none}.tn-nested-tree-node__toggle{display:flex;align-items:center;justify-content:center;width:24px;height:24px;margin-right:8px;padding:0;border:none;background:transparent;border-radius:4px;cursor:pointer;color:var(--tn-fg2);transition:background-color .2s ease,color .2s ease}.tn-nested-tree-node__toggle:hover{background-color:var(--tn-bg3);color:var(--tn-fg1)}.tn-nested-tree-node__toggle:focus{outline:2px solid var(--tn-primary);outline-offset:2px}.tn-nested-tree-node__toggle svg{transition:transform .2s ease}.tn-nested-tree-node__toggle--expanded svg{transform:rotate(90deg)}.tn-nested-tree-node__spacer{width:24px;height:24px;flex-shrink:0}.tn-nested-tree-node__text{flex:1;display:flex;align-items:center;gap:8px;min-width:0;color:var(--tn-fg1)}div.tn-nested-tree-node-container{padding-left:40px}@media(prefers-reduced-motion:reduce){.tn-nested-tree-node__toggle svg,.tn-nested-tree-node__content,.tn-nested-tree-node__children{transition:none}}@media(prefers-contrast:high){.tn-nested-tree-node__content{border:1px solid transparent}.tn-nested-tree-node__content:hover,.tn-nested-tree-node__content:focus-within{border-color:var(--tn-fg1)}.tn-nested-tree-node__toggle{border:1px solid var(--tn-fg2)}.tn-nested-tree-node__toggle:hover,.tn-nested-tree-node__toggle:focus{border-color:var(--tn-fg1)}}\n"] }]
|
|
11943
|
+
}], ctorParameters: () => [], propDecorators: { toggleAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "toggleAriaLabel", required: false }] }], toggleTestId: [{ type: i0.Input, args: [{ isSignal: true, alias: "toggleTestId", required: false }] }], hideToggle: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideToggle", required: false }] }] } });
|
|
11944
|
+
|
|
11945
|
+
class TnTreeNodeOutletDirective {
|
|
11946
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnTreeNodeOutletDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
11947
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.0", type: TnTreeNodeOutletDirective, isStandalone: true, selector: "[tnTreeNodeOutlet]", hostDirectives: [{ directive: i2.CdkTreeNodeOutlet }], ngImport: i0 });
|
|
11948
|
+
}
|
|
11949
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnTreeNodeOutletDirective, decorators: [{
|
|
11950
|
+
type: Directive,
|
|
11951
|
+
args: [{
|
|
11952
|
+
selector: '[tnTreeNodeOutlet]',
|
|
11953
|
+
standalone: true,
|
|
11954
|
+
hostDirectives: [{
|
|
11955
|
+
directive: CdkTreeNodeOutlet,
|
|
11956
|
+
inputs: [],
|
|
11957
|
+
outputs: []
|
|
11958
|
+
}]
|
|
11959
|
+
}]
|
|
11960
|
+
}] });
|
|
11961
|
+
|
|
11962
|
+
/**
|
|
11963
|
+
* Data source for nested trees (`tn-nested-tree-node`).
|
|
11964
|
+
*
|
|
11965
|
+
* Optionally supports client-side filtering and sorting: set `filterPredicate`
|
|
11966
|
+
* (and call `filter(query)`) and/or `sortComparer` (applied recursively through
|
|
11967
|
+
* `children`). Both are opt-in.
|
|
11968
|
+
*/
|
|
11969
|
+
class TnNestedTreeDataSource extends DataSource {
|
|
11970
|
+
/** When set, `filter(query)` re-renders the tree from `filterPredicate(data, query)`. */
|
|
11971
|
+
filterPredicate;
|
|
11972
|
+
/**
|
|
11973
|
+
* When set, incoming `data` is sorted recursively before rendering.
|
|
11974
|
+
*
|
|
11975
|
+
* Note: sorting REWRITES `children` arrays on the caller's node objects
|
|
11976
|
+
* (a new sorted array is assigned per node). Node object identity is
|
|
11977
|
+
* preserved — deliberately, since tree controls track expansion state by
|
|
11978
|
+
* node identity — but don't pass an object graph that is shared with code
|
|
11979
|
+
* relying on the original child order.
|
|
11980
|
+
*/
|
|
11981
|
+
sortComparer;
|
|
11982
|
+
filterValue = '';
|
|
11983
|
+
filterChanged$ = new BehaviorSubject('');
|
|
11984
|
+
_data = new BehaviorSubject([]);
|
|
11985
|
+
_filteredData = new BehaviorSubject([]);
|
|
11986
|
+
get data() {
|
|
11987
|
+
return this._data.value;
|
|
11988
|
+
}
|
|
11989
|
+
set data(value) {
|
|
11990
|
+
this._data.next(this.sortComparer ? this.sort(value) : value);
|
|
11991
|
+
}
|
|
11992
|
+
constructor(initialData) {
|
|
11993
|
+
super();
|
|
11994
|
+
if (initialData) {
|
|
11995
|
+
this.data = initialData;
|
|
11996
|
+
}
|
|
11997
|
+
this.detectFilterChanges();
|
|
11998
|
+
}
|
|
11999
|
+
connect(collectionViewer) {
|
|
12000
|
+
return merge(collectionViewer.viewChange, this._data, this._filteredData).pipe(map(() => (this.filterValue ? this._filteredData.value : this.data)));
|
|
12001
|
+
}
|
|
12002
|
+
disconnect() { }
|
|
12003
|
+
/** Filters the tree using `filterPredicate` (debounced). No-op until `filterPredicate` is set. */
|
|
12004
|
+
filter(query) {
|
|
12005
|
+
this.filterChanged$.next(query);
|
|
12006
|
+
}
|
|
12007
|
+
/**
|
|
12008
|
+
* Deliberately NOT torn down in `disconnect()`: CdkTree disconnects the
|
|
12009
|
+
* datasource when the tree is destroyed, but the same instance may be
|
|
12010
|
+
* reconnected (e.g. a tree behind an `@if`), and filtering must survive that.
|
|
12011
|
+
* The pipeline only references the datasource's own subjects, so it holds no
|
|
12012
|
+
* external resources and is collected with the instance.
|
|
12013
|
+
*/
|
|
12014
|
+
detectFilterChanges() {
|
|
12015
|
+
this.filterChanged$.pipe(filter(() => !!this.filterPredicate), debounceTime(200), distinctUntilChanged()).subscribe((changedValue) => {
|
|
12016
|
+
if (this.filterValue === changedValue || !this.filterPredicate) {
|
|
12017
|
+
return;
|
|
12018
|
+
}
|
|
12019
|
+
this.filterValue = changedValue;
|
|
12020
|
+
this._filteredData.next(this.filterPredicate(this.data, changedValue));
|
|
12021
|
+
});
|
|
12022
|
+
}
|
|
12023
|
+
sort(value) {
|
|
12024
|
+
return [...value].sort(this.sortComparer).map((item) => {
|
|
12025
|
+
if (item.children?.length) {
|
|
12026
|
+
item.children = this.sort(item.children);
|
|
12027
|
+
}
|
|
12028
|
+
return item;
|
|
12029
|
+
});
|
|
12030
|
+
}
|
|
12031
|
+
}
|
|
12032
|
+
|
|
12033
|
+
/**
|
|
12034
|
+
* Creates a flat tree control for managing expansion state of flat tree structures.
|
|
12035
|
+
*
|
|
12036
|
+
* @param getLevel - Function that returns the level/depth of a node
|
|
12037
|
+
* @param isExpandable - Function that returns whether a node can be expanded
|
|
12038
|
+
* @param options - Optional configuration including trackBy function
|
|
12039
|
+
* @returns TnTreeExpansion instance for managing tree state
|
|
12040
|
+
*
|
|
12041
|
+
* @example
|
|
12042
|
+
* ```ts
|
|
12043
|
+
* const treeControl = createFlatTreeControl<DatasetDetails, string>(
|
|
12044
|
+
* (dataset) => (dataset?.name?.split('/')?.length || 0) - 1,
|
|
12045
|
+
* (dataset) => Number(dataset?.children?.length) > 0,
|
|
12046
|
+
* { trackBy: (dataset) => dataset.id }
|
|
12047
|
+
* );
|
|
12048
|
+
* ```
|
|
12049
|
+
*/
|
|
12050
|
+
function createFlatTreeControl(getLevel, isExpandable, options) {
|
|
12051
|
+
return new FlatTreeControl(getLevel, isExpandable, options);
|
|
12052
|
+
}
|
|
12053
|
+
/**
|
|
12054
|
+
* Creates a nested tree control for managing expansion state of nested tree structures.
|
|
12055
|
+
*
|
|
12056
|
+
* @param getChildren - Function that returns the children of a node
|
|
12057
|
+
* @param options - Optional configuration including isExpandable and trackBy functions
|
|
12058
|
+
* @returns TnTreeExpansion instance for managing tree state
|
|
12059
|
+
*
|
|
12060
|
+
* @example
|
|
12061
|
+
* ```ts
|
|
12062
|
+
* const treeControl = createNestedTreeControl<VDevNode, string>(
|
|
12063
|
+
* (vdev) => vdev.children,
|
|
12064
|
+
* { trackBy: (vdev) => vdev.guid }
|
|
12065
|
+
* );
|
|
12066
|
+
* ```
|
|
12067
|
+
*/
|
|
12068
|
+
function createNestedTreeControl(getChildren, options) {
|
|
12069
|
+
// NestedTreeControl leaves `isExpandable` undefined unless provided, which
|
|
12070
|
+
// reads as "every node is a leaf" — default it from getChildren (sync arrays).
|
|
12071
|
+
const isExpandable = options?.isExpandable
|
|
12072
|
+
?? ((dataNode) => {
|
|
12073
|
+
const children = getChildren(dataNode);
|
|
12074
|
+
return Array.isArray(children) && children.length > 0;
|
|
12075
|
+
});
|
|
12076
|
+
return new NestedTreeControl(getChildren, { ...options, isExpandable });
|
|
12077
|
+
}
|
|
12078
|
+
|
|
12079
|
+
/**
|
|
12080
|
+
* Harness for interacting with a single `tn-tree-node` or `tn-nested-tree-node`.
|
|
12081
|
+
*
|
|
12082
|
+
* Levels are 0-based (root nodes are level 0), matching the values consumers pass
|
|
12083
|
+
* to tree controls — the DOM's 1-based `aria-level` is converted internally.
|
|
12084
|
+
*/
|
|
12085
|
+
class TnTreeNodeHarness extends ComponentHarness {
|
|
12086
|
+
static hostSelector = '.tn-tree-node-wrapper, .tn-nested-tree-node-wrapper';
|
|
12087
|
+
/** The built-in nested-node toggle button (absent on flat nodes, leaves, and `hideToggle` nodes). */
|
|
12088
|
+
nestedToggle = this.locatorForOptional('.tn-nested-tree-node__toggle');
|
|
12089
|
+
/** The flat node's row, which acts as its toggle surface. */
|
|
12090
|
+
flatRow = this.locatorForOptional('.tn-tree-node');
|
|
12091
|
+
/**
|
|
12092
|
+
* Gets a `HarnessPredicate` that can be used to search for a tree node with
|
|
12093
|
+
* specific attributes.
|
|
12094
|
+
*
|
|
12095
|
+
* @param options Options for filtering which instances are considered a match.
|
|
12096
|
+
* @returns A `HarnessPredicate` configured with the given options.
|
|
12097
|
+
*/
|
|
12098
|
+
static with(options = {}) {
|
|
12099
|
+
return new HarnessPredicate(TnTreeNodeHarness, options)
|
|
12100
|
+
.addOption('text', options.text, (harness, text) => HarnessPredicate.stringMatches(harness.getText(), text))
|
|
12101
|
+
.addOption('expanded', options.expanded, async (harness, expanded) => (await harness.isExpanded()) === expanded)
|
|
12102
|
+
.addOption('level', options.level, async (harness, level) => (await harness.getLevel()) === level);
|
|
12103
|
+
}
|
|
12104
|
+
/**
|
|
12105
|
+
* Gets the node's own text, excluding any descendant tree nodes and the
|
|
12106
|
+
* built-in toggle button.
|
|
12107
|
+
*
|
|
12108
|
+
* @returns Promise resolving to the node's text.
|
|
12109
|
+
*/
|
|
12110
|
+
async getText() {
|
|
12111
|
+
return (await this.host()).text({
|
|
12112
|
+
exclude: '.tn-tree-node-wrapper, .tn-nested-tree-node-wrapper, button',
|
|
12113
|
+
});
|
|
12114
|
+
}
|
|
12115
|
+
/**
|
|
12116
|
+
* Gets the node's 0-based level (root nodes are 0).
|
|
12117
|
+
*
|
|
12118
|
+
* @returns Promise resolving to the level.
|
|
12119
|
+
*/
|
|
12120
|
+
async getLevel() {
|
|
12121
|
+
const ariaLevel = await (await this.host()).getAttribute('aria-level');
|
|
12122
|
+
return Number(ariaLevel) - 1;
|
|
12123
|
+
}
|
|
12124
|
+
/**
|
|
12125
|
+
* Whether the node is expandable (advertises `aria-expanded`).
|
|
12126
|
+
*
|
|
12127
|
+
* @returns Promise resolving to true if the node is expandable.
|
|
12128
|
+
*/
|
|
12129
|
+
async isExpandable() {
|
|
12130
|
+
return (await (await this.host()).getAttribute('aria-expanded')) !== null;
|
|
12131
|
+
}
|
|
12132
|
+
/**
|
|
12133
|
+
* Whether an expandable node is currently expanded.
|
|
12134
|
+
*
|
|
12135
|
+
* @returns Promise resolving to true if `aria-expanded="true"`.
|
|
12136
|
+
*/
|
|
12137
|
+
async isExpanded() {
|
|
12138
|
+
return (await (await this.host()).getAttribute('aria-expanded')) === 'true';
|
|
12139
|
+
}
|
|
12140
|
+
/**
|
|
12141
|
+
* Toggles the node's expansion by clicking its toggle surface — the built-in
|
|
12142
|
+
* toggle button on a nested node, or the row itself on a flat node. Throws for
|
|
12143
|
+
* nested nodes rendered with `hideToggle` (interact with the custom toggle
|
|
12144
|
+
* directly in that case).
|
|
12145
|
+
*/
|
|
12146
|
+
async toggle() {
|
|
12147
|
+
await (await this.getToggle()).click();
|
|
12148
|
+
}
|
|
12149
|
+
/**
|
|
12150
|
+
* Toggles the node together with all of its descendants (Alt+click on the
|
|
12151
|
+
* built-in nested-node toggle).
|
|
12152
|
+
*
|
|
12153
|
+
* Only nested nodes honor the Alt modifier — on a flat node the row's
|
|
12154
|
+
* `cdkTreeNodeToggle` is not Alt-aware, so this degrades to a plain
|
|
12155
|
+
* single-level toggle.
|
|
12156
|
+
*/
|
|
12157
|
+
async toggleWithDescendants() {
|
|
12158
|
+
await (await this.getToggle()).click({ alt: true });
|
|
12159
|
+
}
|
|
12160
|
+
/**
|
|
12161
|
+
* Expands the node if it is expandable and currently collapsed.
|
|
12162
|
+
*/
|
|
12163
|
+
async expand() {
|
|
12164
|
+
if ((await this.isExpandable()) && !(await this.isExpanded())) {
|
|
12165
|
+
await this.toggle();
|
|
12166
|
+
}
|
|
12167
|
+
}
|
|
12168
|
+
/**
|
|
12169
|
+
* Collapses the node if it is currently expanded.
|
|
12170
|
+
*/
|
|
12171
|
+
async collapse() {
|
|
12172
|
+
if (await this.isExpanded()) {
|
|
12173
|
+
await this.toggle();
|
|
12174
|
+
}
|
|
12175
|
+
}
|
|
12176
|
+
async getToggle() {
|
|
12177
|
+
const toggle = (await this.nestedToggle()) ?? (await this.flatRow());
|
|
12178
|
+
if (!toggle) {
|
|
12179
|
+
throw new Error('Node has no toggle surface (nested node with hideToggle?)');
|
|
12180
|
+
}
|
|
12181
|
+
return toggle;
|
|
12182
|
+
}
|
|
12183
|
+
}
|
|
12184
|
+
/**
|
|
12185
|
+
* Harness for interacting with `tn-tree` in tests.
|
|
12186
|
+
*
|
|
12187
|
+
* @example
|
|
12188
|
+
* ```typescript
|
|
12189
|
+
* const tree = await loader.getHarness(TnTreeHarness);
|
|
12190
|
+
* const roots = await tree.getNodes({ level: 0 });
|
|
12191
|
+
* await roots[0].expand();
|
|
12192
|
+
* expect(await tree.getNodeTexts()).toContain('child');
|
|
12193
|
+
* ```
|
|
12194
|
+
*/
|
|
12195
|
+
class TnTreeHarness extends ComponentHarness {
|
|
12196
|
+
static hostSelector = 'tn-tree';
|
|
12197
|
+
/**
|
|
12198
|
+
* Gets a `HarnessPredicate` that can be used to search for a tree with
|
|
12199
|
+
* specific attributes.
|
|
12200
|
+
*
|
|
12201
|
+
* @param options Options for filtering which instances are considered a match.
|
|
12202
|
+
* @returns A `HarnessPredicate` configured with the given options.
|
|
12203
|
+
*/
|
|
12204
|
+
static with(options = {}) {
|
|
12205
|
+
return new HarnessPredicate(TnTreeHarness, options);
|
|
12206
|
+
}
|
|
12207
|
+
/**
|
|
12208
|
+
* Gets the harnesses for the tree's nodes (all levels, in document order).
|
|
12209
|
+
*
|
|
12210
|
+
* Note: nested trees render collapsed subtrees into the DOM (hidden via CSS),
|
|
12211
|
+
* so nodes under a collapsed parent are still returned — filter by `level` or
|
|
12212
|
+
* check the parent's `isExpanded()` when visibility matters.
|
|
12213
|
+
*
|
|
12214
|
+
* @param filter Optional filter to narrow the nodes.
|
|
12215
|
+
* @returns Promise resolving to the matching node harnesses.
|
|
12216
|
+
*/
|
|
12217
|
+
async getNodes(filter = {}) {
|
|
12218
|
+
return this.locatorForAll(TnTreeNodeHarness.with(filter))();
|
|
12219
|
+
}
|
|
12220
|
+
/**
|
|
12221
|
+
* Gets the text of every node currently rendered, in document order.
|
|
12222
|
+
*
|
|
12223
|
+
* @returns Promise resolving to an array of node texts.
|
|
12224
|
+
*/
|
|
12225
|
+
async getNodeTexts() {
|
|
12226
|
+
const nodes = await this.getNodes();
|
|
12227
|
+
return Promise.all(nodes.map((node) => node.getText()));
|
|
12228
|
+
}
|
|
12229
|
+
}
|
|
11856
12230
|
|
|
11857
12231
|
/**
|
|
11858
12232
|
* Renders a single virtual tree row.
|
|
@@ -18857,5 +19231,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
|
|
|
18857
19231
|
* Generated bundle index. Do not edit.
|
|
18858
19232
|
*/
|
|
18859
19233
|
|
|
18860
|
-
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_CONTEXT, 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, injectTnFormFieldAria, kebabTestSegment, labelMarkupToHtml, labelMarkupToText, libIconMarker, optionTestId, parseLabelMarkup, parseSize, registerLucideIcons, scopeTestId, setupLucideIntegration, tnIconMarker, writeTestId };
|
|
19234
|
+
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_CONTEXT, 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, TnNestedTreeDataSource, 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, TnTreeHarness, TnTreeNodeComponent, TnTreeNodeHarness, TnTreeNodeOutletDirective, TnTreeVirtualScrollNodeOutletDirective, TnTreeVirtualScrollViewComponent, TnTreeVirtualScrollViewHarness, TruncatePathPipe, WindowsModifierKeys, WindowsShortcuts, composeTestId, controlTestId, createFlatTreeControl, createLucideLibrary, createNestedTreeControl, createShortcut, defaultSpriteBasePath, defaultSpriteConfigPath, defaultTreeItemSize, formatSize, injectTnFormFieldAria, kebabTestSegment, labelMarkupToHtml, labelMarkupToText, libIconMarker, optionTestId, parseLabelMarkup, parseSize, registerLucideIcons, scopeTestId, setupLucideIntegration, tnIconMarker, writeTestId };
|
|
18861
19235
|
//# sourceMappingURL=truenas-ui-components.mjs.map
|