@acorex/components 21.0.0-next.36 → 21.0.0-next.38

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.
@@ -1,505 +1,1231 @@
1
- import { AXClickEvent, NXComponent, AXComponent, AXCommonModule } from '@acorex/cdk/common';
2
- import { AXLoadingComponent, AXLoadingModule } from '@acorex/components/loading';
3
- import { AXTooltipDirective, AXTooltipModule } from '@acorex/components/tooltip';
1
+ import { moveItemInArray, transferArrayItem, AXDragDirective, AXDragHandleDirective, AXDropListDirective } from '@acorex/cdk/drag-drop';
2
+ import { AXFocusTrapDirective } from '@acorex/cdk/focus-trap';
3
+ import { AXBadgeComponent } from '@acorex/components/badge';
4
+ import { AXButtonComponent } from '@acorex/components/button';
5
+ import { AXCheckBoxComponent } from '@acorex/components/check-box';
6
+ import { AXDecoratorIconComponent } from '@acorex/components/decorators';
4
7
  import { AXPlatform } from '@acorex/core/platform';
5
- import { AXTranslatorPipe } from '@acorex/core/translation';
6
8
  import * as i1 from '@angular/common';
7
- import { CommonModule, NgTemplateOutlet, AsyncPipe } from '@angular/common';
9
+ import { CommonModule, NgTemplateOutlet } from '@angular/common';
8
10
  import * as i0 from '@angular/core';
9
- import { inject, input, model, computed, ChangeDetectionStrategy, ViewEncapsulation, Component, signal, output, effect, Input, HostBinding, NgModule } from '@angular/core';
10
- import { AXCheckBoxComponent, AXCheckBoxModule } from '@acorex/components/check-box';
11
- import { AXDecoratorGenericComponent, AXDecoratorIconComponent, AXDecoratorModule } from '@acorex/components/decorators';
12
- import * as i1$1 from '@angular/forms';
11
+ import { Injectable, inject, DestroyRef, model, input, output, signal, computed, effect, afterNextRender, ViewEncapsulation, ChangeDetectionStrategy, Component, NgModule } from '@angular/core';
12
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
13
+ import * as i2 from '@angular/forms';
13
14
  import { FormsModule } from '@angular/forms';
14
- import { AXFormModule } from '@acorex/components/form';
15
+ import { map } from 'rxjs/operators';
15
16
 
16
- class AXTreeItemClickBaseEvent extends AXClickEvent {
17
- }
18
- class AXTreeViewBase {
19
- }
20
-
21
- class AXTreeViewItemComponent extends NXComponent {
22
- constructor() {
23
- super();
24
- this.treeView = inject(AXTreeViewBase);
25
- this.item = input(...(ngDevMode ? [undefined, { debugName: "item" }] : []));
26
- this.isExpanded = model(false, ...(ngDevMode ? [{ debugName: "isExpanded" }] : []));
27
- this.isActive = model(false, ...(ngDevMode ? [{ debugName: "isActive" }] : []));
28
- this.isLoading = input(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
29
- this.executorChanges = input(...(ngDevMode ? [undefined, { debugName: "executorChanges" }] : []));
30
- this.platformService = inject(AXPlatform);
31
- this.arrowIcon = computed(() => {
32
- const baseClasses = 'ax-tree-view-arrow ax-icon ax-icon-solid';
33
- const toggleIcons = this.treeView.toggleIcons();
34
- if (toggleIcons) {
35
- return this.isExpanded() ? `${baseClasses} ${toggleIcons.expanded}` : `${baseClasses} ${toggleIcons.collapsed}`;
36
- }
37
- if (this.isExpanded()) {
38
- return `${baseClasses} ax-icon-chevron-down`;
17
+ /**
18
+ * Service for tree node operations
19
+ * Handles all business logic for tree node manipulation
20
+ */
21
+ class AXTreeViewService {
22
+ // ==================== Constants ====================
23
+ static { this.ROOT_LIST_ID = 'ax-tree-view-root-list'; }
24
+ static { this.NODE_DROP_PREFIX = 'ax-tree-view-node-drop-'; }
25
+ static { this.LIST_PREFIX = 'ax-tree-view-list-'; }
26
+ // ==================== Node Finding & Traversal ====================
27
+ /**
28
+ * Find a node by ID in the tree
29
+ */
30
+ findNodeById(nodes, id) {
31
+ for (const node of nodes) {
32
+ if (node.id === id)
33
+ return node;
34
+ if (node.children) {
35
+ const found = this.findNodeById(node.children, id);
36
+ if (found)
37
+ return found;
39
38
  }
40
- return this.platformService.isRtl()
41
- ? `${baseClasses} ax-icon-chevron-left`
42
- : `${baseClasses} ax-icon-chevron-right`;
43
- }, ...(ngDevMode ? [{ debugName: "arrowIcon" }] : []));
44
- }
45
- handleArrowNodeClick() {
46
- if (this.item()[this.treeView.disableField()] || this.isLoading() || this.treeView.expandOn() === 'dbClick') {
47
- return;
48
- }
49
- this.isExpanded.set(!this.isExpanded());
50
- if (this.treeView.itemsPromise && this.isExpanded() && !this.item()[this.treeView.childrenField()]?.length) {
51
- this.treeView.fetchData(this.item());
52
- this.treeView.setNodeLoading(this.item()[this.treeView.valueField()], true);
53
39
  }
54
- this.treeView.onCollapsedChanged.emit({ component: this, data: this.item(), nativeElement: this.nativeElement });
40
+ return null;
55
41
  }
56
- handleTextClick() {
57
- if (this.item()[this.treeView.disableField()]) {
58
- return;
42
+ /**
43
+ * Find parent node of a given node
44
+ */
45
+ findParentNode(nodes, targetNode) {
46
+ for (const node of nodes) {
47
+ if (node.children?.some((child) => child.id === targetNode.id)) {
48
+ return node;
49
+ }
50
+ if (node.children) {
51
+ const found = this.findParentNode(node.children, targetNode);
52
+ if (found)
53
+ return found;
54
+ }
59
55
  }
60
- if (this.treeView.focusNodeEnabled()) {
61
- this.treeView.handleUnActiveNode(this.treeView.itemsSignal());
62
- this.item()[this.treeView.activeField()] = true;
56
+ return undefined;
57
+ }
58
+ /**
59
+ * Check if targetNode is a descendant of ancestorNode (or the same node)
60
+ * Prevents circular references by checking if target exists in ancestor's children tree
61
+ */
62
+ isValidDropTarget(movedNode, targetNode) {
63
+ if (movedNode.id === targetNode.id || this.isNodeDescendantOf(targetNode, movedNode)) {
64
+ return false;
63
65
  }
64
- this.treeView.onNodeClick.emit({ component: this, data: this.item(), nativeElement: this.nativeElement });
66
+ return true;
65
67
  }
66
- handleTextDbClick() {
67
- if (this.item()[this.treeView.disableField()] || this.treeView.expandOn() === 'click') {
68
- return;
68
+ /**
69
+ * Check if targetNode is a descendant of ancestorNode
70
+ */
71
+ isNodeDescendantOf(targetNode, ancestorNode) {
72
+ if (targetNode.id === ancestorNode.id) {
73
+ return true;
69
74
  }
70
- if (this.item()?.[this.treeView.childrenField()] || this.item()[this.treeView.hasChildField()]) {
71
- this.isExpanded.set(!this.isExpanded());
72
- if (this.treeView.itemsPromise && this.isExpanded()) {
73
- this.treeView.fetchData(this.item());
74
- this.treeView.setNodeLoading(this.item()[this.treeView.valueField()], true);
75
+ if (!ancestorNode.children || ancestorNode.children.length === 0) {
76
+ return false;
77
+ }
78
+ for (const child of ancestorNode.children) {
79
+ if (child.id === targetNode.id) {
80
+ return true;
81
+ }
82
+ if (this.isNodeDescendantOf(targetNode, child)) {
83
+ return true;
75
84
  }
76
85
  }
77
- this.treeView.onNodedbClick.emit({ component: this, data: this.item(), nativeElement: this.nativeElement });
78
- this.treeView.onCollapsedChanged.emit({ component: this, data: this.item(), nativeElement: this.nativeElement });
86
+ return false;
79
87
  }
80
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
81
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: AXTreeViewItemComponent, isStandalone: true, selector: "ax-tree-view-item", inputs: { item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: false, transformFunction: null }, isExpanded: { classPropertyName: "isExpanded", publicName: "isExpanded", isSignal: true, isRequired: false, transformFunction: null }, isActive: { classPropertyName: "isActive", publicName: "isActive", isSignal: true, isRequired: false, transformFunction: null }, isLoading: { classPropertyName: "isLoading", publicName: "isLoading", isSignal: true, isRequired: false, transformFunction: null }, executorChanges: { classPropertyName: "executorChanges", publicName: "executorChanges", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { isExpanded: "isExpandedChange", isActive: "isActiveChange" }, providers: [{ provide: AXComponent, useExisting: AXTreeViewItemComponent }], usesInheritance: true, ngImport: i0, template: "<div class=\"ax-tree-view-container\">\n @if (\n (treeView.showEmptyNodeMassage() && item().hasOwnProperty(treeView.childrenField())) ||\n (item()[this.treeView.childrenField()]?.length && !isLoading()) ||\n (item()[treeView.hasChildField()] && !isLoading())\n ) {\n <div class=\"ax-tree-view-icon-container\" (click)=\"handleArrowNodeClick()\">\n <i [class.ax-state-disabled]=\"item()[treeView.disableField()]\" class=\"{{ arrowIcon() }}\"></i>\n </div>\n } @else if (isLoading()) {\n <ax-loading></ax-loading>\n }\n\n <div class=\"ax-tree-view-items\">\n <ng-content select=\"ax-check-box\"></ng-content>\n <div\n [class.ax-state-disabled]=\"item()[treeView.disableField()]\"\n [axTooltip]=\"item()[treeView.tooltipField()]\"\n axTooltipPlacement=\"end-bottom\"\n (click)=\"handleTextClick()\"\n (dblclick)=\"handleTextDbClick()\"\n class=\"ax-tree-view-items-prefix ax-noselect-tree-view\"\n [class.ax-state-tree-view-active]=\"item()[treeView.activeField()]\"\n >\n @if (treeView.itemTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"treeView.itemTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: item() }\"\n ></ng-container>\n } @else {\n <ng-content select=\"ax-prefix\"></ng-content>\n <ng-content select=\"ax-text\"></ng-content>\n <ng-content select=\"ax-suffix\"></ng-content>\n }\n </div>\n </div>\n</div>\n\n@if (isExpanded()) {\n <div\n animate.enter=\"ax-fade-slide-in\"\n animate.leave=\"ax-fade-slide-out\"\n class=\"ax-tree-view-child\"\n [class.ax-tree-view-empty-child]=\"\n treeView.showEmptyNodeMassage() &&\n item().hasOwnProperty(treeView.childrenField()) &&\n !item()[treeView.childrenField()]?.length\n \"\n >\n @if (\n treeView.showEmptyNodeMassage() &&\n item().hasOwnProperty(treeView.childrenField()) &&\n !item()[treeView.childrenField()]?.length\n ) {\n <ng-container [ngTemplateOutlet]=\"empty\"></ng-container>\n } @else {\n <ng-content></ng-content>\n }\n </div>\n}\n\n<ng-template #empty>\n {{ '@acorex:common.general.no-result-found' | translate | async }}\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "directive", type: AXTooltipDirective, selector: "[axTooltip]", inputs: ["axTooltipDisabled", "axTooltip", "axTooltipContext", "axTooltipPlacement", "axTooltipOffsetX", "axTooltipOffsetY", "axTooltipOpenAfter", "axTooltipCloseAfter"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
82
- }
83
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewItemComponent, decorators: [{
84
- type: Component,
85
- args: [{ selector: 'ax-tree-view-item', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, AXLoadingComponent, AXTooltipDirective, NgTemplateOutlet, AXTranslatorPipe, AsyncPipe], providers: [{ provide: AXComponent, useExisting: AXTreeViewItemComponent }], template: "<div class=\"ax-tree-view-container\">\n @if (\n (treeView.showEmptyNodeMassage() && item().hasOwnProperty(treeView.childrenField())) ||\n (item()[this.treeView.childrenField()]?.length && !isLoading()) ||\n (item()[treeView.hasChildField()] && !isLoading())\n ) {\n <div class=\"ax-tree-view-icon-container\" (click)=\"handleArrowNodeClick()\">\n <i [class.ax-state-disabled]=\"item()[treeView.disableField()]\" class=\"{{ arrowIcon() }}\"></i>\n </div>\n } @else if (isLoading()) {\n <ax-loading></ax-loading>\n }\n\n <div class=\"ax-tree-view-items\">\n <ng-content select=\"ax-check-box\"></ng-content>\n <div\n [class.ax-state-disabled]=\"item()[treeView.disableField()]\"\n [axTooltip]=\"item()[treeView.tooltipField()]\"\n axTooltipPlacement=\"end-bottom\"\n (click)=\"handleTextClick()\"\n (dblclick)=\"handleTextDbClick()\"\n class=\"ax-tree-view-items-prefix ax-noselect-tree-view\"\n [class.ax-state-tree-view-active]=\"item()[treeView.activeField()]\"\n >\n @if (treeView.itemTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"treeView.itemTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: item() }\"\n ></ng-container>\n } @else {\n <ng-content select=\"ax-prefix\"></ng-content>\n <ng-content select=\"ax-text\"></ng-content>\n <ng-content select=\"ax-suffix\"></ng-content>\n }\n </div>\n </div>\n</div>\n\n@if (isExpanded()) {\n <div\n animate.enter=\"ax-fade-slide-in\"\n animate.leave=\"ax-fade-slide-out\"\n class=\"ax-tree-view-child\"\n [class.ax-tree-view-empty-child]=\"\n treeView.showEmptyNodeMassage() &&\n item().hasOwnProperty(treeView.childrenField()) &&\n !item()[treeView.childrenField()]?.length\n \"\n >\n @if (\n treeView.showEmptyNodeMassage() &&\n item().hasOwnProperty(treeView.childrenField()) &&\n !item()[treeView.childrenField()]?.length\n ) {\n <ng-container [ngTemplateOutlet]=\"empty\"></ng-container>\n } @else {\n <ng-content></ng-content>\n }\n </div>\n}\n\n<ng-template #empty>\n {{ '@acorex:common.general.no-result-found' | translate | async }}\n</ng-template>\n" }]
86
- }], ctorParameters: () => [], propDecorators: { item: [{ type: i0.Input, args: [{ isSignal: true, alias: "item", required: false }] }], isExpanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "isExpanded", required: false }] }, { type: i0.Output, args: ["isExpandedChange"] }], isActive: [{ type: i0.Input, args: [{ isSignal: true, alias: "isActive", required: false }] }, { type: i0.Output, args: ["isActiveChange"] }], isLoading: [{ type: i0.Input, args: [{ isSignal: true, alias: "isLoading", required: false }] }], executorChanges: [{ type: i0.Input, args: [{ isSignal: true, alias: "executorChanges", required: false }] }] } });
87
-
88
- class AXTreeViewComponent extends NXComponent {
89
- constructor() {
90
- super(...arguments);
91
- this.itemsSignal = signal([], ...(ngDevMode ? [{ debugName: "itemsSignal" }] : []));
92
- this.items = input(...(ngDevMode ? [undefined, { debugName: "items" }] : []));
93
- this.showCheckbox = input(true, ...(ngDevMode ? [{ debugName: "showCheckbox" }] : []));
94
- this.hasCheckboxField = input('hasCheckbox', ...(ngDevMode ? [{ debugName: "hasCheckboxField" }] : []));
95
- this.selectionMode = input('single', ...(ngDevMode ? [{ debugName: "selectionMode" }] : []));
96
- this.selectionBehavior = input(...(ngDevMode ? [undefined, { debugName: "selectionBehavior" }] : []));
97
- this.selectionScope = input('all', ...(ngDevMode ? [{ debugName: "selectionScope" }] : []));
98
- this.focusNodeEnabled = input(true, ...(ngDevMode ? [{ debugName: "focusNodeEnabled" }] : []));
99
- this.valueField = input('id', ...(ngDevMode ? [{ debugName: "valueField" }] : []));
100
- this.textField = input('text', ...(ngDevMode ? [{ debugName: "textField" }] : []));
101
- this.visibleField = input('visible', ...(ngDevMode ? [{ debugName: "visibleField" }] : []));
102
- this.disableField = input('disabled', ...(ngDevMode ? [{ debugName: "disableField" }] : []));
103
- this.hasChildField = input('hasChild', ...(ngDevMode ? [{ debugName: "hasChildField" }] : []));
104
- this.selectedField = input('selected', ...(ngDevMode ? [{ debugName: "selectedField" }] : []));
105
- this.expandedField = input('expanded', ...(ngDevMode ? [{ debugName: "expandedField" }] : []));
106
- this.tooltipField = input('tooltip', ...(ngDevMode ? [{ debugName: "tooltipField" }] : []));
107
- this.childrenField = input('children', ...(ngDevMode ? [{ debugName: "childrenField" }] : []));
108
- this.activeField = input('active', ...(ngDevMode ? [{ debugName: "activeField" }] : []));
109
- this.indeterminateField = input('indeterminate', ...(ngDevMode ? [{ debugName: "indeterminateField" }] : []));
110
- this.parentField = input('parentId', ...(ngDevMode ? [{ debugName: "parentField" }] : []));
111
- this.iconField = input('icon', ...(ngDevMode ? [{ debugName: "iconField" }] : []));
112
- this.toggleIcons = input(...(ngDevMode ? [undefined, { debugName: "toggleIcons" }] : []));
113
- this.look = input('defult', ...(ngDevMode ? [{ debugName: "look" }] : []));
114
- this.showEmptyNodeMassage = input(false, ...(ngDevMode ? [{ debugName: "showEmptyNodeMassage" }] : []));
115
- this.onSelectionChanged = output();
116
- this.onItemSelectedChanged = output();
117
- this.onNodeClick = output();
118
- this.onCollapsedChanged = output();
119
- this.onNodedbClick = output();
120
- this.executorChanges = signal(null, ...(ngDevMode ? [{ debugName: "executorChanges" }] : []));
121
- this.platformService = inject(AXPlatform);
122
- this.#effect = effect(() => {
123
- const itemsInput = this.items();
124
- if (typeof itemsInput === 'function') {
125
- const result = itemsInput();
126
- if (result instanceof Promise) {
127
- this.itemsPromise = (options) => itemsInput(options);
128
- this.fetchData();
129
- }
130
- else {
131
- this.itemsSignal.set(result);
132
- this.itemsPromise = null;
88
+ /**
89
+ * Build a flat list of all visible focusable nodes
90
+ */
91
+ buildFlatNodeList(nodes) {
92
+ const flatList = [];
93
+ const traverse = (nodeList, level, parent) => {
94
+ for (const node of nodeList) {
95
+ if (node.visible !== false && !node.disabled) {
96
+ flatList.push({ node, level, parent });
97
+ if (node.expanded && node.children) {
98
+ traverse(node.children, level + 1, node);
99
+ }
133
100
  }
134
101
  }
135
- else {
136
- this.itemsSignal.set(itemsInput);
137
- this.itemsPromise = null;
138
- }
139
- }, ...(ngDevMode ? [{ debugName: "#effect" }] : []));
140
- this.expandOn = input('defult', ...(ngDevMode ? [{ debugName: "expandOn" }] : []));
141
- this.loadingState = signal({}, ...(ngDevMode ? [{ debugName: "loadingState" }] : []));
102
+ };
103
+ traverse(nodes, 0);
104
+ return flatList;
142
105
  }
143
- /** @ignore */
144
- get __hostClass() {
145
- return [`ax-look-${this.look()}`];
106
+ // ==================== Node State Checks ====================
107
+ /**
108
+ * Check if node has children
109
+ */
110
+ hasChildren(node) {
111
+ return Boolean(node.children?.length);
146
112
  }
147
- get resolvedItems() {
148
- return this.itemsSignal();
113
+ /**
114
+ * Check if node can be lazy loaded
115
+ */
116
+ canLazyLoad(node, isLazyDataSource) {
117
+ return isLazyDataSource && Boolean(node.childrenCount && node.childrenCount > 0 && !this.hasChildren(node));
149
118
  }
150
- #effect;
151
- handleNodeSelectionClick(event, item) {
152
- if (item[this.disableField()] || this.isNodeLoading(item[this.valueField()])) {
153
- return;
154
- }
155
- if (this.selectionMode() === 'single' && event.isUserInteraction) {
156
- this.handleUnSelectNode(this.itemsSignal());
157
- }
158
- if (event.isUserInteraction) {
159
- item[this.selectedField()] = event.value;
160
- if (event.value !== null) {
161
- switch (this.selectionBehavior()) {
162
- case 'autoExpand':
163
- if (event.value) {
164
- if (this.itemsPromise && item[this.hasChildField()] && !item?.[this.childrenField()]?.length) {
165
- this.setNodeLoading(item[this.valueField()], true);
166
- this.fetchData(item);
167
- }
168
- this.toggleExpand(item);
169
- }
170
- break;
171
- case 'cascade':
172
- this.expandAndToggleSelection(item, event.value);
173
- break;
174
- case 'indeterminate':
175
- if (item?.[this.childrenField()]?.length) {
176
- this.applySelectionToChildren(item, event.value, item[this.valueField()]);
177
- }
178
- this.updateParentSelection(item, event.value);
179
- break;
180
- default:
181
- break;
182
- }
119
+ // ==================== Selection Management ====================
120
+ /**
121
+ * Recursively select/deselect all children
122
+ */
123
+ selectAllChildren(children, selected) {
124
+ for (const child of children) {
125
+ child.selected = selected;
126
+ child.indeterminate = false;
127
+ if (child.children) {
128
+ this.selectAllChildren(child.children, selected);
183
129
  }
184
- this.onItemSelectedChanged.emit({
185
- component: this,
186
- data: item,
187
- nativeElement: this.nativeElement,
188
- });
189
- const result = this.findSelectedNodes(this.itemsSignal());
190
- this.onSelectionChanged.emit({
191
- component: this,
192
- data: result,
193
- nativeElement: this.nativeElement,
194
- });
195
130
  }
196
131
  }
197
132
  /**
198
- *
199
- * auto expand
200
- *
133
+ * Get selection state of children
201
134
  */
202
- toggleExpand(item) {
203
- if (!item[this.expandedField()]) {
204
- item[this.expandedField()] = true;
135
+ getChildrenSelectionState(children) {
136
+ let selectedCount = 0;
137
+ let indeterminateCount = 0;
138
+ for (const child of children) {
139
+ if (child.selected && !child.indeterminate) {
140
+ selectedCount++;
141
+ }
142
+ if (child.indeterminate) {
143
+ indeterminateCount++;
144
+ }
205
145
  }
146
+ return {
147
+ allSelected: selectedCount === children.length,
148
+ someSelected: selectedCount > 0 || indeterminateCount > 0,
149
+ };
206
150
  }
207
151
  /**
208
- *
209
- * expand and change value parent change
210
- *
152
+ * Update parent node states based on children selection (with intermediate state support)
211
153
  */
212
- async expandAndToggleSelection(item, selected) {
213
- if (this.itemsPromise && item[this.hasChildField()] && !item?.[this.childrenField()]?.length) {
214
- await this.setNodeLoading(item[this.valueField()], true);
215
- await this.fetchData(item);
154
+ updateParentStates(nodes, changedNode, intermediateState) {
155
+ const parent = this.findParentNode(nodes, changedNode);
156
+ if (!parent || !parent.children)
157
+ return;
158
+ const { allSelected, someSelected } = this.getChildrenSelectionState(parent.children);
159
+ if (allSelected) {
160
+ parent.selected = true;
161
+ parent.indeterminate = false;
216
162
  }
217
- this.toggleExpand(item);
218
- if (item[this.childrenField()]?.length) {
219
- this.applySelectionToChildren(item, selected, item[this.valueField()]);
163
+ else if (someSelected) {
164
+ if (intermediateState) {
165
+ parent.selected = true;
166
+ parent.indeterminate = true;
167
+ }
168
+ else {
169
+ parent.selected = false;
170
+ parent.indeterminate = false;
171
+ }
220
172
  }
173
+ else {
174
+ parent.selected = false;
175
+ parent.indeterminate = false;
176
+ }
177
+ this.updateParentStates(nodes, parent, intermediateState);
221
178
  }
222
- applySelectionToChildren(item, isSelected, parentId) {
223
- item[this.childrenField()].forEach(async (child) => {
224
- if (this.itemsPromise &&
225
- child[this.hasChildField()] &&
226
- !child?.[this.childrenField()]?.length &&
227
- this.selectionBehavior() === 'cascade') {
228
- await this.setNodeLoading(child[this.valueField()], true);
229
- await this.fetchData(child);
230
- this.toggleExpand(child);
179
+ /**
180
+ * Recursively deselect all nodes
181
+ */
182
+ deselectAllNodes(nodes) {
183
+ for (const node of nodes) {
184
+ node.selected = false;
185
+ node.indeterminate = false;
186
+ if (node.children) {
187
+ this.deselectAllNodes(node.children);
231
188
  }
232
- child[this.parentField()] = parentId;
233
- child[this.selectedField()] = isSelected;
234
- if (child[this.childrenField()]?.length) {
235
- this.applySelectionToChildren(child, isSelected, child[this.valueField()]);
189
+ }
190
+ }
191
+ /**
192
+ * Recursively set selection state for all nodes
193
+ */
194
+ setAllSelection(nodes, selected) {
195
+ for (const node of nodes) {
196
+ node.selected = selected;
197
+ node.indeterminate = false;
198
+ if (node.children) {
199
+ this.setAllSelection(node.children, selected);
236
200
  }
237
- });
201
+ }
238
202
  }
239
203
  /**
240
- *
241
- * indeterminate logic
242
- *
204
+ * Recursively count selected nodes
243
205
  */
244
- updateParentSelection(item, selected) {
245
- item[this.selectedField()] = selected;
246
- let parent = this.findParent(item, this.itemsSignal());
247
- while ((parent && parent[this.selectedField()] != false) || (parent && item[this.selectedField()])) {
248
- const allSelected = parent?.[this.childrenField()]?.every((child) => child[this.selectedField()]);
249
- const someSelected = parent?.[this.childrenField()]?.some((child) => child[this.selectedField()] || child[this.indeterminateField()]);
250
- if (!allSelected && !someSelected) {
251
- parent[this.selectedField()] = false;
252
- parent[this.indeterminateField()] = null;
206
+ countSelected(nodes) {
207
+ let count = 0;
208
+ for (const node of nodes) {
209
+ if (node.selected)
210
+ count++;
211
+ if (node.children) {
212
+ count += this.countSelected(node.children);
253
213
  }
254
- else if (!allSelected) {
255
- parent[this.indeterminateField()] = true;
256
- parent[this.selectedField()] = null;
214
+ }
215
+ return count;
216
+ }
217
+ /**
218
+ * Recursively collect selected nodes
219
+ */
220
+ collectSelected(nodes, result) {
221
+ for (const node of nodes) {
222
+ if (node.selected)
223
+ result.push(node);
224
+ if (node.children) {
225
+ this.collectSelected(node.children, result);
257
226
  }
258
- else if (allSelected) {
259
- parent[this.selectedField()] = true;
260
- parent[this.indeterminateField()] = false;
227
+ }
228
+ }
229
+ /**
230
+ * Recursively remove selected nodes
231
+ */
232
+ removeSelected(nodes) {
233
+ for (let i = nodes.length - 1; i >= 0; i--) {
234
+ if (nodes[i].selected && !nodes[i].indeterminate) {
235
+ nodes.splice(i, 1);
261
236
  }
262
- else {
263
- parent[this.indeterminateField()] = false;
264
- parent[this.selectedField()] = true;
237
+ else if (nodes[i].children) {
238
+ this.removeSelected(nodes[i].children ?? []);
265
239
  }
266
- parent = this.findParent(parent, this.itemsSignal());
267
240
  }
268
241
  }
269
- findParent(item, nodes) {
242
+ /**
243
+ * Recursively update all parent states in the tree (used after deletion)
244
+ */
245
+ updateAllParentStates(nodes, intermediateState) {
270
246
  for (const node of nodes) {
271
- if (node[this.childrenField()]?.includes(item)) {
272
- return node;
247
+ if (node.children && node.children.length > 0) {
248
+ this.updateAllParentStates(node.children, intermediateState);
249
+ const { allSelected, someSelected } = this.getChildrenSelectionState(node.children);
250
+ if (allSelected) {
251
+ node.selected = true;
252
+ node.indeterminate = false;
253
+ }
254
+ else if (someSelected) {
255
+ if (intermediateState) {
256
+ node.selected = true;
257
+ node.indeterminate = true;
258
+ }
259
+ else {
260
+ node.selected = false;
261
+ node.indeterminate = false;
262
+ }
263
+ }
264
+ else {
265
+ node.selected = false;
266
+ node.indeterminate = false;
267
+ }
273
268
  }
274
- else if (node[this.childrenField()]) {
275
- const parent = this.findParent(item, node[this.childrenField()]);
276
- if (parent)
277
- return parent;
269
+ }
270
+ }
271
+ // ==================== Expansion Management ====================
272
+ /**
273
+ * Recursively set expanded state (with lazy loading)
274
+ */
275
+ async setExpandedState(nodes, expanded, isLazyDataSource, loadNodeChildren) {
276
+ for (const node of nodes) {
277
+ const hasChildren = this.hasChildren(node);
278
+ const canLazyLoad = this.canLazyLoad(node, isLazyDataSource);
279
+ if (hasChildren || canLazyLoad) {
280
+ if (expanded && canLazyLoad) {
281
+ await loadNodeChildren(node);
282
+ }
283
+ node.expanded = expanded;
284
+ if (node.children) {
285
+ await this.setExpandedState(node.children, expanded, isLazyDataSource, loadNodeChildren);
286
+ }
278
287
  }
279
288
  }
280
- return null;
289
+ }
290
+ // ==================== Drag & Drop Helpers ====================
291
+ /**
292
+ * Get array reference by drop list ID
293
+ */
294
+ getArrayByListId(nodes, listId) {
295
+ if (listId === AXTreeViewService.ROOT_LIST_ID) {
296
+ return nodes;
297
+ }
298
+ if (listId.startsWith(AXTreeViewService.NODE_DROP_PREFIX)) {
299
+ const nodeId = listId.replace(AXTreeViewService.NODE_DROP_PREFIX, '');
300
+ const node = this.findNodeById(nodes, nodeId);
301
+ return node ? [node] : null;
302
+ }
303
+ const nodeId = listId.replace(AXTreeViewService.LIST_PREFIX, '');
304
+ const node = this.findNodeById(nodes, nodeId);
305
+ return node?.children ?? null;
306
+ }
307
+ /**
308
+ * Find parent node by list ID
309
+ */
310
+ findParentByListId(nodes, listId) {
311
+ if (listId === AXTreeViewService.ROOT_LIST_ID) {
312
+ return undefined;
313
+ }
314
+ const prefix = listId.startsWith(AXTreeViewService.NODE_DROP_PREFIX)
315
+ ? AXTreeViewService.NODE_DROP_PREFIX
316
+ : AXTreeViewService.LIST_PREFIX;
317
+ const nodeId = listId.replace(prefix, '');
318
+ return this.findNodeById(nodes, nodeId) ?? undefined;
319
+ }
320
+ /**
321
+ * Generate unique list ID for each node
322
+ */
323
+ getListId(node) {
324
+ return node ? `${AXTreeViewService.LIST_PREFIX}${node.id}` : AXTreeViewService.ROOT_LIST_ID;
281
325
  }
282
326
  /**
283
- *
284
- * find node selected true for emit Selections
285
- *
327
+ * Get root list ID constant
286
328
  */
287
- findSelectedNodes(nodes) {
288
- let selectedNodes = [];
289
- nodes.forEach((node) => {
290
- if (node[this.selectedField()]) {
291
- selectedNodes.push(node);
329
+ getRootListId() {
330
+ return AXTreeViewService.ROOT_LIST_ID;
331
+ }
332
+ /**
333
+ * Get node drop prefix constant
334
+ */
335
+ getNodeDropPrefix() {
336
+ return AXTreeViewService.NODE_DROP_PREFIX;
337
+ }
338
+ /**
339
+ * Get list prefix constant
340
+ */
341
+ getListPrefix() {
342
+ return AXTreeViewService.LIST_PREFIX;
343
+ }
344
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
345
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewService }); }
346
+ }
347
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewService, decorators: [{
348
+ type: Injectable
349
+ }] });
350
+
351
+ class AXTreeViewComponent {
352
+ constructor() {
353
+ // ==================== Dependencies ====================
354
+ this.treeService = inject(AXTreeViewService);
355
+ this.platformService = inject(AXPlatform);
356
+ this.destroyRef = inject(DestroyRef);
357
+ // ==================== Inputs ====================
358
+ /** Tree data source - can be static array or lazy loading function */
359
+ this.datasource = model.required(...(ngDevMode ? [{ debugName: "datasource" }] : []));
360
+ /** Selection mode: 'single' (click to select) or 'multiple' (checkbox selection) */
361
+ this.selectMode = input('multiple', ...(ngDevMode ? [{ debugName: "selectMode" }] : []));
362
+ /** Whether to show checkboxes for selection (only applies to multiple mode) */
363
+ this.showCheckbox = input(true, ...(ngDevMode ? [{ debugName: "showCheckbox" }] : []));
364
+ /** When true, selecting a parent also selects all loaded children (only for multiple mode) */
365
+ this.checkChildrenOnSelect = input(true, ...(ngDevMode ? [{ debugName: "checkChildrenOnSelect" }] : []));
366
+ /** When true, selecting a child makes parents indeterminate (only for multiple mode) */
367
+ this.intermediateState = input(true, ...(ngDevMode ? [{ debugName: "intermediateState" }] : []));
368
+ /** When true, clicking on a node toggles its selection (works for both single and multiple modes) */
369
+ this.checkOnClick = input(false, ...(ngDevMode ? [{ debugName: "checkOnClick" }] : []));
370
+ /** Drag and drop mode: 'none' (disabled), 'handler' (drag handle), 'item' (entire item) */
371
+ this.dragMode = input('handler', ...(ngDevMode ? [{ debugName: "dragMode" }] : []));
372
+ /** Drag operation type: 'order-only' (reorder only), 'move' (move between parents), 'both' (allow both) */
373
+ this.dragOperationType = input('both', ...(ngDevMode ? [{ debugName: "dragOperationType" }] : []));
374
+ /** Whether to show icons */
375
+ this.showIcons = input(true, ...(ngDevMode ? [{ debugName: "showIcons" }] : []));
376
+ /** Whether to show children count badge */
377
+ this.showChildrenBadge = input(true, ...(ngDevMode ? [{ debugName: "showChildrenBadge" }] : []));
378
+ /** Custom icon for expanded nodes */
379
+ this.expandedIcon = input('fa-solid fa-chevron-down', ...(ngDevMode ? [{ debugName: "expandedIcon" }] : []));
380
+ /** Custom icon for collapsed nodes */
381
+ this.collapsedIcon = input('fa-solid fa-chevron-right', ...(ngDevMode ? [{ debugName: "collapsedIcon" }] : []));
382
+ /** Indent size in pixels for each level */
383
+ this.indentSize = input(12, ...(ngDevMode ? [{ debugName: "indentSize" }] : []));
384
+ /** Node height in pixels */
385
+ this.nodeHeight = input('normal', ...(ngDevMode ? [{ debugName: "nodeHeight" }] : []));
386
+ /** Visual style variant */
387
+ this.look = input('default', ...(ngDevMode ? [{ debugName: "look" }] : []));
388
+ /** Custom template for tree items */
389
+ this.itemTemplate = input(...(ngDevMode ? [undefined, { debugName: "itemTemplate" }] : []));
390
+ // ==================== Outputs ====================
391
+ /** Emitted before a drop operation - set canceled to true to prevent drop */
392
+ this.onBeforeDrop = output();
393
+ /** Emitted when a node is toggled (expanded/collapsed) */
394
+ this.onNodeToggle = output();
395
+ /** Emitted when a node is selected/deselected */
396
+ this.onNodeSelect = output();
397
+ /** Emitted when nodes are reordered within the same parent */
398
+ this.onOrderChange = output();
399
+ /** Emitted when a node is moved to a different parent */
400
+ this.onMoveChange = output();
401
+ /** Emitted for any item change (order or move) */
402
+ this.onItemsChange = output();
403
+ // ==================== Internal State ====================
404
+ /** Internal signal for tree nodes */
405
+ this.nodes = signal([], ...(ngDevMode ? [{ debugName: "nodes" }] : []));
406
+ /** Internal signal for tracking loading state */
407
+ this.loadingNodes = signal(new Set(), ...(ngDevMode ? [{ debugName: "loadingNodes" }] : []));
408
+ /** Currently focused node ID for keyboard navigation */
409
+ this.focusedNodeId = signal(null, ...(ngDevMode ? [{ debugName: "focusedNodeId" }] : []));
410
+ /** RTL detection signal */
411
+ this.isRtl = signal(this.platformService.isRtl(), ...(ngDevMode ? [{ debugName: "isRtl" }] : []));
412
+ /** Computed chevron icons that flip for RTL */
413
+ this.directionExpandedIcon = computed(() => this.expandedIcon(), ...(ngDevMode ? [{ debugName: "directionExpandedIcon" }] : []));
414
+ this.directionCollapsedIcon = computed(() => {
415
+ const isRtlDirection = this.isRtl();
416
+ const defaultIcon = this.collapsedIcon();
417
+ if (isRtlDirection && defaultIcon === 'fa-solid fa-chevron-right') {
418
+ return 'fa-solid fa-chevron-left';
419
+ }
420
+ if (!isRtlDirection && defaultIcon === 'fa-solid fa-chevron-left') {
421
+ return 'fa-solid fa-chevron-right';
422
+ }
423
+ return defaultIcon;
424
+ }, ...(ngDevMode ? [{ debugName: "directionCollapsedIcon" }] : []));
425
+ /** Flag to prevent infinite loops when syncing datasource */
426
+ this.isUpdatingFromDatasource = false;
427
+ /** Computed to check if datasource is a function */
428
+ this.isLazyDataSource = computed(() => typeof this.datasource() === 'function', ...(ngDevMode ? [{ debugName: "isLazyDataSource" }] : []));
429
+ // ==================== Effects ====================
430
+ /** Effect to handle datasource changes */
431
+ this.#datasourceEffect = effect(() => {
432
+ if (this.isUpdatingFromDatasource)
433
+ return;
434
+ const ds = this.datasource();
435
+ if (Array.isArray(ds)) {
436
+ this.nodes.set([...ds]);
292
437
  }
293
- if (node[this.childrenField()]) {
294
- selectedNodes = selectedNodes.concat(this.findSelectedNodes(node[this.childrenField()]));
438
+ else if (typeof ds === 'function') {
439
+ this.loadRootItems(ds).catch((error) => {
440
+ this.handleError('Failed to load root items', error);
441
+ });
295
442
  }
443
+ }, ...(ngDevMode ? [{ debugName: "#datasourceEffect" }] : []));
444
+ /** Initialize direction change listener */
445
+ this.#initDirectionListener = afterNextRender(() => {
446
+ this.platformService.directionChange
447
+ .pipe(map((event) => event.data === 'rtl'), takeUntilDestroyed(this.destroyRef))
448
+ .subscribe((isRtl) => this.isRtl.set(isRtl));
296
449
  });
297
- return selectedNodes;
298
450
  }
451
+ // ==================== Effects ====================
452
+ /** Effect to handle datasource changes */
453
+ #datasourceEffect;
454
+ /** Initialize direction change listener */
455
+ #initDirectionListener;
456
+ // ==================== Public API ====================
299
457
  /**
300
- *
301
- * find for emit Selections single mode
302
- *
458
+ * Expand all nodes in the tree (with lazy loading support)
303
459
  */
304
- handleUnSelectNode(items) {
305
- items.forEach((child) => {
306
- child[this.selectedField()] = false;
307
- if (child?.[this.childrenField()]?.length) {
308
- this.handleUnSelectNode(child[this.childrenField()]);
309
- }
310
- });
460
+ async expandAll() {
461
+ await this.treeService.setExpandedState(this.nodes(), true, this.isLazyDataSource(), (node) => this.loadNodeChildren(node));
462
+ this.refreshNodes();
311
463
  }
312
464
  /**
313
- *
314
- * lazy load logic
315
- *
465
+ * Collapse all nodes in the tree
316
466
  */
317
- fetchData(selectedNode) {
318
- this.itemsPromise(selectedNode?.[this.valueField()])
319
- .then((data) => {
320
- if (Array.isArray(data)) {
321
- if (selectedNode?.[this.valueField()]) {
322
- this.findNode(selectedNode[this.valueField()], data, this.itemsSignal());
323
- }
324
- else {
325
- const isNodeExpanded = data.filter((child) => child[this.expandedField()]);
326
- isNodeExpanded.forEach((child) => {
327
- this.fetchData(child);
328
- });
329
- this.itemsSignal.set(data);
330
- }
467
+ collapseAll() {
468
+ this.treeService.setExpandedState(this.nodes(), false, this.isLazyDataSource(), (node) => this.loadNodeChildren(node));
469
+ this.refreshNodes();
470
+ }
471
+ /**
472
+ * Get count of selected nodes
473
+ */
474
+ getSelectedCount() {
475
+ return this.treeService.countSelected(this.nodes());
476
+ }
477
+ /**
478
+ * Check if any nodes are selected
479
+ */
480
+ hasSelection() {
481
+ return this.getSelectedCount() > 0;
482
+ }
483
+ /**
484
+ * Get all selected nodes
485
+ */
486
+ getSelectedNodes() {
487
+ const selected = [];
488
+ this.treeService.collectSelected(this.nodes(), selected);
489
+ return selected;
490
+ }
491
+ /**
492
+ * Delete selected nodes from the tree
493
+ */
494
+ deleteSelected() {
495
+ this.treeService.removeSelected(this.nodes());
496
+ this.treeService.updateAllParentStates(this.nodes(), this.intermediateState());
497
+ this.refreshNodes();
498
+ }
499
+ /**
500
+ * Select all nodes in the tree
501
+ */
502
+ selectAll() {
503
+ this.treeService.setAllSelection(this.nodes(), true);
504
+ this.refreshNodes();
505
+ }
506
+ /**
507
+ * Deselect all nodes in the tree
508
+ */
509
+ deselectAll() {
510
+ this.treeService.setAllSelection(this.nodes(), false);
511
+ this.refreshNodes();
512
+ }
513
+ /**
514
+ * Find a node by ID in the tree
515
+ */
516
+ findNode(id) {
517
+ return this.treeService.findNodeById(this.nodes(), id);
518
+ }
519
+ /**
520
+ * Refresh the tree to trigger change detection
521
+ */
522
+ refresh() {
523
+ this.refreshNodes();
524
+ }
525
+ /**
526
+ * Check if a node is currently loading
527
+ */
528
+ isNodeLoading(nodeId) {
529
+ return this.loadingNodes().has(nodeId);
530
+ }
531
+ /**
532
+ * Get template context for a node
533
+ */
534
+ getTemplateContext(node, level = 0) {
535
+ return {
536
+ $implicit: node,
537
+ node,
538
+ level,
539
+ expanded: node.expanded ?? false,
540
+ childrenCount: node.childrenCount ?? node.children?.length ?? 0,
541
+ loading: node.loading ?? false,
542
+ };
543
+ }
544
+ /**
545
+ * Calculate padding-inline for a node based on its level
546
+ */
547
+ getNodePaddingInline(level) {
548
+ const indent = this.indentSize();
549
+ const currentLook = this.look();
550
+ const multiplier = currentLook === 'with-line' ? 1 / 3 : 1;
551
+ return level * indent * multiplier;
552
+ }
553
+ /**
554
+ * Check if node should show expand toggle
555
+ */
556
+ shouldShowExpandToggle(node) {
557
+ return this.treeService.hasChildren(node) || this.treeService.canLazyLoad(node, this.isLazyDataSource());
558
+ }
559
+ /**
560
+ * Check if checkboxes should be shown (only for multiple mode)
561
+ */
562
+ shouldShowCheckbox() {
563
+ return this.selectMode() === 'multiple' && this.showCheckbox();
564
+ }
565
+ /**
566
+ * Generate unique list ID for each node
567
+ */
568
+ getListId(node) {
569
+ return this.treeService.getListId(node);
570
+ }
571
+ /**
572
+ * Check if a node is currently focused
573
+ */
574
+ isNodeFocused(nodeId) {
575
+ return this.focusedNodeId() === nodeId;
576
+ }
577
+ /**
578
+ * Get ARIA level for a node
579
+ */
580
+ getNodeAriaLevel(level) {
581
+ return level + 1;
582
+ }
583
+ /**
584
+ * Get ARIA expanded state for a node
585
+ */
586
+ getNodeAriaExpanded(node) {
587
+ if (!this.shouldShowExpandToggle(node)) {
588
+ return null;
589
+ }
590
+ return node.expanded ? 'true' : 'false';
591
+ }
592
+ /**
593
+ * Get ARIA selected state for a node
594
+ */
595
+ getNodeAriaSelected(node) {
596
+ if (this.selectMode() === 'single') {
597
+ return node.selected ? 'true' : 'false';
598
+ }
599
+ return null;
600
+ }
601
+ // ==================== Event Handlers ====================
602
+ /**
603
+ * Handle node click - for single selection mode or multiple mode with checkOnClick enabled
604
+ */
605
+ onNodeClick(node, event) {
606
+ if (node.disabled)
607
+ return;
608
+ const mode = this.selectMode();
609
+ const shouldCheckOnClick = this.checkOnClick();
610
+ if (mode === 'single') {
611
+ this.handleSingleSelection(node, event);
612
+ }
613
+ else if (mode === 'multiple' && shouldCheckOnClick) {
614
+ this.handleMultipleSelection(node, event);
615
+ }
616
+ }
617
+ /**
618
+ * Toggle node expansion state with lazy loading support
619
+ */
620
+ async toggleNode(node, event) {
621
+ if (node.disabled)
622
+ return;
623
+ if (this.isEvent(event) && typeof event.stopPropagation === 'function') {
624
+ event.stopPropagation();
625
+ }
626
+ const hasChildren = this.treeService.hasChildren(node);
627
+ const canLazyLoad = this.treeService.canLazyLoad(node, this.isLazyDataSource());
628
+ if (hasChildren || canLazyLoad) {
629
+ const willExpand = !node.expanded;
630
+ if (willExpand && canLazyLoad) {
631
+ await this.loadNodeChildren(node);
331
632
  }
332
- })
333
- .finally(() => {
334
- this.setNodeLoading(selectedNode?.[this.valueField()], false);
633
+ node.expanded = willExpand;
634
+ this.refreshNodes();
635
+ this.onNodeToggle.emit({ component: this, node, nativeEvent: event });
636
+ }
637
+ }
638
+ /**
639
+ * Toggle node selection state with indeterminate support (for multiple mode)
640
+ */
641
+ toggleSelection(node, event) {
642
+ if (!event.isUserInteraction)
643
+ return;
644
+ const mode = this.selectMode();
645
+ if (mode !== 'multiple')
646
+ return;
647
+ const newValue = event.value === null ? true : event.value;
648
+ node.selected = newValue;
649
+ node.indeterminate = false;
650
+ if (this.checkChildrenOnSelect() && node.children) {
651
+ this.treeService.selectAllChildren(node.children, newValue);
652
+ }
653
+ if (this.intermediateState()) {
654
+ this.treeService.updateParentStates(this.nodes(), node, this.intermediateState());
655
+ }
656
+ this.refreshNodes();
657
+ this.onNodeSelect.emit({
658
+ component: this,
659
+ node,
660
+ isUserInteraction: event.isUserInteraction,
335
661
  });
336
662
  }
337
- findNode(parentId, _children, source) {
338
- if (source.length) {
339
- source.forEach((element) => {
340
- if (element[this.valueField()] == parentId) {
341
- if (this.selectionBehavior() === 'indeterminate' && element[this.selectedField()]) {
342
- _children.forEach((child) => (child[this.selectedField()] = true));
663
+ /**
664
+ * Handle drop events for tree nodes
665
+ */
666
+ onDrop(event, parentNode) {
667
+ const targetArray = parentNode?.children ?? this.nodes();
668
+ const isReordering = event.previousContainer === event.container;
669
+ if (isReordering) {
670
+ this.handleReorder(event, targetArray, parentNode);
671
+ }
672
+ else {
673
+ this.handleMove(event, targetArray, parentNode);
674
+ }
675
+ this.refreshNodes();
676
+ }
677
+ /**
678
+ * Handle drop events when dropping directly onto a node (to make it a child)
679
+ */
680
+ onDropOntoNode(event, targetNode) {
681
+ if (!this.canMoveToParent())
682
+ return;
683
+ const sourceListId = event.previousContainer.element.id;
684
+ const sourceArray = this.getArrayByListId(sourceListId);
685
+ if (!sourceArray)
686
+ return;
687
+ const movedNode = sourceArray[event.previousIndex];
688
+ if (!this.treeService.isValidDropTarget(movedNode, targetNode))
689
+ return;
690
+ if (!this.emitBeforeDropEvent(movedNode, sourceListId, targetNode, event.previousIndex, 0))
691
+ return;
692
+ targetNode.children ??= [];
693
+ sourceArray.splice(event.previousIndex, 1);
694
+ targetNode.children.unshift(movedNode);
695
+ targetNode.expanded = true;
696
+ this.emitDropEvents(movedNode, this.findParentByListId(sourceListId), targetNode, event.previousIndex, 0, false);
697
+ this.refreshNodes();
698
+ }
699
+ /**
700
+ * Handle node focus event
701
+ */
702
+ onNodeFocus(nodeId) {
703
+ this.focusedNodeId.set(nodeId);
704
+ }
705
+ /**
706
+ * Handle tree container focus - focus first node if none is focused
707
+ */
708
+ onTreeFocus(event) {
709
+ if (event.target === event.currentTarget) {
710
+ afterNextRender(() => {
711
+ const flatList = this.treeService.buildFlatNodeList(this.nodes());
712
+ if (flatList.length > 0) {
713
+ const focusedId = this.focusedNodeId();
714
+ if (focusedId) {
715
+ this.focusNodeById(focusedId);
716
+ }
717
+ else {
718
+ this.focusNodeById(flatList[0].node.id);
343
719
  }
344
- element[this.childrenField()] = _children;
345
- }
346
- else {
347
- if (element?.[this.childrenField()])
348
- this.findNode(parentId, _children, element[this.childrenField()]);
349
720
  }
350
721
  });
351
722
  }
352
723
  }
353
724
  /**
354
- *
355
- * emit when arrow click
356
- *
725
+ * Handle tree container blur
726
+ */
727
+ onTreeBlur(event) {
728
+ if (event.relatedTarget && !event.currentTarget.contains(event.relatedTarget)) {
729
+ this.focusedNodeId.set(null);
730
+ }
731
+ }
732
+ /**
733
+ * Handle keyboard navigation
734
+ */
735
+ handleKeyDown(event) {
736
+ const flatList = this.treeService.buildFlatNodeList(this.nodes());
737
+ if (flatList.length === 0)
738
+ return;
739
+ const currentFocused = this.getFocusedNode();
740
+ let currentIndex = currentFocused ? flatList.findIndex((item) => item.node.id === currentFocused.id) : -1;
741
+ if (currentIndex === -1 && event.target === event.currentTarget) {
742
+ currentIndex = 0;
743
+ }
744
+ const navigationResult = this.handleNavigationKey(event, flatList, currentIndex, currentFocused);
745
+ if (navigationResult.handled) {
746
+ if (navigationResult.shouldPreventDefault) {
747
+ event.preventDefault();
748
+ event.stopPropagation();
749
+ }
750
+ if (navigationResult.targetIndex !== null &&
751
+ navigationResult.targetIndex >= 0 &&
752
+ navigationResult.targetIndex < flatList.length) {
753
+ this.focusNodeById(flatList[navigationResult.targetIndex].node.id);
754
+ }
755
+ }
756
+ }
757
+ // ==================== Private Methods ====================
758
+ /**
759
+ * Load root items when datasource is a function
760
+ */
761
+ async loadRootItems(loadFn) {
762
+ try {
763
+ const result = loadFn();
764
+ const rootNodes = result instanceof Promise ? await result : result;
765
+ this.nodes.set(rootNodes);
766
+ }
767
+ catch (error) {
768
+ this.handleError('Failed to load root items', error);
769
+ this.nodes.set([]);
770
+ }
771
+ }
772
+ /**
773
+ * Load children for a node using lazy loading
774
+ */
775
+ async loadNodeChildren(node) {
776
+ if (!this.isLazyDataSource() || node.loading)
777
+ return;
778
+ if (this.treeService.hasChildren(node) || !node.childrenCount || node.childrenCount === 0) {
779
+ return;
780
+ }
781
+ const ds = this.datasource();
782
+ if (typeof ds !== 'function')
783
+ return;
784
+ try {
785
+ node.loading = true;
786
+ this.loadingNodes.update((set) => new Set(set).add(node.id));
787
+ this.refreshNodes();
788
+ const result = ds(node.id);
789
+ const children = result instanceof Promise ? await result : result;
790
+ node.children = children;
791
+ node.childrenCount = children.length;
792
+ }
793
+ catch (error) {
794
+ this.handleError('Failed to load children', error);
795
+ node.childrenCount = 0;
796
+ }
797
+ finally {
798
+ node.loading = false;
799
+ this.loadingNodes.update((set) => {
800
+ const newSet = new Set(set);
801
+ newSet.delete(node.id);
802
+ return newSet;
803
+ });
804
+ this.refreshNodes();
805
+ }
806
+ }
807
+ /**
808
+ * Internal method to refresh nodes signal and sync back to datasource if it's an array
809
+ * Creates new array references for all nested children to ensure reactivity
357
810
  */
358
- handleNodeExpandClick(node) {
359
- const selectedNode = node.data;
360
- if (this.itemsPromise && node.data[this.expandedField()] && !node?.data[this.childrenField()]?.length) {
361
- this.setNodeLoading(selectedNode[this.valueField()], true);
362
- this.fetchData(selectedNode);
811
+ refreshNodes() {
812
+ const currentNodes = this.nodes();
813
+ // Create new array references for all nested children to ensure reactivity
814
+ // This ensures Angular's change detection picks up changes even with callback datasource
815
+ this.ensureNewArrayReferences(currentNodes);
816
+ this.nodes.set([...currentNodes]);
817
+ if (!this.isLazyDataSource() && !this.isUpdatingFromDatasource) {
818
+ this.isUpdatingFromDatasource = true;
819
+ this.datasource.set([...currentNodes]);
820
+ setTimeout(() => {
821
+ this.isUpdatingFromDatasource = false;
822
+ }, 0);
363
823
  }
364
- this.onCollapsedChanged.emit({ component: this, data: node.data, nativeElement: this.nativeElement });
365
824
  }
366
- handleUnActiveNode(unActiveSource) {
367
- unActiveSource.forEach((child) => {
368
- child[this.activeField()] = false;
369
- if (child?.[this.childrenField()]?.length) {
370
- this.handleUnActiveNode(child[this.childrenField()]);
825
+ /**
826
+ * Recursively ensure all children arrays have new references to trigger change detection
827
+ * Mutates the tree structure by replacing children arrays with new array references
828
+ */
829
+ ensureNewArrayReferences(nodes) {
830
+ for (const node of nodes) {
831
+ if (node.children && node.children.length > 0) {
832
+ // Create new array reference for children
833
+ node.children = [...node.children];
834
+ // Recursively process nested children
835
+ this.ensureNewArrayReferences(node.children);
371
836
  }
837
+ }
838
+ }
839
+ /**
840
+ * Handle single selection mode
841
+ */
842
+ handleSingleSelection(node, event) {
843
+ this.treeService.deselectAllNodes(this.nodes());
844
+ node.selected = true;
845
+ node.indeterminate = false;
846
+ this.refreshNodes();
847
+ this.onNodeSelect.emit({
848
+ component: this,
849
+ node,
850
+ nativeEvent: event,
851
+ isUserInteraction: true,
372
852
  });
373
853
  }
374
- isNodeLoading(nodeId) {
375
- return this.loadingState()[nodeId] || false;
376
- }
377
- setNodeLoading(nodeId, isLoading) {
378
- this.loadingState.update((state) => ({
379
- ...state,
380
- [nodeId]: isLoading,
381
- }));
382
- }
383
- executeOnTreeNode(node, operation, value) {
384
- switch (operation) {
385
- case 'active':
386
- node[this.activeField()] = value;
854
+ /**
855
+ * Handle multiple selection mode with checkOnClick
856
+ */
857
+ handleMultipleSelection(node, event) {
858
+ const newValue = !node.selected;
859
+ node.selected = newValue;
860
+ node.indeterminate = false;
861
+ if (this.checkChildrenOnSelect() && node.children) {
862
+ this.treeService.selectAllChildren(node.children, newValue);
863
+ }
864
+ if (this.intermediateState()) {
865
+ this.treeService.updateParentStates(this.nodes(), node, this.intermediateState());
866
+ }
867
+ this.refreshNodes();
868
+ this.onNodeSelect.emit({
869
+ component: this,
870
+ node,
871
+ nativeEvent: event,
872
+ isUserInteraction: true,
873
+ });
874
+ }
875
+ /**
876
+ * Get array reference by drop list ID
877
+ */
878
+ getArrayByListId(listId) {
879
+ return this.treeService.getArrayByListId(this.nodes(), listId);
880
+ }
881
+ /**
882
+ * Find parent node by list ID
883
+ */
884
+ findParentByListId(listId) {
885
+ return this.treeService.findParentByListId(this.nodes(), listId);
886
+ }
887
+ /**
888
+ * Check if move operation is allowed based on dragOperationType
889
+ */
890
+ canMoveToParent() {
891
+ return this.dragOperationType() !== 'order-only';
892
+ }
893
+ /**
894
+ * Check if reorder operation is allowed based on dragOperationType
895
+ */
896
+ canReorder() {
897
+ return this.dragOperationType() !== 'move';
898
+ }
899
+ /**
900
+ * Handle reordering within the same list */
901
+ handleReorder(event, targetArray, parentNode) {
902
+ if (!this.canReorder())
903
+ return;
904
+ const movedNode = targetArray[event.previousIndex];
905
+ moveItemInArray(targetArray, event.previousIndex, event.currentIndex);
906
+ this.emitDropEvents(movedNode, parentNode, parentNode, event.previousIndex, event.currentIndex, true);
907
+ }
908
+ /**
909
+ * Handle moving between different lists
910
+ */
911
+ handleMove(event, targetArray, parentNode) {
912
+ if (!this.canMoveToParent())
913
+ return;
914
+ const sourceListId = event.previousContainer.element.id;
915
+ const sourceArray = this.getArrayByListId(sourceListId);
916
+ if (!sourceArray)
917
+ return;
918
+ const movedNode = sourceArray[event.previousIndex];
919
+ if (parentNode && !this.treeService.isValidDropTarget(movedNode, parentNode))
920
+ return;
921
+ if (!this.emitBeforeDropEvent(movedNode, sourceListId, parentNode, event.previousIndex, event.currentIndex)) {
922
+ return;
923
+ }
924
+ transferArrayItem(sourceArray, targetArray, event.previousIndex, event.currentIndex);
925
+ this.emitDropEvents(movedNode, this.findParentByListId(sourceListId), parentNode, event.previousIndex, event.currentIndex, false);
926
+ }
927
+ /**
928
+ * Emit beforeDrop event and return whether to continue
929
+ */
930
+ emitBeforeDropEvent(movedNode, sourceListId, currentParent, previousIndex, currentIndex) {
931
+ const beforeDropEvent = {
932
+ component: this,
933
+ movedNode,
934
+ previousParent: this.findParentByListId(sourceListId),
935
+ currentParent,
936
+ previousIndex,
937
+ currentIndex,
938
+ canceled: false,
939
+ };
940
+ this.onBeforeDrop.emit(beforeDropEvent);
941
+ return !beforeDropEvent.canceled;
942
+ }
943
+ /**
944
+ * Emit drop events based on operation type
945
+ */
946
+ emitDropEvents(node, previousParent, currentParent, previousIndex, currentIndex, isReorder) {
947
+ const dropEvent = {
948
+ component: this,
949
+ node,
950
+ previousParent,
951
+ currentParent,
952
+ previousIndex,
953
+ currentIndex,
954
+ };
955
+ if (isReorder) {
956
+ this.onOrderChange.emit(dropEvent);
957
+ }
958
+ else {
959
+ this.onMoveChange.emit(dropEvent);
960
+ }
961
+ this.onItemsChange.emit(dropEvent);
962
+ }
963
+ /**
964
+ * Get the currently focused node
965
+ */
966
+ getFocusedNode() {
967
+ const focusedId = this.focusedNodeId();
968
+ if (!focusedId)
969
+ return null;
970
+ return this.treeService.findNodeById(this.nodes(), focusedId);
971
+ }
972
+ /**
973
+ * Set focus to a node by ID
974
+ */
975
+ focusNodeById(nodeId) {
976
+ this.focusedNodeId.set(nodeId);
977
+ setTimeout(() => {
978
+ const element = document.querySelector(`[data-tree-node-id="${nodeId}"]`);
979
+ if (element) {
980
+ element.focus();
981
+ element.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
982
+ }
983
+ }, 0);
984
+ }
985
+ /**
986
+ * Handle keyboard navigation keys
987
+ */
988
+ handleNavigationKey(event, flatList, currentIndex, currentFocused) {
989
+ let targetIndex = currentIndex;
990
+ let shouldPreventDefault = true;
991
+ let handled = true;
992
+ switch (event.key) {
993
+ case 'ArrowUp':
994
+ if (currentIndex > 0) {
995
+ targetIndex = currentIndex - 1;
996
+ }
997
+ else {
998
+ shouldPreventDefault = false;
999
+ }
387
1000
  break;
388
- case 'expand':
389
- node[this.expandedField()] = true;
390
- if (this.itemsPromise && node[this.hasChildField()] && !node[this.childrenField()]?.length) {
391
- this.handleNodeExpandClick({ data: node, nativeElement: this.nativeElement, component: this });
1001
+ case 'ArrowDown':
1002
+ if (currentIndex < flatList.length - 1) {
1003
+ targetIndex = currentIndex + 1;
1004
+ }
1005
+ else if (currentIndex === -1) {
1006
+ targetIndex = 0;
1007
+ }
1008
+ else {
1009
+ shouldPreventDefault = false;
392
1010
  }
393
1011
  break;
394
- case 'visible':
395
- node[this.visibleField()] = value;
1012
+ case 'ArrowLeft':
1013
+ if (currentFocused) {
1014
+ if (currentFocused.expanded && this.shouldShowExpandToggle(currentFocused)) {
1015
+ this.toggleNode(currentFocused, event);
1016
+ return { handled: true, shouldPreventDefault: true, targetIndex: null };
1017
+ }
1018
+ else {
1019
+ const currentItem = flatList[currentIndex];
1020
+ if (currentItem?.parent) {
1021
+ targetIndex = flatList.findIndex((item) => item.node.id === currentItem.parent.id);
1022
+ }
1023
+ else {
1024
+ shouldPreventDefault = false;
1025
+ }
1026
+ }
1027
+ }
1028
+ else {
1029
+ shouldPreventDefault = false;
1030
+ }
396
1031
  break;
397
- case 'disabled':
398
- node[this.disableField()] = value;
1032
+ case 'ArrowRight':
1033
+ if (currentFocused) {
1034
+ if (!currentFocused.expanded && this.shouldShowExpandToggle(currentFocused)) {
1035
+ this.toggleNode(currentFocused, event);
1036
+ return { handled: true, shouldPreventDefault: true, targetIndex: null };
1037
+ }
1038
+ else if (currentFocused.expanded &&
1039
+ this.treeService.hasChildren(currentFocused) &&
1040
+ currentFocused.children) {
1041
+ const children = currentFocused.children;
1042
+ if (children.length > 0) {
1043
+ const firstChild = children[0];
1044
+ targetIndex = flatList.findIndex((item) => item.node.id === firstChild.id);
1045
+ if (targetIndex === -1) {
1046
+ const updatedFlatList = this.treeService.buildFlatNodeList(this.nodes());
1047
+ targetIndex = updatedFlatList.findIndex((item) => item.node.id === firstChild.id);
1048
+ if (targetIndex >= 0 && targetIndex < updatedFlatList.length) {
1049
+ this.focusNodeById(updatedFlatList[targetIndex].node.id);
1050
+ return { handled: true, shouldPreventDefault: true, targetIndex: null };
1051
+ }
1052
+ }
1053
+ }
1054
+ else {
1055
+ shouldPreventDefault = false;
1056
+ }
1057
+ }
1058
+ else {
1059
+ shouldPreventDefault = false;
1060
+ }
1061
+ }
1062
+ else {
1063
+ shouldPreventDefault = false;
1064
+ }
1065
+ break;
1066
+ case 'Home':
1067
+ targetIndex = 0;
1068
+ break;
1069
+ case 'End':
1070
+ targetIndex = flatList.length - 1;
1071
+ break;
1072
+ case ' ':
1073
+ case 'Space':
1074
+ if (currentFocused && this.selectMode() === 'multiple') {
1075
+ event.preventDefault();
1076
+ this.handleSpaceKeySelection(currentFocused, event);
1077
+ return { handled: true, shouldPreventDefault: true, targetIndex: null };
1078
+ }
1079
+ shouldPreventDefault = false;
1080
+ break;
1081
+ case 'Enter':
1082
+ if (currentFocused) {
1083
+ event.preventDefault();
1084
+ this.handleEnterKeySelection(currentFocused, event);
1085
+ return { handled: true, shouldPreventDefault: true, targetIndex: null };
1086
+ }
1087
+ shouldPreventDefault = false;
399
1088
  break;
400
1089
  default:
1090
+ if ((event.ctrlKey || event.metaKey) && event.key === 'Enter') {
1091
+ if (currentFocused && this.selectMode() === 'multiple') {
1092
+ event.preventDefault();
1093
+ this.handleCtrlEnterSelection(currentFocused, event);
1094
+ return { handled: true, shouldPreventDefault: true, targetIndex: null };
1095
+ }
1096
+ }
1097
+ handled = false;
1098
+ shouldPreventDefault = false;
401
1099
  break;
402
1100
  }
403
- /**
404
- *
405
- * for detect changes treeviewitem
406
- *
407
- */
408
- this.executorChanges.set(operation);
1101
+ return { handled, shouldPreventDefault, targetIndex };
409
1102
  }
410
- refresh() {
411
- if (this.itemsPromise) {
412
- this.fetchData();
1103
+ /**
1104
+ * Handle Space key selection
1105
+ */
1106
+ handleSpaceKeySelection(node, event) {
1107
+ const newValue = !node.selected;
1108
+ node.selected = newValue;
1109
+ node.indeterminate = false;
1110
+ if (this.checkChildrenOnSelect() && node.children) {
1111
+ this.treeService.selectAllChildren(node.children, newValue);
413
1112
  }
414
- }
415
- async setNodeExpandAndChildren(valueFields, value) {
416
- const nodesToExpand = [];
417
- for (const valueField of valueFields) {
418
- const foundNodes = this.findNodesByValueField(this.itemsSignal(), valueField);
419
- nodesToExpand.push(...foundNodes);
1113
+ if (this.intermediateState()) {
1114
+ this.treeService.updateParentStates(this.nodes(), node, this.intermediateState());
420
1115
  }
421
- await Promise.all(nodesToExpand.map((node) => this.expandNodeAndAllChildren(node, value)));
1116
+ this.refreshNodes();
1117
+ this.onNodeSelect.emit({
1118
+ component: this,
1119
+ node,
1120
+ nativeEvent: event,
1121
+ isUserInteraction: true,
1122
+ });
422
1123
  }
423
- findNodesByValueField(nodes, valueField) {
424
- const results = [];
425
- for (const node of nodes) {
426
- if (node[this.valueField()] === valueField) {
427
- results.push(node);
1124
+ /**
1125
+ * Handle Enter key selection
1126
+ */
1127
+ handleEnterKeySelection(node, event) {
1128
+ const mode = this.selectMode();
1129
+ this.treeService.deselectAllNodes(this.nodes());
1130
+ node.selected = true;
1131
+ node.indeterminate = false;
1132
+ if (mode === 'multiple') {
1133
+ if (this.checkChildrenOnSelect() && node.children) {
1134
+ this.treeService.selectAllChildren(node.children, true);
428
1135
  }
429
- if (node[this.childrenField()]?.length) {
430
- results.push(...this.findNodesByValueField(node[this.childrenField()], valueField));
1136
+ if (this.intermediateState()) {
1137
+ this.treeService.updateParentStates(this.nodes(), node, this.intermediateState());
431
1138
  }
432
1139
  }
433
- return results;
1140
+ this.refreshNodes();
1141
+ this.onNodeSelect.emit({
1142
+ component: this,
1143
+ node,
1144
+ nativeEvent: event,
1145
+ isUserInteraction: true,
1146
+ });
1147
+ }
1148
+ /**
1149
+ * Handle Ctrl/Cmd + Enter key selection
1150
+ */
1151
+ handleCtrlEnterSelection(node, event) {
1152
+ const newValue = !node.selected;
1153
+ node.selected = newValue;
1154
+ node.indeterminate = false;
1155
+ if (this.checkChildrenOnSelect() && node.children) {
1156
+ this.treeService.selectAllChildren(node.children, newValue);
1157
+ }
1158
+ if (this.intermediateState()) {
1159
+ this.treeService.updateParentStates(this.nodes(), node, this.intermediateState());
1160
+ }
1161
+ this.refreshNodes();
1162
+ this.onNodeSelect.emit({
1163
+ component: this,
1164
+ node,
1165
+ nativeEvent: event,
1166
+ isUserInteraction: true,
1167
+ });
434
1168
  }
435
- async expandNodeAndAllChildren(node, value) {
436
- node[this.expandedField()] = value;
437
- if (value && this.itemsPromise && node[this.hasChildField()] && !node[this.childrenField()]?.length) {
438
- await this.setNodeLoading(node[this.valueField()], true);
439
- await this.fetchData(node);
1169
+ /**
1170
+ * Type guard to check if value is an Event
1171
+ */
1172
+ isEvent(value) {
1173
+ return value instanceof Event;
1174
+ }
1175
+ /**
1176
+ * Handle errors consistently
1177
+ */
1178
+ handleError(message, error) {
1179
+ if (error instanceof Error) {
1180
+ console.error(`${message}:`, error.message);
440
1181
  }
441
- if (node[this.childrenField()]?.length) {
442
- await Promise.all(node[this.childrenField()].map((child) => this.expandNodeAndAllChildren(child, value)));
1182
+ else {
1183
+ console.error(`${message}:`, error);
443
1184
  }
444
1185
  }
445
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
446
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: AXTreeViewComponent, isStandalone: true, selector: "ax-tree-view", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, showCheckbox: { classPropertyName: "showCheckbox", publicName: "showCheckbox", isSignal: true, isRequired: false, transformFunction: null }, hasCheckboxField: { classPropertyName: "hasCheckboxField", publicName: "hasCheckboxField", isSignal: true, isRequired: false, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, selectionBehavior: { classPropertyName: "selectionBehavior", publicName: "selectionBehavior", isSignal: true, isRequired: false, transformFunction: null }, selectionScope: { classPropertyName: "selectionScope", publicName: "selectionScope", isSignal: true, isRequired: false, transformFunction: null }, focusNodeEnabled: { classPropertyName: "focusNodeEnabled", publicName: "focusNodeEnabled", isSignal: true, isRequired: false, transformFunction: null }, valueField: { classPropertyName: "valueField", publicName: "valueField", isSignal: true, isRequired: false, transformFunction: null }, textField: { classPropertyName: "textField", publicName: "textField", isSignal: true, isRequired: false, transformFunction: null }, visibleField: { classPropertyName: "visibleField", publicName: "visibleField", isSignal: true, isRequired: false, transformFunction: null }, disableField: { classPropertyName: "disableField", publicName: "disableField", isSignal: true, isRequired: false, transformFunction: null }, hasChildField: { classPropertyName: "hasChildField", publicName: "hasChildField", isSignal: true, isRequired: false, transformFunction: null }, selectedField: { classPropertyName: "selectedField", publicName: "selectedField", isSignal: true, isRequired: false, transformFunction: null }, expandedField: { classPropertyName: "expandedField", publicName: "expandedField", isSignal: true, isRequired: false, transformFunction: null }, tooltipField: { classPropertyName: "tooltipField", publicName: "tooltipField", isSignal: true, isRequired: false, transformFunction: null }, childrenField: { classPropertyName: "childrenField", publicName: "childrenField", isSignal: true, isRequired: false, transformFunction: null }, activeField: { classPropertyName: "activeField", publicName: "activeField", isSignal: true, isRequired: false, transformFunction: null }, indeterminateField: { classPropertyName: "indeterminateField", publicName: "indeterminateField", isSignal: true, isRequired: false, transformFunction: null }, parentField: { classPropertyName: "parentField", publicName: "parentField", isSignal: true, isRequired: false, transformFunction: null }, iconField: { classPropertyName: "iconField", publicName: "iconField", isSignal: true, isRequired: false, transformFunction: null }, toggleIcons: { classPropertyName: "toggleIcons", publicName: "toggleIcons", isSignal: true, isRequired: false, transformFunction: null }, look: { classPropertyName: "look", publicName: "look", isSignal: true, isRequired: false, transformFunction: null }, showEmptyNodeMassage: { classPropertyName: "showEmptyNodeMassage", publicName: "showEmptyNodeMassage", isSignal: true, isRequired: false, transformFunction: null }, itemTemplate: { classPropertyName: "itemTemplate", publicName: "itemTemplate", isSignal: false, isRequired: false, transformFunction: null }, emptyTemplate: { classPropertyName: "emptyTemplate", publicName: "emptyTemplate", isSignal: false, isRequired: false, transformFunction: null }, expandOn: { classPropertyName: "expandOn", publicName: "expandOn", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSelectionChanged: "onSelectionChanged", onItemSelectedChanged: "onItemSelectedChanged", onNodeClick: "onNodeClick", onCollapsedChanged: "onCollapsedChanged", onNodedbClick: "onNodedbClick" }, host: { properties: { "class": "this.__hostClass" } }, providers: [
447
- { provide: AXComponent, useExisting: AXTreeViewComponent },
448
- { provide: AXTreeViewBase, useExisting: AXTreeViewComponent },
449
- ], usesInheritance: true, ngImport: i0, template: "@if (resolvedItems?.length) {\n @for (node of resolvedItems; track $index) {\n <ng-container [ngTemplateOutlet]=\"recursion\" [ngTemplateOutletContext]=\"{ $implicit: node }\"></ng-container>\n }\n} @else {\n <ng-container [ngTemplateOutlet]=\"emptyTemplate || empty\"></ng-container>\n}\n\n<ng-template #recursion let-item>\n @if (item[visibleField()] !== false) {\n <ax-tree-view-item\n [item]=\"item\"\n [isExpanded]=\"item[expandedField()]\"\n [(isActive)]=\"item[activeField()]\"\n [isLoading]=\"isNodeLoading(item[valueField()])\"\n [executorChanges]=\"executorChanges()\"\n >\n @if (\n (showCheckbox() && selectionScope() === 'all' && item[hasCheckboxField()] !== false) ||\n (showCheckbox() &&\n selectionScope() === 'parent' &&\n item[childrenField()]?.length &&\n item[hasCheckboxField()]) !== false ||\n (showCheckbox() &&\n selectionScope() === 'children' &&\n !item[childrenField()]?.length &&\n item[hasCheckboxField()] !== false)\n ) {\n <ax-check-box\n [disabled]=\"item[disableField()]\"\n [indeterminate]=\"item[indeterminateField()]\"\n [(ngModel)]=\"item[selectedField()]\"\n (onValueChanged)=\"handleNodeSelectionClick($event, item)\"\n ></ax-check-box>\n }\n @if (item[iconField()]) {\n <ax-prefix>\n <ax-icon [icon]=\"item[iconField()]\"></ax-icon>\n </ax-prefix>\n }\n @if (item[textField()]) {\n <ax-text>{{ item[textField()] }}</ax-text>\n }\n\n @for (child of item?.[childrenField()]; track $index) {\n <ng-container [ngTemplateOutlet]=\"recursion\" [ngTemplateOutletContext]=\"{ $implicit: child }\"></ng-container>\n }\n </ax-tree-view-item>\n }\n</ng-template>\n\n<ng-template #empty>\n {{ '@acorex:common.general.no-result-found' | translate | async }}\n</ng-template>\n", styles: ["ax-tree-view{--ax-comp-tree-view-arrow-size: .875rem;--ax-comp-tree-view-text-size: .875rem;--ax-comp-tree-view-active-bg-color: var(--ax-sys-color-primary-surface);--ax-comp-tree-view-active-text-color: var(--ax-sys-color-on-primary-surface);--ax-comp-tree-view-hover-bg-color: var(--ax-sys-color-dark-surface);--ax-comp-tree-view-indicator-size: 2px}ax-tree-view:has(>ax-tree-view-item i) ax-tree-view-item .ax-tree-view-container:not(:has(i)){padding-inline-start:1.5rem}ax-tree-view.ax-look-with-line ax-tree-view-item{position:relative}ax-tree-view.ax-look-with-line ax-tree-view-item:before{content:\"\";position:absolute;top:0;inset-inline-start:.625rem;width:1px;height:100%;background-color:#ccc}ax-tree-view.ax-look-with-line ax-tree-view-item .ax-tree-view-container{padding-inline-start:1.25rem}ax-tree-view.ax-look-with-line ax-tree-view-item .ax-tree-view-container .ax-tree-view-icon-container{padding:.25rem}ax-tree-view ax-tree-view-item ax-check-box{margin-inline-start:.5rem}ax-tree-view ax-tree-view-item .ax-tree-view-container{display:flex;align-items:center;margin-bottom:.125rem}ax-tree-view ax-tree-view-item .ax-tree-view-container ax-text{font-size:var(--ax-comp-tree-view-text-size)}ax-tree-view ax-tree-view-item .ax-tree-view-container{cursor:pointer}ax-tree-view ax-tree-view-item .ax-tree-view-container .ax-checkbox-end-side{display:none!important}ax-tree-view ax-tree-view-item .ax-tree-view-container .ax-tree-view-arrow{font-size:var(--ax-comp-tree-view-arrow-size)!important}ax-tree-view ax-tree-view-item .ax-tree-view-container ax-suffix:empty{display:none}ax-tree-view ax-tree-view-item .ax-tree-view-container .ax-tree-view-icon-container{width:1.5rem;height:1.5rem;display:flex;align-items:center;justify-content:center}ax-tree-view ax-tree-view-item .ax-tree-view-container .ax-tree-view-items{display:flex;align-items:center}ax-tree-view ax-tree-view-item .ax-tree-view-container .ax-tree-view-items .ax-tree-view-items-prefix{display:flex;align-items:center;gap:.5rem;padding:.25rem .5rem;border-radius:.25rem;overflow-x:auto;margin-inline-start:.25rem}ax-tree-view ax-tree-view-item .ax-tree-view-container .ax-tree-view-items .ax-tree-view-items-prefix.ax-noselect-tree-view{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}ax-tree-view ax-tree-view-item .ax-tree-view-container .ax-tree-view-items .ax-tree-view-items-prefix.ax-state-tree-view-active{background-color:rgba(var(--ax-comp-tree-view-active-bg-color));color:rgba(var(--ax-comp-tree-view-active-text-color))}ax-tree-view ax-tree-view-item .ax-tree-view-container .ax-tree-view-items .ax-tree-view-items-prefix:hover:not(.ax-state-tree-view-active){background-color:rgba(var(--ax-comp-tree-view-hover-bg-color))}ax-tree-view ax-tree-view-item .ax-tree-view-child{padding-inline-start:1rem}ax-tree-view ax-tree-view-item .ax-tree-view-child .ax-tree-view-container:not(:has(.ax-tree-view-icon-container i)){padding-inline-start:1.5rem}ax-tree-view ax-tree-view-item .ax-tree-view-child.ax-tree-view-empty-child{padding-inline-start:2rem}ax-tree-view ax-tree-view-item .ax-state-disabled{cursor:not-allowed!important;opacity:.5!important}@keyframes fadeSlideIn{0%{opacity:0;max-height:0}to{opacity:1;max-height:50px}}@keyframes fadeSlideOut{0%{opacity:1;max-height:50px}to{opacity:0;max-height:0}}ax-tree-view ax-tree-view-item .ax-fade-slide-in{animation:fadeSlideIn var(--ax-sys-transition-duration) var(--ax-sys-transition-timing-function)}ax-tree-view ax-tree-view-item .ax-fade-slide-out{animation:fadeSlideOut var(--ax-sys-transition-duration) var(--ax-sys-transition-timing-function)}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: AXTreeViewItemComponent, selector: "ax-tree-view-item", inputs: ["item", "isExpanded", "isActive", "isLoading", "executorChanges"], outputs: ["isExpandedChange", "isActiveChange"] }, { kind: "component", type: AXCheckBoxComponent, selector: "ax-check-box", inputs: ["disabled", "tabIndex", "readonly", "color", "value", "name", "id", "isLoading", "indeterminate"], outputs: ["onBlur", "onFocus", "valueChange", "onValueChanged"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "component", type: AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "pipe", type: AXTranslatorPipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
1186
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1187
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: AXTreeViewComponent, isStandalone: true, selector: "ax-tree-view", inputs: { datasource: { classPropertyName: "datasource", publicName: "datasource", isSignal: true, isRequired: true, transformFunction: null }, selectMode: { classPropertyName: "selectMode", publicName: "selectMode", isSignal: true, isRequired: false, transformFunction: null }, showCheckbox: { classPropertyName: "showCheckbox", publicName: "showCheckbox", isSignal: true, isRequired: false, transformFunction: null }, checkChildrenOnSelect: { classPropertyName: "checkChildrenOnSelect", publicName: "checkChildrenOnSelect", isSignal: true, isRequired: false, transformFunction: null }, intermediateState: { classPropertyName: "intermediateState", publicName: "intermediateState", isSignal: true, isRequired: false, transformFunction: null }, checkOnClick: { classPropertyName: "checkOnClick", publicName: "checkOnClick", isSignal: true, isRequired: false, transformFunction: null }, dragMode: { classPropertyName: "dragMode", publicName: "dragMode", isSignal: true, isRequired: false, transformFunction: null }, dragOperationType: { classPropertyName: "dragOperationType", publicName: "dragOperationType", isSignal: true, isRequired: false, transformFunction: null }, showIcons: { classPropertyName: "showIcons", publicName: "showIcons", isSignal: true, isRequired: false, transformFunction: null }, showChildrenBadge: { classPropertyName: "showChildrenBadge", publicName: "showChildrenBadge", isSignal: true, isRequired: false, transformFunction: null }, expandedIcon: { classPropertyName: "expandedIcon", publicName: "expandedIcon", isSignal: true, isRequired: false, transformFunction: null }, collapsedIcon: { classPropertyName: "collapsedIcon", publicName: "collapsedIcon", isSignal: true, isRequired: false, transformFunction: null }, indentSize: { classPropertyName: "indentSize", publicName: "indentSize", isSignal: true, isRequired: false, transformFunction: null }, nodeHeight: { classPropertyName: "nodeHeight", publicName: "nodeHeight", isSignal: true, isRequired: false, transformFunction: null }, look: { classPropertyName: "look", publicName: "look", isSignal: true, isRequired: false, transformFunction: null }, itemTemplate: { classPropertyName: "itemTemplate", publicName: "itemTemplate", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { datasource: "datasourceChange", onBeforeDrop: "onBeforeDrop", onNodeToggle: "onNodeToggle", onNodeSelect: "onNodeSelect", onOrderChange: "onOrderChange", onMoveChange: "onMoveChange", onItemsChange: "onItemsChange" }, host: { attributes: { "role": "tree", "tabindex": "0" }, listeners: { "keydown": "handleKeyDown($event)", "focus": "onTreeFocus($event)", "blur": "onTreeBlur($event)" }, properties: { "class.ax-tree-view-default": "look() === 'default'", "class.ax-tree-view-card": "look() === 'card'", "class.ax-tree-view-with-line": "look() === 'with-line'", "class.ax-tree-view-rtl": "isRtl", "style.--ax-tree-view-indent-size": "indentSize() + 'px'", "style.--ax-tree-view-line-offset": "(indentSize() / 2) + 'px'", "attr.aria-label": "\"Tree navigation\"" }, classAttribute: "ax-tree-view" }, providers: [AXTreeViewService], ngImport: i0, template: "<!-- Root drop list -->\n<div\n axFocusTrap\n [axDropList]=\"dragMode() !== 'none'\"\n [sortingDisabled]=\"false\"\n [id]=\"getListId()\"\n [attr.data-node-id]=\"null\"\n dropListGroup=\"ax-tree-view-nodes\"\n (dropListDropped)=\"onDrop($event)\"\n class=\"ax-tree-view-drop-list\"\n [class.ax-tree-view-card]=\"look() === 'card'\"\n [class.ax-tree-view-with-lines]=\"look() === 'with-line'\"\n [class.ax-tree-view-compact]=\"nodeHeight() === 'compact'\"\n [class.ax-tree-view-comfortable]=\"nodeHeight() === 'comfortable'\"\n role=\"group\"\n>\n @for (node of nodes(); track node.id) {\n @if (node.visible !== false) {\n <div\n [axDrag]=\"dragMode() !== 'none'\"\n [dragDisabled]=\"node.disabled\"\n [dragData]=\"node\"\n class=\"ax-tree-view-node\"\n [class.ax-tree-view-node-selected]=\"node.selected\"\n [class.ax-tree-view-node-disabled]=\"node.disabled\"\n [class.ax-tree-view-node-loading]=\"node.loading\"\n role=\"treeitem\"\n [attr.aria-level]=\"getNodeAriaLevel(0)\"\n [attr.aria-expanded]=\"getNodeAriaExpanded(node)\"\n [attr.aria-selected]=\"getNodeAriaSelected(node)\"\n [attr.aria-disabled]=\"node.disabled ? 'true' : null\"\n >\n <div\n class=\"ax-tree-view-node-content\"\n [axDropList]=\"dragMode() !== 'none'\"\n [id]=\"'ax-tree-view-node-drop-' + node.id\"\n [attr.data-node-id]=\"node.id\"\n [attr.data-tree-node-id]=\"node.id\"\n [attr.data-drop-type]=\"'onto-node'\"\n dropListGroup=\"ax-tree-view-nodes\"\n (dropListDropped)=\"onDropOntoNode($event, node)\"\n (click)=\"\n (selectMode() === 'single' || (selectMode() === 'multiple' && checkOnClick())) && onNodeClick(node, $event)\n \"\n (focus)=\"onNodeFocus(node.id)\"\n [tabindex]=\"isNodeFocused(node.id) ? 0 : -1\"\n >\n @if (dragMode() === 'handler') {\n <span class=\"ax-tree-view-drag-handle\" axDragHandle title=\"Drag to reorder\"> \u22EE\u22EE </span>\n }\n <ax-button\n class=\"ax-tree-view-expand-toggle ax-sm\"\n (onClick)=\"toggleNode(node, $any($event))\"\n [class.ax-tree-view-has-children]=\"shouldShowExpandToggle(node)\"\n [class.ax-tree-view-expanded]=\"node.expanded\"\n [disabled]=\"node.disabled || node.loading\"\n [style.visibility]=\"shouldShowExpandToggle(node) ? 'visible' : 'hidden'\"\n >\n @if (node.loading) {\n <ax-icon>\n <i class=\"fa-solid fa-spinner fa-spin ax-tree-view-loading-spinner\"></i>\n </ax-icon>\n } @else {\n <ax-icon>\n <i\n [class]=\"node.expanded ? directionExpandedIcon() : directionCollapsedIcon()\"\n class=\"ax-tree-view-toggle-icon\"\n ></i>\n </ax-icon>\n }\n </ax-button>\n @if (itemTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"itemTemplate()!\"\n [ngTemplateOutletContext]=\"getTemplateContext(node, 0)\"\n ></ng-container>\n } @else {\n @if (shouldShowCheckbox()) {\n <ax-check-box\n class=\"ax-tree-view-checkbox\"\n [ngModel]=\"node.indeterminate ? null : node.selected || false\"\n [indeterminate]=\"node.indeterminate || false\"\n (onValueChanged)=\"toggleSelection(node, $event)\"\n ></ax-check-box>\n }\n @if (showIcons() && node.icon) {\n <i [class]=\"node.icon\" class=\"ax-tree-view-node-icon\"></i>\n }\n <span class=\"ax-tree-view-node-label\">{{ node.label }}</span>\n @if (showChildrenBadge() && (node.childrenCount || (node.children && node.children.length > 0))) {\n <ax-badge\n class=\"ax-tree-view-children-badge\"\n [text]=\"(node.childrenCount ?? node.children?.length ?? 0).toString()\"\n ></ax-badge>\n }\n }\n </div>\n </div>\n @if (node.expanded && node.children && node.children.length > 0) {\n <div class=\"ax-tree-view-children\" role=\"group\">\n <ng-container\n [ngTemplateOutlet]=\"childrenList\"\n [ngTemplateOutletContext]=\"{ children: node.children, parent: node, level: 1 }\"\n ></ng-container>\n </div>\n }\n }\n }\n</div>\n\n<!-- Recursive children template -->\n<ng-template #childrenList let-children=\"children\" let-parent=\"parent\" let-level=\"level\">\n <div\n [axDropList]=\"dragMode() !== 'none'\"\n [id]=\"getListId(parent)\"\n [attr.data-node-id]=\"parent.id\"\n dropListGroup=\"ax-tree-view-nodes\"\n (dropListDropped)=\"onDrop($event, parent)\"\n class=\"ax-tree-view-drop-list\"\n role=\"group\"\n >\n @for (node of children; track node.id) {\n @if (node.visible !== false) {\n <div\n [axDrag]=\"dragMode() !== 'none'\"\n [dragDisabled]=\"node.disabled\"\n [dragData]=\"node\"\n class=\"ax-tree-view-node\"\n [class.ax-tree-view-node-selected]=\"node.selected\"\n [class.ax-tree-view-node-disabled]=\"node.disabled\"\n [class.ax-tree-view-node-loading]=\"node.loading\"\n [class.ax-tree-view-node-focused]=\"isNodeFocused(node.id)\"\n role=\"treeitem\"\n [attr.aria-level]=\"getNodeAriaLevel(level)\"\n [attr.aria-expanded]=\"getNodeAriaExpanded(node)\"\n [attr.aria-selected]=\"getNodeAriaSelected(node)\"\n [attr.aria-disabled]=\"node.disabled ? 'true' : null\"\n >\n <div\n class=\"ax-tree-view-node-content\"\n [style.padding-inline-start.px]=\"getNodePaddingInline(level)\"\n [axDropList]=\"dragMode() !== 'none'\"\n [id]=\"'ax-tree-view-node-drop-' + node.id\"\n [attr.data-node-id]=\"node.id\"\n [attr.data-tree-node-id]=\"node.id\"\n [attr.data-drop-type]=\"'onto-node'\"\n dropListGroup=\"ax-tree-view-nodes\"\n (dropListDropped)=\"onDropOntoNode($event, node)\"\n (click)=\"\n (selectMode() === 'single' || (selectMode() === 'multiple' && checkOnClick())) &&\n onNodeClick(node, $event)\n \"\n (focus)=\"onNodeFocus(node.id)\"\n (blur)=\"focusedNodeId.set(null)\"\n [tabindex]=\"isNodeFocused(node.id) ? 0 : -1\"\n >\n @if (dragMode() === 'handler') {\n <span class=\"ax-tree-view-drag-handle\" axDragHandle title=\"Drag to reorder\"> \u22EE\u22EE </span>\n }\n <ax-button\n class=\"ax-tree-view-expand-toggle ax-sm\"\n (onClick)=\"toggleNode(node, $any($event))\"\n [class.ax-tree-view-has-children]=\"shouldShowExpandToggle(node)\"\n [class.ax-tree-view-expanded]=\"node.expanded\"\n [disabled]=\"node.disabled || node.loading\"\n [style.visibility]=\"shouldShowExpandToggle(node) ? 'visible' : 'hidden'\"\n >\n @if (node.loading) {\n <ax-icon>\n <i class=\"fa-solid fa-spinner fa-spin ax-tree-view-loading-spinner\"></i>\n </ax-icon>\n } @else {\n <ax-icon>\n <i\n [class]=\"node.expanded ? directionExpandedIcon() : directionCollapsedIcon()\"\n class=\"ax-tree-view-toggle-icon\"\n ></i>\n </ax-icon>\n }\n </ax-button>\n\n @if (itemTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"itemTemplate()!\"\n [ngTemplateOutletContext]=\"getTemplateContext(node, level)\"\n ></ng-container>\n } @else {\n @if (shouldShowCheckbox()) {\n <ax-check-box\n class=\"ax-tree-view-checkbox\"\n [ngModel]=\"node.indeterminate ? null : node.selected || false\"\n [indeterminate]=\"node.indeterminate || false\"\n (onValueChanged)=\"toggleSelection(node, $event)\"\n ></ax-check-box>\n }\n @if (showIcons() && node.icon) {\n <i [class]=\"node.icon\" class=\"ax-tree-view-node-icon\"></i>\n }\n <span class=\"ax-tree-view-node-label\">{{ node.label }}</span>\n @if (showChildrenBadge() && (node.childrenCount || (node.children && node.children.length > 0))) {\n <ax-badge\n class=\"ax-tree-view-children-badge\"\n [text]=\"(node.childrenCount ?? node.children?.length ?? 0).toString()\"\n ></ax-badge>\n }\n }\n </div>\n </div>\n @if (node.expanded && node.children && node.children.length > 0) {\n <div class=\"ax-tree-view-children\" role=\"group\">\n <ng-container\n [ngTemplateOutlet]=\"childrenList\"\n [ngTemplateOutletContext]=\"{ children: node.children, parent: node, level: level + 1 }\"\n ></ng-container>\n </div>\n }\n }\n }\n </div>\n</ng-template>\n", styles: [".ax-tree-view{display:block;width:100%;--ax-comp-tree-view-indent-size: 12px;--ax-comp-tree-view-node-hover-bg: rgba(var(--ax-sys-color-on-lightest-surface), .04);--ax-comp-tree-view-node-selected-bg: rgba(var(--ax-sys-color-primary-500), .12);--ax-comp-tree-view-node-border-radius: 6px;--ax-comp-tree-view-node-margin: .25rem;--ax-comp-tree-view-line-color: rgba(var(--ax-sys-color-on-lightest-surface), .15);--ax-comp-tree-view-drag-preview-opacity: .9;--ax-comp-tree-view-drag-placeholder-bg: rgba(var(--ax-sys-color-on-lightest-surface), .02);--ax-comp-tree-view-drop-active-bg: rgba(var(--ax-sys-color-primary-500), .08);--ax-comp-tree-view-drop-active-outline: rgba(var(--ax-sys-color-primary-500), .3);--ax-comp-tree-view-content-padding: 0;--ax-comp-tree-view-content-gap: .5rem;--ax-comp-tree-view-drop-list-min-height: 2rem;--ax-comp-tree-view-drag-handle-padding: .25rem;--ax-comp-tree-view-expand-toggle-padding: .25rem;--ax-comp-tree-view-card-node-margin: .5rem;--ax-comp-tree-view-card-content-padding: 1rem;--ax-comp-tree-view-outline-offset: 2px;--ax-comp-tree-view-outline-offset-negative: -2px}.ax-tree-view-drop-list{min-height:var(--ax-comp-tree-view-drop-list-min-height)}.ax-tree-view-compact .ax-tree-view-node-content{padding:var(--ax-comp-tree-view-content-padding, .25rem .5rem);gap:var(--ax-comp-tree-view-content-gap, .375rem);font-size:.8125rem}.ax-tree-view-comfortable .ax-tree-view-node-content{padding:var(--ax-comp-tree-view-content-padding, .75rem .625rem);gap:var(--ax-comp-tree-view-content-gap, .625rem);font-size:.9375rem}.ax-tree-view-node{position:relative;margin:var(--ax-comp-tree-view-node-margin) 0;border-radius:var(--ax-comp-tree-view-node-border-radius);border:1px solid transparent;cursor:move}.ax-tree-view-node:hover:not(.ax-dragging){background:var(--ax-comp-tree-view-node-hover-bg)}.ax-tree-view-node.ax-tree-view-node-selected{background:var(--ax-comp-tree-view-node-selected-bg);border-color:currentColor}.ax-tree-view-node.ax-dragging{opacity:var(--ax-comp-tree-view-drag-placeholder-opacity);cursor:grabbing!important}.ax-tree-view-node.ax-drag-placeholder{background:var(--ax-comp-tree-view-drag-placeholder-bg)}.ax-drag-preview{opacity:var(--ax-comp-tree-view-drag-preview-opacity)!important;box-shadow:0 4px 12px rgba(var(--ax-sys-color-on-lightest-surface),.2)!important;cursor:grabbing!important;border:2px dashed currentColor!important}.ax-tree-view-node-content.ax-drop-list-sorting-active{background:var(--ax-comp-tree-view-drop-active-bg);border-radius:var(--ax-comp-tree-view-node-border-radius);outline:2px dashed var(--ax-comp-tree-view-drop-active-outline);outline-offset:var(--ax-comp-tree-view-outline-offset-negative)}.ax-tree-view-node-content{display:flex;align-items:center;gap:var(--ax-comp-tree-view-content-gap);padding:var(--ax-comp-tree-view-content-padding);cursor:pointer;-webkit-user-select:none;user-select:none;outline:none;border:1px solid transparent;border-radius:var(--ax-comp-tree-view-node-border-radius)}.ax-tree-view-node-content:focus{outline:none}.ax-tree-view-node-content:focus-visible{outline:2px solid rgba(var(--ax-sys-color-primary-500),.8);outline-offset:var(--ax-comp-tree-view-outline-offset);border-radius:var(--ax-comp-tree-view-node-border-radius)}.ax-tree-view-drag-handle{cursor:grab;opacity:.6;padding:var(--ax-comp-tree-view-drag-handle-padding)}.ax-tree-view-drag-handle:hover{opacity:1}.ax-tree-view-drag-handle:active{cursor:grabbing}.ax-tree-view-expand-toggle{background:none;border:none;cursor:pointer;padding:var(--ax-comp-tree-view-expand-toggle-padding);min-width:1.5rem;height:1.5rem}.ax-tree-view-expand-toggle:not(.ax-tree-view-has-children){opacity:0;pointer-events:none}.ax-tree-view-toggle-icon{font-size:.75rem}.ax-tree-view-node-icon{font-size:1.125rem;flex-shrink:0}.ax-tree-view-node-label{flex:1;font-size:.875rem;line-height:1rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ax-tree-view-children{padding-inline-start:var(--ax-tree-view-indent-size, var(--ax-comp-tree-view-indent-size))}.ax-tree-view-node-disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.ax-tree-view-node-loading{opacity:.7}.ax-tree-view-card .ax-tree-view-node{border:1px solid rgba(var(--ax-sys-color-border-lightest-surface),1);margin:var(--ax-comp-tree-view-card-node-margin) 0}.ax-tree-view-card .ax-tree-view-node-content{padding:var(--ax-comp-tree-view-card-content-padding)}.ax-tree-view-with-lines .ax-tree-view-children{position:relative;padding-inline-start:var(--ax-tree-view-indent-size, var(--ax-comp-tree-view-indent-size))}.ax-tree-view-with-lines .ax-tree-view-children:before{content:\"\";position:absolute;inset-inline-start:var(--ax-tree-view-line-offset, calc(var(--ax-comp-tree-view-indent-size) / 2));top:0;height:calc(100% - .875rem);width:1px;background:var(--ax-tree-view-line-color, var(--ax-comp-tree-view-line-color))}.ax-tree-view-with-lines .ax-tree-view-node{position:relative}.ax-tree-view-with-lines .ax-tree-view-node:before{content:\"\";position:absolute;inset-inline-start:calc(-1 * var(--ax-tree-view-line-offset, calc(var(--ax-comp-tree-view-indent-size) / 2)));top:60%;width:var(--ax-tree-view-line-offset, calc(var(--ax-comp-tree-view-indent-size) / 2));height:1px;background:var(--ax-tree-view-line-color, var(--ax-comp-tree-view-line-color))}.ax-tree-view-with-lines>.ax-tree-view-drop-list>.ax-tree-view-node:before,.ax-tree-view-with-lines>.ax-tree-view-node:before{display:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: AXDragDirective, selector: "[axDrag]", inputs: ["axDrag", "dragData", "dragDisabled", "dragTransition", "dragElementClone", "dropZoneGroup", "dragStartDelay", "dragResetOnDblClick", "dragLockAxis", "dragClonedTemplate", "dragCursor", "dragBoundary", "dragTransitionDuration"], outputs: ["dragPositionChanged"] }, { kind: "directive", type: AXDragHandleDirective, selector: "[axDragHandle]" }, { kind: "directive", type: AXDropListDirective, selector: "[axDropList]", inputs: ["axDropList", "sortingDisabled", "dropListGroup", "dropListOrientation"], outputs: ["dropListDropped"], exportAs: ["axDropList"] }, { kind: "directive", type: AXFocusTrapDirective, selector: "[axFocusTrap]" }, { kind: "component", type: AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "component", type: AXCheckBoxComponent, selector: "ax-check-box", inputs: ["disabled", "tabIndex", "readonly", "color", "value", "name", "id", "isLoading", "indeterminate"], outputs: ["onBlur", "onFocus", "valueChange", "onValueChanged"] }, { kind: "component", type: AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "component", type: AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
450
1188
  }
451
1189
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewComponent, decorators: [{
452
1190
  type: Component,
453
- args: [{ selector: 'ax-tree-view', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
1191
+ args: [{ selector: 'ax-tree-view', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, providers: [AXTreeViewService], imports: [
1192
+ CommonModule,
1193
+ FormsModule,
1194
+ AXDragDirective,
1195
+ AXDragHandleDirective,
1196
+ AXDropListDirective,
1197
+ AXFocusTrapDirective,
454
1198
  NgTemplateOutlet,
455
- AXTreeViewItemComponent,
1199
+ AXButtonComponent,
456
1200
  AXCheckBoxComponent,
457
- FormsModule,
458
- AXDecoratorGenericComponent,
1201
+ AXBadgeComponent,
459
1202
  AXDecoratorIconComponent,
460
- AXTranslatorPipe,
461
- AsyncPipe,
462
- ], providers: [
463
- { provide: AXComponent, useExisting: AXTreeViewComponent },
464
- { provide: AXTreeViewBase, useExisting: AXTreeViewComponent },
465
- ], template: "@if (resolvedItems?.length) {\n @for (node of resolvedItems; track $index) {\n <ng-container [ngTemplateOutlet]=\"recursion\" [ngTemplateOutletContext]=\"{ $implicit: node }\"></ng-container>\n }\n} @else {\n <ng-container [ngTemplateOutlet]=\"emptyTemplate || empty\"></ng-container>\n}\n\n<ng-template #recursion let-item>\n @if (item[visibleField()] !== false) {\n <ax-tree-view-item\n [item]=\"item\"\n [isExpanded]=\"item[expandedField()]\"\n [(isActive)]=\"item[activeField()]\"\n [isLoading]=\"isNodeLoading(item[valueField()])\"\n [executorChanges]=\"executorChanges()\"\n >\n @if (\n (showCheckbox() && selectionScope() === 'all' && item[hasCheckboxField()] !== false) ||\n (showCheckbox() &&\n selectionScope() === 'parent' &&\n item[childrenField()]?.length &&\n item[hasCheckboxField()]) !== false ||\n (showCheckbox() &&\n selectionScope() === 'children' &&\n !item[childrenField()]?.length &&\n item[hasCheckboxField()] !== false)\n ) {\n <ax-check-box\n [disabled]=\"item[disableField()]\"\n [indeterminate]=\"item[indeterminateField()]\"\n [(ngModel)]=\"item[selectedField()]\"\n (onValueChanged)=\"handleNodeSelectionClick($event, item)\"\n ></ax-check-box>\n }\n @if (item[iconField()]) {\n <ax-prefix>\n <ax-icon [icon]=\"item[iconField()]\"></ax-icon>\n </ax-prefix>\n }\n @if (item[textField()]) {\n <ax-text>{{ item[textField()] }}</ax-text>\n }\n\n @for (child of item?.[childrenField()]; track $index) {\n <ng-container [ngTemplateOutlet]=\"recursion\" [ngTemplateOutletContext]=\"{ $implicit: child }\"></ng-container>\n }\n </ax-tree-view-item>\n }\n</ng-template>\n\n<ng-template #empty>\n {{ '@acorex:common.general.no-result-found' | translate | async }}\n</ng-template>\n", styles: ["ax-tree-view{--ax-comp-tree-view-arrow-size: .875rem;--ax-comp-tree-view-text-size: .875rem;--ax-comp-tree-view-active-bg-color: var(--ax-sys-color-primary-surface);--ax-comp-tree-view-active-text-color: var(--ax-sys-color-on-primary-surface);--ax-comp-tree-view-hover-bg-color: var(--ax-sys-color-dark-surface);--ax-comp-tree-view-indicator-size: 2px}ax-tree-view:has(>ax-tree-view-item i) ax-tree-view-item .ax-tree-view-container:not(:has(i)){padding-inline-start:1.5rem}ax-tree-view.ax-look-with-line ax-tree-view-item{position:relative}ax-tree-view.ax-look-with-line ax-tree-view-item:before{content:\"\";position:absolute;top:0;inset-inline-start:.625rem;width:1px;height:100%;background-color:#ccc}ax-tree-view.ax-look-with-line ax-tree-view-item .ax-tree-view-container{padding-inline-start:1.25rem}ax-tree-view.ax-look-with-line ax-tree-view-item .ax-tree-view-container .ax-tree-view-icon-container{padding:.25rem}ax-tree-view ax-tree-view-item ax-check-box{margin-inline-start:.5rem}ax-tree-view ax-tree-view-item .ax-tree-view-container{display:flex;align-items:center;margin-bottom:.125rem}ax-tree-view ax-tree-view-item .ax-tree-view-container ax-text{font-size:var(--ax-comp-tree-view-text-size)}ax-tree-view ax-tree-view-item .ax-tree-view-container{cursor:pointer}ax-tree-view ax-tree-view-item .ax-tree-view-container .ax-checkbox-end-side{display:none!important}ax-tree-view ax-tree-view-item .ax-tree-view-container .ax-tree-view-arrow{font-size:var(--ax-comp-tree-view-arrow-size)!important}ax-tree-view ax-tree-view-item .ax-tree-view-container ax-suffix:empty{display:none}ax-tree-view ax-tree-view-item .ax-tree-view-container .ax-tree-view-icon-container{width:1.5rem;height:1.5rem;display:flex;align-items:center;justify-content:center}ax-tree-view ax-tree-view-item .ax-tree-view-container .ax-tree-view-items{display:flex;align-items:center}ax-tree-view ax-tree-view-item .ax-tree-view-container .ax-tree-view-items .ax-tree-view-items-prefix{display:flex;align-items:center;gap:.5rem;padding:.25rem .5rem;border-radius:.25rem;overflow-x:auto;margin-inline-start:.25rem}ax-tree-view ax-tree-view-item .ax-tree-view-container .ax-tree-view-items .ax-tree-view-items-prefix.ax-noselect-tree-view{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}ax-tree-view ax-tree-view-item .ax-tree-view-container .ax-tree-view-items .ax-tree-view-items-prefix.ax-state-tree-view-active{background-color:rgba(var(--ax-comp-tree-view-active-bg-color));color:rgba(var(--ax-comp-tree-view-active-text-color))}ax-tree-view ax-tree-view-item .ax-tree-view-container .ax-tree-view-items .ax-tree-view-items-prefix:hover:not(.ax-state-tree-view-active){background-color:rgba(var(--ax-comp-tree-view-hover-bg-color))}ax-tree-view ax-tree-view-item .ax-tree-view-child{padding-inline-start:1rem}ax-tree-view ax-tree-view-item .ax-tree-view-child .ax-tree-view-container:not(:has(.ax-tree-view-icon-container i)){padding-inline-start:1.5rem}ax-tree-view ax-tree-view-item .ax-tree-view-child.ax-tree-view-empty-child{padding-inline-start:2rem}ax-tree-view ax-tree-view-item .ax-state-disabled{cursor:not-allowed!important;opacity:.5!important}@keyframes fadeSlideIn{0%{opacity:0;max-height:0}to{opacity:1;max-height:50px}}@keyframes fadeSlideOut{0%{opacity:1;max-height:50px}to{opacity:0;max-height:0}}ax-tree-view ax-tree-view-item .ax-fade-slide-in{animation:fadeSlideIn var(--ax-sys-transition-duration) var(--ax-sys-transition-timing-function)}ax-tree-view ax-tree-view-item .ax-fade-slide-out{animation:fadeSlideOut var(--ax-sys-transition-duration) var(--ax-sys-transition-timing-function)}\n"] }]
466
- }], propDecorators: { __hostClass: [{
467
- type: HostBinding,
468
- args: ['class']
469
- }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], showCheckbox: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCheckbox", required: false }] }], hasCheckboxField: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasCheckboxField", required: false }] }], selectionMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionMode", required: false }] }], selectionBehavior: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionBehavior", required: false }] }], selectionScope: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionScope", required: false }] }], focusNodeEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "focusNodeEnabled", required: false }] }], valueField: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueField", required: false }] }], textField: [{ type: i0.Input, args: [{ isSignal: true, alias: "textField", required: false }] }], visibleField: [{ type: i0.Input, args: [{ isSignal: true, alias: "visibleField", required: false }] }], disableField: [{ type: i0.Input, args: [{ isSignal: true, alias: "disableField", required: false }] }], hasChildField: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasChildField", required: false }] }], selectedField: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedField", required: false }] }], expandedField: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandedField", required: false }] }], tooltipField: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipField", required: false }] }], childrenField: [{ type: i0.Input, args: [{ isSignal: true, alias: "childrenField", required: false }] }], activeField: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeField", required: false }] }], indeterminateField: [{ type: i0.Input, args: [{ isSignal: true, alias: "indeterminateField", required: false }] }], parentField: [{ type: i0.Input, args: [{ isSignal: true, alias: "parentField", required: false }] }], iconField: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconField", required: false }] }], toggleIcons: [{ type: i0.Input, args: [{ isSignal: true, alias: "toggleIcons", required: false }] }], look: [{ type: i0.Input, args: [{ isSignal: true, alias: "look", required: false }] }], showEmptyNodeMassage: [{ type: i0.Input, args: [{ isSignal: true, alias: "showEmptyNodeMassage", required: false }] }], onSelectionChanged: [{ type: i0.Output, args: ["onSelectionChanged"] }], onItemSelectedChanged: [{ type: i0.Output, args: ["onItemSelectedChanged"] }], onNodeClick: [{ type: i0.Output, args: ["onNodeClick"] }], onCollapsedChanged: [{ type: i0.Output, args: ["onCollapsedChanged"] }], onNodedbClick: [{ type: i0.Output, args: ["onNodedbClick"] }], itemTemplate: [{
470
- type: Input
471
- }], emptyTemplate: [{
472
- type: Input
473
- }], expandOn: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandOn", required: false }] }] } });
1203
+ ], host: {
1204
+ class: 'ax-tree-view',
1205
+ '[class.ax-tree-view-default]': "look() === 'default'",
1206
+ '[class.ax-tree-view-card]': "look() === 'card'",
1207
+ '[class.ax-tree-view-with-line]': "look() === 'with-line'",
1208
+ '[class.ax-tree-view-rtl]': 'isRtl',
1209
+ '[style.--ax-tree-view-indent-size]': "indentSize() + 'px'",
1210
+ '[style.--ax-tree-view-line-offset]': "(indentSize() / 2) + 'px'",
1211
+ role: 'tree',
1212
+ '[attr.aria-label]': '"Tree navigation"',
1213
+ '(keydown)': 'handleKeyDown($event)',
1214
+ '(focus)': 'onTreeFocus($event)',
1215
+ '(blur)': 'onTreeBlur($event)',
1216
+ tabindex: '0',
1217
+ }, template: "<!-- Root drop list -->\n<div\n axFocusTrap\n [axDropList]=\"dragMode() !== 'none'\"\n [sortingDisabled]=\"false\"\n [id]=\"getListId()\"\n [attr.data-node-id]=\"null\"\n dropListGroup=\"ax-tree-view-nodes\"\n (dropListDropped)=\"onDrop($event)\"\n class=\"ax-tree-view-drop-list\"\n [class.ax-tree-view-card]=\"look() === 'card'\"\n [class.ax-tree-view-with-lines]=\"look() === 'with-line'\"\n [class.ax-tree-view-compact]=\"nodeHeight() === 'compact'\"\n [class.ax-tree-view-comfortable]=\"nodeHeight() === 'comfortable'\"\n role=\"group\"\n>\n @for (node of nodes(); track node.id) {\n @if (node.visible !== false) {\n <div\n [axDrag]=\"dragMode() !== 'none'\"\n [dragDisabled]=\"node.disabled\"\n [dragData]=\"node\"\n class=\"ax-tree-view-node\"\n [class.ax-tree-view-node-selected]=\"node.selected\"\n [class.ax-tree-view-node-disabled]=\"node.disabled\"\n [class.ax-tree-view-node-loading]=\"node.loading\"\n role=\"treeitem\"\n [attr.aria-level]=\"getNodeAriaLevel(0)\"\n [attr.aria-expanded]=\"getNodeAriaExpanded(node)\"\n [attr.aria-selected]=\"getNodeAriaSelected(node)\"\n [attr.aria-disabled]=\"node.disabled ? 'true' : null\"\n >\n <div\n class=\"ax-tree-view-node-content\"\n [axDropList]=\"dragMode() !== 'none'\"\n [id]=\"'ax-tree-view-node-drop-' + node.id\"\n [attr.data-node-id]=\"node.id\"\n [attr.data-tree-node-id]=\"node.id\"\n [attr.data-drop-type]=\"'onto-node'\"\n dropListGroup=\"ax-tree-view-nodes\"\n (dropListDropped)=\"onDropOntoNode($event, node)\"\n (click)=\"\n (selectMode() === 'single' || (selectMode() === 'multiple' && checkOnClick())) && onNodeClick(node, $event)\n \"\n (focus)=\"onNodeFocus(node.id)\"\n [tabindex]=\"isNodeFocused(node.id) ? 0 : -1\"\n >\n @if (dragMode() === 'handler') {\n <span class=\"ax-tree-view-drag-handle\" axDragHandle title=\"Drag to reorder\"> \u22EE\u22EE </span>\n }\n <ax-button\n class=\"ax-tree-view-expand-toggle ax-sm\"\n (onClick)=\"toggleNode(node, $any($event))\"\n [class.ax-tree-view-has-children]=\"shouldShowExpandToggle(node)\"\n [class.ax-tree-view-expanded]=\"node.expanded\"\n [disabled]=\"node.disabled || node.loading\"\n [style.visibility]=\"shouldShowExpandToggle(node) ? 'visible' : 'hidden'\"\n >\n @if (node.loading) {\n <ax-icon>\n <i class=\"fa-solid fa-spinner fa-spin ax-tree-view-loading-spinner\"></i>\n </ax-icon>\n } @else {\n <ax-icon>\n <i\n [class]=\"node.expanded ? directionExpandedIcon() : directionCollapsedIcon()\"\n class=\"ax-tree-view-toggle-icon\"\n ></i>\n </ax-icon>\n }\n </ax-button>\n @if (itemTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"itemTemplate()!\"\n [ngTemplateOutletContext]=\"getTemplateContext(node, 0)\"\n ></ng-container>\n } @else {\n @if (shouldShowCheckbox()) {\n <ax-check-box\n class=\"ax-tree-view-checkbox\"\n [ngModel]=\"node.indeterminate ? null : node.selected || false\"\n [indeterminate]=\"node.indeterminate || false\"\n (onValueChanged)=\"toggleSelection(node, $event)\"\n ></ax-check-box>\n }\n @if (showIcons() && node.icon) {\n <i [class]=\"node.icon\" class=\"ax-tree-view-node-icon\"></i>\n }\n <span class=\"ax-tree-view-node-label\">{{ node.label }}</span>\n @if (showChildrenBadge() && (node.childrenCount || (node.children && node.children.length > 0))) {\n <ax-badge\n class=\"ax-tree-view-children-badge\"\n [text]=\"(node.childrenCount ?? node.children?.length ?? 0).toString()\"\n ></ax-badge>\n }\n }\n </div>\n </div>\n @if (node.expanded && node.children && node.children.length > 0) {\n <div class=\"ax-tree-view-children\" role=\"group\">\n <ng-container\n [ngTemplateOutlet]=\"childrenList\"\n [ngTemplateOutletContext]=\"{ children: node.children, parent: node, level: 1 }\"\n ></ng-container>\n </div>\n }\n }\n }\n</div>\n\n<!-- Recursive children template -->\n<ng-template #childrenList let-children=\"children\" let-parent=\"parent\" let-level=\"level\">\n <div\n [axDropList]=\"dragMode() !== 'none'\"\n [id]=\"getListId(parent)\"\n [attr.data-node-id]=\"parent.id\"\n dropListGroup=\"ax-tree-view-nodes\"\n (dropListDropped)=\"onDrop($event, parent)\"\n class=\"ax-tree-view-drop-list\"\n role=\"group\"\n >\n @for (node of children; track node.id) {\n @if (node.visible !== false) {\n <div\n [axDrag]=\"dragMode() !== 'none'\"\n [dragDisabled]=\"node.disabled\"\n [dragData]=\"node\"\n class=\"ax-tree-view-node\"\n [class.ax-tree-view-node-selected]=\"node.selected\"\n [class.ax-tree-view-node-disabled]=\"node.disabled\"\n [class.ax-tree-view-node-loading]=\"node.loading\"\n [class.ax-tree-view-node-focused]=\"isNodeFocused(node.id)\"\n role=\"treeitem\"\n [attr.aria-level]=\"getNodeAriaLevel(level)\"\n [attr.aria-expanded]=\"getNodeAriaExpanded(node)\"\n [attr.aria-selected]=\"getNodeAriaSelected(node)\"\n [attr.aria-disabled]=\"node.disabled ? 'true' : null\"\n >\n <div\n class=\"ax-tree-view-node-content\"\n [style.padding-inline-start.px]=\"getNodePaddingInline(level)\"\n [axDropList]=\"dragMode() !== 'none'\"\n [id]=\"'ax-tree-view-node-drop-' + node.id\"\n [attr.data-node-id]=\"node.id\"\n [attr.data-tree-node-id]=\"node.id\"\n [attr.data-drop-type]=\"'onto-node'\"\n dropListGroup=\"ax-tree-view-nodes\"\n (dropListDropped)=\"onDropOntoNode($event, node)\"\n (click)=\"\n (selectMode() === 'single' || (selectMode() === 'multiple' && checkOnClick())) &&\n onNodeClick(node, $event)\n \"\n (focus)=\"onNodeFocus(node.id)\"\n (blur)=\"focusedNodeId.set(null)\"\n [tabindex]=\"isNodeFocused(node.id) ? 0 : -1\"\n >\n @if (dragMode() === 'handler') {\n <span class=\"ax-tree-view-drag-handle\" axDragHandle title=\"Drag to reorder\"> \u22EE\u22EE </span>\n }\n <ax-button\n class=\"ax-tree-view-expand-toggle ax-sm\"\n (onClick)=\"toggleNode(node, $any($event))\"\n [class.ax-tree-view-has-children]=\"shouldShowExpandToggle(node)\"\n [class.ax-tree-view-expanded]=\"node.expanded\"\n [disabled]=\"node.disabled || node.loading\"\n [style.visibility]=\"shouldShowExpandToggle(node) ? 'visible' : 'hidden'\"\n >\n @if (node.loading) {\n <ax-icon>\n <i class=\"fa-solid fa-spinner fa-spin ax-tree-view-loading-spinner\"></i>\n </ax-icon>\n } @else {\n <ax-icon>\n <i\n [class]=\"node.expanded ? directionExpandedIcon() : directionCollapsedIcon()\"\n class=\"ax-tree-view-toggle-icon\"\n ></i>\n </ax-icon>\n }\n </ax-button>\n\n @if (itemTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"itemTemplate()!\"\n [ngTemplateOutletContext]=\"getTemplateContext(node, level)\"\n ></ng-container>\n } @else {\n @if (shouldShowCheckbox()) {\n <ax-check-box\n class=\"ax-tree-view-checkbox\"\n [ngModel]=\"node.indeterminate ? null : node.selected || false\"\n [indeterminate]=\"node.indeterminate || false\"\n (onValueChanged)=\"toggleSelection(node, $event)\"\n ></ax-check-box>\n }\n @if (showIcons() && node.icon) {\n <i [class]=\"node.icon\" class=\"ax-tree-view-node-icon\"></i>\n }\n <span class=\"ax-tree-view-node-label\">{{ node.label }}</span>\n @if (showChildrenBadge() && (node.childrenCount || (node.children && node.children.length > 0))) {\n <ax-badge\n class=\"ax-tree-view-children-badge\"\n [text]=\"(node.childrenCount ?? node.children?.length ?? 0).toString()\"\n ></ax-badge>\n }\n }\n </div>\n </div>\n @if (node.expanded && node.children && node.children.length > 0) {\n <div class=\"ax-tree-view-children\" role=\"group\">\n <ng-container\n [ngTemplateOutlet]=\"childrenList\"\n [ngTemplateOutletContext]=\"{ children: node.children, parent: node, level: level + 1 }\"\n ></ng-container>\n </div>\n }\n }\n }\n </div>\n</ng-template>\n", styles: [".ax-tree-view{display:block;width:100%;--ax-comp-tree-view-indent-size: 12px;--ax-comp-tree-view-node-hover-bg: rgba(var(--ax-sys-color-on-lightest-surface), .04);--ax-comp-tree-view-node-selected-bg: rgba(var(--ax-sys-color-primary-500), .12);--ax-comp-tree-view-node-border-radius: 6px;--ax-comp-tree-view-node-margin: .25rem;--ax-comp-tree-view-line-color: rgba(var(--ax-sys-color-on-lightest-surface), .15);--ax-comp-tree-view-drag-preview-opacity: .9;--ax-comp-tree-view-drag-placeholder-bg: rgba(var(--ax-sys-color-on-lightest-surface), .02);--ax-comp-tree-view-drop-active-bg: rgba(var(--ax-sys-color-primary-500), .08);--ax-comp-tree-view-drop-active-outline: rgba(var(--ax-sys-color-primary-500), .3);--ax-comp-tree-view-content-padding: 0;--ax-comp-tree-view-content-gap: .5rem;--ax-comp-tree-view-drop-list-min-height: 2rem;--ax-comp-tree-view-drag-handle-padding: .25rem;--ax-comp-tree-view-expand-toggle-padding: .25rem;--ax-comp-tree-view-card-node-margin: .5rem;--ax-comp-tree-view-card-content-padding: 1rem;--ax-comp-tree-view-outline-offset: 2px;--ax-comp-tree-view-outline-offset-negative: -2px}.ax-tree-view-drop-list{min-height:var(--ax-comp-tree-view-drop-list-min-height)}.ax-tree-view-compact .ax-tree-view-node-content{padding:var(--ax-comp-tree-view-content-padding, .25rem .5rem);gap:var(--ax-comp-tree-view-content-gap, .375rem);font-size:.8125rem}.ax-tree-view-comfortable .ax-tree-view-node-content{padding:var(--ax-comp-tree-view-content-padding, .75rem .625rem);gap:var(--ax-comp-tree-view-content-gap, .625rem);font-size:.9375rem}.ax-tree-view-node{position:relative;margin:var(--ax-comp-tree-view-node-margin) 0;border-radius:var(--ax-comp-tree-view-node-border-radius);border:1px solid transparent;cursor:move}.ax-tree-view-node:hover:not(.ax-dragging){background:var(--ax-comp-tree-view-node-hover-bg)}.ax-tree-view-node.ax-tree-view-node-selected{background:var(--ax-comp-tree-view-node-selected-bg);border-color:currentColor}.ax-tree-view-node.ax-dragging{opacity:var(--ax-comp-tree-view-drag-placeholder-opacity);cursor:grabbing!important}.ax-tree-view-node.ax-drag-placeholder{background:var(--ax-comp-tree-view-drag-placeholder-bg)}.ax-drag-preview{opacity:var(--ax-comp-tree-view-drag-preview-opacity)!important;box-shadow:0 4px 12px rgba(var(--ax-sys-color-on-lightest-surface),.2)!important;cursor:grabbing!important;border:2px dashed currentColor!important}.ax-tree-view-node-content.ax-drop-list-sorting-active{background:var(--ax-comp-tree-view-drop-active-bg);border-radius:var(--ax-comp-tree-view-node-border-radius);outline:2px dashed var(--ax-comp-tree-view-drop-active-outline);outline-offset:var(--ax-comp-tree-view-outline-offset-negative)}.ax-tree-view-node-content{display:flex;align-items:center;gap:var(--ax-comp-tree-view-content-gap);padding:var(--ax-comp-tree-view-content-padding);cursor:pointer;-webkit-user-select:none;user-select:none;outline:none;border:1px solid transparent;border-radius:var(--ax-comp-tree-view-node-border-radius)}.ax-tree-view-node-content:focus{outline:none}.ax-tree-view-node-content:focus-visible{outline:2px solid rgba(var(--ax-sys-color-primary-500),.8);outline-offset:var(--ax-comp-tree-view-outline-offset);border-radius:var(--ax-comp-tree-view-node-border-radius)}.ax-tree-view-drag-handle{cursor:grab;opacity:.6;padding:var(--ax-comp-tree-view-drag-handle-padding)}.ax-tree-view-drag-handle:hover{opacity:1}.ax-tree-view-drag-handle:active{cursor:grabbing}.ax-tree-view-expand-toggle{background:none;border:none;cursor:pointer;padding:var(--ax-comp-tree-view-expand-toggle-padding);min-width:1.5rem;height:1.5rem}.ax-tree-view-expand-toggle:not(.ax-tree-view-has-children){opacity:0;pointer-events:none}.ax-tree-view-toggle-icon{font-size:.75rem}.ax-tree-view-node-icon{font-size:1.125rem;flex-shrink:0}.ax-tree-view-node-label{flex:1;font-size:.875rem;line-height:1rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ax-tree-view-children{padding-inline-start:var(--ax-tree-view-indent-size, var(--ax-comp-tree-view-indent-size))}.ax-tree-view-node-disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.ax-tree-view-node-loading{opacity:.7}.ax-tree-view-card .ax-tree-view-node{border:1px solid rgba(var(--ax-sys-color-border-lightest-surface),1);margin:var(--ax-comp-tree-view-card-node-margin) 0}.ax-tree-view-card .ax-tree-view-node-content{padding:var(--ax-comp-tree-view-card-content-padding)}.ax-tree-view-with-lines .ax-tree-view-children{position:relative;padding-inline-start:var(--ax-tree-view-indent-size, var(--ax-comp-tree-view-indent-size))}.ax-tree-view-with-lines .ax-tree-view-children:before{content:\"\";position:absolute;inset-inline-start:var(--ax-tree-view-line-offset, calc(var(--ax-comp-tree-view-indent-size) / 2));top:0;height:calc(100% - .875rem);width:1px;background:var(--ax-tree-view-line-color, var(--ax-comp-tree-view-line-color))}.ax-tree-view-with-lines .ax-tree-view-node{position:relative}.ax-tree-view-with-lines .ax-tree-view-node:before{content:\"\";position:absolute;inset-inline-start:calc(-1 * var(--ax-tree-view-line-offset, calc(var(--ax-comp-tree-view-indent-size) / 2)));top:60%;width:var(--ax-tree-view-line-offset, calc(var(--ax-comp-tree-view-indent-size) / 2));height:1px;background:var(--ax-tree-view-line-color, var(--ax-comp-tree-view-line-color))}.ax-tree-view-with-lines>.ax-tree-view-drop-list>.ax-tree-view-node:before,.ax-tree-view-with-lines>.ax-tree-view-node:before{display:none}\n"] }]
1218
+ }], propDecorators: { datasource: [{ type: i0.Input, args: [{ isSignal: true, alias: "datasource", required: true }] }, { type: i0.Output, args: ["datasourceChange"] }], selectMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectMode", required: false }] }], showCheckbox: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCheckbox", required: false }] }], checkChildrenOnSelect: [{ type: i0.Input, args: [{ isSignal: true, alias: "checkChildrenOnSelect", required: false }] }], intermediateState: [{ type: i0.Input, args: [{ isSignal: true, alias: "intermediateState", required: false }] }], checkOnClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "checkOnClick", required: false }] }], dragMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "dragMode", required: false }] }], dragOperationType: [{ type: i0.Input, args: [{ isSignal: true, alias: "dragOperationType", required: false }] }], showIcons: [{ type: i0.Input, args: [{ isSignal: true, alias: "showIcons", required: false }] }], showChildrenBadge: [{ type: i0.Input, args: [{ isSignal: true, alias: "showChildrenBadge", required: false }] }], expandedIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandedIcon", required: false }] }], collapsedIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsedIcon", required: false }] }], indentSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "indentSize", required: false }] }], nodeHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodeHeight", required: false }] }], look: [{ type: i0.Input, args: [{ isSignal: true, alias: "look", required: false }] }], itemTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemTemplate", required: false }] }], onBeforeDrop: [{ type: i0.Output, args: ["onBeforeDrop"] }], onNodeToggle: [{ type: i0.Output, args: ["onNodeToggle"] }], onNodeSelect: [{ type: i0.Output, args: ["onNodeSelect"] }], onOrderChange: [{ type: i0.Output, args: ["onOrderChange"] }], onMoveChange: [{ type: i0.Output, args: ["onMoveChange"] }], onItemsChange: [{ type: i0.Output, args: ["onItemsChange"] }] } });
474
1219
 
475
- const COMPONENT = [AXTreeViewComponent, AXTreeViewItemComponent];
476
- const MODULES = [
477
- CommonModule,
478
- AXCommonModule,
479
- AXDecoratorModule,
480
- AXCheckBoxModule,
481
- AXFormModule,
482
- FormsModule,
483
- AXTooltipModule,
484
- AXLoadingModule,
485
- ];
486
1220
  class AXTreeViewModule {
487
1221
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
488
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewModule, imports: [AXTreeViewComponent, AXTreeViewItemComponent, CommonModule,
489
- AXCommonModule,
490
- AXDecoratorModule,
491
- AXCheckBoxModule,
492
- AXFormModule,
493
- FormsModule,
494
- AXTooltipModule,
495
- AXLoadingModule], exports: [AXTreeViewComponent, AXTreeViewItemComponent] }); }
496
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewModule, imports: [COMPONENT, MODULES] }); }
1222
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewModule, imports: [AXTreeViewComponent] }); }
1223
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewModule, imports: [AXTreeViewComponent] }); }
497
1224
  }
498
1225
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewModule, decorators: [{
499
1226
  type: NgModule,
500
1227
  args: [{
501
- imports: [...COMPONENT, ...MODULES],
502
- exports: [...COMPONENT],
1228
+ imports: [AXTreeViewComponent],
503
1229
  }]
504
1230
  }] });
505
1231
 
@@ -507,5 +1233,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
507
1233
  * Generated bundle index. Do not edit.
508
1234
  */
509
1235
 
510
- export { AXTreeItemClickBaseEvent, AXTreeViewBase, AXTreeViewComponent, AXTreeViewItemComponent, AXTreeViewModule };
1236
+ export { AXTreeViewComponent, AXTreeViewModule, AXTreeViewService };
511
1237
  //# sourceMappingURL=acorex-components-tree-view.mjs.map