@acorex/components 20.2.45 → 20.2.47

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