@acorex/components 21.0.0-next.37 → 21.0.0-next.39

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.
Files changed (242) hide show
  1. package/accordion/index.d.ts +1 -0
  2. package/button-group/index.d.ts +4 -6
  3. package/calendar/index.d.ts +4 -0
  4. package/chips/index.d.ts +8 -3
  5. package/dialog/index.d.ts +1 -1
  6. package/fesm2022/acorex-components-accordion.mjs +21 -16
  7. package/fesm2022/acorex-components-accordion.mjs.map +1 -1
  8. package/fesm2022/acorex-components-action-sheet.mjs +12 -12
  9. package/fesm2022/acorex-components-action-sheet.mjs.map +1 -1
  10. package/fesm2022/acorex-components-alert.mjs +13 -13
  11. package/fesm2022/acorex-components-alert.mjs.map +1 -1
  12. package/fesm2022/acorex-components-aspect-ratio.mjs +3 -3
  13. package/fesm2022/acorex-components-aspect-ratio.mjs.map +1 -1
  14. package/fesm2022/acorex-components-audio-wave.mjs +10 -11
  15. package/fesm2022/acorex-components-audio-wave.mjs.map +1 -1
  16. package/fesm2022/acorex-components-autocomplete.mjs +7 -7
  17. package/fesm2022/acorex-components-autocomplete.mjs.map +1 -1
  18. package/fesm2022/acorex-components-avatar.mjs +12 -12
  19. package/fesm2022/acorex-components-avatar.mjs.map +1 -1
  20. package/fesm2022/acorex-components-badge.mjs +9 -9
  21. package/fesm2022/acorex-components-badge.mjs.map +1 -1
  22. package/fesm2022/acorex-components-bottom-navigation.mjs +11 -11
  23. package/fesm2022/acorex-components-bottom-navigation.mjs.map +1 -1
  24. package/fesm2022/acorex-components-breadcrumbs.mjs +11 -11
  25. package/fesm2022/acorex-components-breadcrumbs.mjs.map +1 -1
  26. package/fesm2022/acorex-components-button-group.mjs +19 -23
  27. package/fesm2022/acorex-components-button-group.mjs.map +1 -1
  28. package/fesm2022/acorex-components-button.mjs +18 -18
  29. package/fesm2022/acorex-components-button.mjs.map +1 -1
  30. package/fesm2022/acorex-components-calendar.mjs +32 -17
  31. package/fesm2022/acorex-components-calendar.mjs.map +1 -1
  32. package/fesm2022/acorex-components-check-box.mjs +10 -10
  33. package/fesm2022/acorex-components-check-box.mjs.map +1 -1
  34. package/fesm2022/acorex-components-chips.mjs +14 -12
  35. package/fesm2022/acorex-components-chips.mjs.map +1 -1
  36. package/fesm2022/acorex-components-circular-progress.mjs +10 -12
  37. package/fesm2022/acorex-components-circular-progress.mjs.map +1 -1
  38. package/fesm2022/acorex-components-code-editor.mjs +10 -10
  39. package/fesm2022/acorex-components-code-editor.mjs.map +1 -1
  40. package/fesm2022/acorex-components-collapse.mjs +13 -13
  41. package/fesm2022/acorex-components-collapse.mjs.map +1 -1
  42. package/fesm2022/acorex-components-color-box.mjs +9 -9
  43. package/fesm2022/acorex-components-color-box.mjs.map +1 -1
  44. package/fesm2022/acorex-components-color-palette.mjs +30 -30
  45. package/fesm2022/acorex-components-color-palette.mjs.map +1 -1
  46. package/fesm2022/acorex-components-command.mjs +9 -9
  47. package/fesm2022/acorex-components-command.mjs.map +1 -1
  48. package/fesm2022/acorex-components-comment.mjs +32 -32
  49. package/fesm2022/acorex-components-comment.mjs.map +1 -1
  50. package/fesm2022/acorex-components-conversation.mjs +51 -51
  51. package/fesm2022/acorex-components-conversation.mjs.map +1 -1
  52. package/fesm2022/acorex-components-conversation2.mjs +186 -186
  53. package/fesm2022/acorex-components-conversation2.mjs.map +1 -1
  54. package/fesm2022/acorex-components-cron-job.mjs +46 -46
  55. package/fesm2022/acorex-components-cron-job.mjs.map +1 -1
  56. package/fesm2022/acorex-components-data-list.mjs +3 -3
  57. package/fesm2022/acorex-components-data-list.mjs.map +1 -1
  58. package/fesm2022/acorex-components-data-pager.mjs +37 -34
  59. package/fesm2022/acorex-components-data-pager.mjs.map +1 -1
  60. package/fesm2022/acorex-components-data-table.mjs +43 -43
  61. package/fesm2022/acorex-components-data-table.mjs.map +1 -1
  62. package/fesm2022/acorex-components-datetime-box.mjs +9 -9
  63. package/fesm2022/acorex-components-datetime-box.mjs.map +1 -1
  64. package/fesm2022/acorex-components-datetime-input.mjs +9 -9
  65. package/fesm2022/acorex-components-datetime-input.mjs.map +1 -1
  66. package/fesm2022/acorex-components-datetime-picker.mjs +9 -9
  67. package/fesm2022/acorex-components-datetime-picker.mjs.map +1 -1
  68. package/fesm2022/acorex-components-decorators.mjs +36 -43
  69. package/fesm2022/acorex-components-decorators.mjs.map +1 -1
  70. package/fesm2022/acorex-components-dialog.mjs +14 -15
  71. package/fesm2022/acorex-components-dialog.mjs.map +1 -1
  72. package/fesm2022/acorex-components-drawer-legacy.mjs +13 -13
  73. package/fesm2022/acorex-components-drawer-legacy.mjs.map +1 -1
  74. package/fesm2022/acorex-components-drawer.mjs +16 -15
  75. package/fesm2022/acorex-components-drawer.mjs.map +1 -1
  76. package/fesm2022/acorex-components-dropdown-button.mjs +9 -9
  77. package/fesm2022/acorex-components-dropdown-button.mjs.map +1 -1
  78. package/fesm2022/acorex-components-dropdown.mjs +16 -18
  79. package/fesm2022/acorex-components-dropdown.mjs.map +1 -1
  80. package/fesm2022/acorex-components-editor.mjs +11 -11
  81. package/fesm2022/acorex-components-editor.mjs.map +1 -1
  82. package/fesm2022/acorex-components-file-explorer.mjs +32 -32
  83. package/fesm2022/acorex-components-file-explorer.mjs.map +1 -1
  84. package/fesm2022/acorex-components-flow-chart.mjs +16 -16
  85. package/fesm2022/acorex-components-flow-chart.mjs.map +1 -1
  86. package/fesm2022/acorex-components-form.mjs +24 -32
  87. package/fesm2022/acorex-components-form.mjs.map +1 -1
  88. package/fesm2022/acorex-components-grid-layout-builder.mjs +13 -12
  89. package/fesm2022/acorex-components-grid-layout-builder.mjs.map +1 -1
  90. package/fesm2022/acorex-components-image-editor.mjs +47 -46
  91. package/fesm2022/acorex-components-image-editor.mjs.map +1 -1
  92. package/fesm2022/acorex-components-image.mjs +9 -9
  93. package/fesm2022/acorex-components-image.mjs.map +1 -1
  94. package/fesm2022/acorex-components-json-viewer.mjs +8 -8
  95. package/fesm2022/acorex-components-json-viewer.mjs.map +1 -1
  96. package/fesm2022/acorex-components-kanban.mjs +6 -8
  97. package/fesm2022/acorex-components-kanban.mjs.map +1 -1
  98. package/fesm2022/acorex-components-kbd.mjs +7 -7
  99. package/fesm2022/acorex-components-kbd.mjs.map +1 -1
  100. package/fesm2022/acorex-components-label.mjs +9 -9
  101. package/fesm2022/acorex-components-label.mjs.map +1 -1
  102. package/fesm2022/acorex-components-list.mjs +9 -9
  103. package/fesm2022/acorex-components-list.mjs.map +1 -1
  104. package/fesm2022/acorex-components-loading-dialog.mjs +12 -12
  105. package/fesm2022/acorex-components-loading-dialog.mjs.map +1 -1
  106. package/fesm2022/acorex-components-loading.mjs +23 -23
  107. package/fesm2022/acorex-components-loading.mjs.map +1 -1
  108. package/fesm2022/acorex-components-map.mjs +289 -31
  109. package/fesm2022/acorex-components-map.mjs.map +1 -1
  110. package/fesm2022/acorex-components-media-viewer.mjs +41 -41
  111. package/fesm2022/acorex-components-media-viewer.mjs.map +1 -1
  112. package/fesm2022/acorex-components-menu.mjs +21 -21
  113. package/fesm2022/acorex-components-menu.mjs.map +1 -1
  114. package/fesm2022/{acorex-components-modal-acorex-components-modal-BmmAkCKJ.mjs → acorex-components-modal-acorex-components-modal-iYSPzoLn.mjs} +22 -22
  115. package/fesm2022/acorex-components-modal-acorex-components-modal-iYSPzoLn.mjs.map +1 -0
  116. package/fesm2022/acorex-components-modal-modal-content.component-sZWKhYM-.mjs +212 -0
  117. package/fesm2022/acorex-components-modal-modal-content.component-sZWKhYM-.mjs.map +1 -0
  118. package/fesm2022/acorex-components-modal.mjs +1 -1
  119. package/fesm2022/acorex-components-navbar.mjs +9 -9
  120. package/fesm2022/acorex-components-navbar.mjs.map +1 -1
  121. package/fesm2022/acorex-components-notification.mjs +23 -16
  122. package/fesm2022/acorex-components-notification.mjs.map +1 -1
  123. package/fesm2022/acorex-components-number-box-legacy.mjs +9 -9
  124. package/fesm2022/acorex-components-number-box-legacy.mjs.map +1 -1
  125. package/fesm2022/acorex-components-number-box.mjs +15 -14
  126. package/fesm2022/acorex-components-number-box.mjs.map +1 -1
  127. package/fesm2022/acorex-components-otp.mjs +9 -9
  128. package/fesm2022/acorex-components-otp.mjs.map +1 -1
  129. package/fesm2022/acorex-components-page.mjs +10 -10
  130. package/fesm2022/acorex-components-page.mjs.map +1 -1
  131. package/fesm2022/acorex-components-paint.mjs +39 -34
  132. package/fesm2022/acorex-components-paint.mjs.map +1 -1
  133. package/fesm2022/acorex-components-password-box.mjs +12 -12
  134. package/fesm2022/acorex-components-password-box.mjs.map +1 -1
  135. package/fesm2022/acorex-components-pdf-reader.mjs +8 -8
  136. package/fesm2022/acorex-components-pdf-reader.mjs.map +1 -1
  137. package/fesm2022/acorex-components-phone-box.mjs +9 -9
  138. package/fesm2022/acorex-components-phone-box.mjs.map +1 -1
  139. package/fesm2022/acorex-components-picker.mjs +15 -15
  140. package/fesm2022/acorex-components-picker.mjs.map +1 -1
  141. package/fesm2022/acorex-components-popover.mjs +11 -11
  142. package/fesm2022/acorex-components-popover.mjs.map +1 -1
  143. package/fesm2022/acorex-components-popup.mjs +13 -13
  144. package/fesm2022/acorex-components-popup.mjs.map +1 -1
  145. package/fesm2022/acorex-components-progress-bar.mjs +9 -11
  146. package/fesm2022/acorex-components-progress-bar.mjs.map +1 -1
  147. package/fesm2022/acorex-components-qrcode.mjs +7 -7
  148. package/fesm2022/acorex-components-qrcode.mjs.map +1 -1
  149. package/fesm2022/acorex-components-query-builder.mjs +8 -8
  150. package/fesm2022/acorex-components-query-builder.mjs.map +1 -1
  151. package/fesm2022/acorex-components-radio.mjs +7 -7
  152. package/fesm2022/acorex-components-radio.mjs.map +1 -1
  153. package/fesm2022/acorex-components-rail-navigation.mjs +36 -38
  154. package/fesm2022/acorex-components-rail-navigation.mjs.map +1 -1
  155. package/fesm2022/acorex-components-range-slider.mjs +10 -10
  156. package/fesm2022/acorex-components-range-slider.mjs.map +1 -1
  157. package/fesm2022/acorex-components-rate-picker.mjs +35 -20
  158. package/fesm2022/acorex-components-rate-picker.mjs.map +1 -1
  159. package/fesm2022/acorex-components-rest-api-generator.mjs +22 -22
  160. package/fesm2022/acorex-components-rest-api-generator.mjs.map +1 -1
  161. package/fesm2022/acorex-components-result.mjs +8 -8
  162. package/fesm2022/acorex-components-result.mjs.map +1 -1
  163. package/fesm2022/acorex-components-routing-progress.mjs +8 -8
  164. package/fesm2022/acorex-components-routing-progress.mjs.map +1 -1
  165. package/fesm2022/acorex-components-rrule.mjs +9 -9
  166. package/fesm2022/acorex-components-rrule.mjs.map +1 -1
  167. package/fesm2022/acorex-components-scheduler-picker.mjs +56 -56
  168. package/fesm2022/acorex-components-scheduler-picker.mjs.map +1 -1
  169. package/fesm2022/acorex-components-scheduler.mjs +43 -43
  170. package/fesm2022/acorex-components-scheduler.mjs.map +1 -1
  171. package/fesm2022/acorex-components-scss.mjs +4 -4
  172. package/fesm2022/acorex-components-scss.mjs.map +1 -1
  173. package/fesm2022/acorex-components-search-box.mjs +10 -16
  174. package/fesm2022/acorex-components-search-box.mjs.map +1 -1
  175. package/fesm2022/acorex-components-select-box.mjs +9 -11
  176. package/fesm2022/acorex-components-select-box.mjs.map +1 -1
  177. package/fesm2022/acorex-components-selection-list-2.mjs +11 -11
  178. package/fesm2022/acorex-components-selection-list-2.mjs.map +1 -1
  179. package/fesm2022/acorex-components-selection-list.mjs +9 -9
  180. package/fesm2022/acorex-components-selection-list.mjs.map +1 -1
  181. package/fesm2022/acorex-components-side-menu.mjs +14 -14
  182. package/fesm2022/acorex-components-side-menu.mjs.map +1 -1
  183. package/fesm2022/acorex-components-skeleton.mjs +8 -8
  184. package/fesm2022/acorex-components-skeleton.mjs.map +1 -1
  185. package/fesm2022/acorex-components-slider.mjs +10 -10
  186. package/fesm2022/acorex-components-slider.mjs.map +1 -1
  187. package/fesm2022/acorex-components-sliding-item.mjs +14 -14
  188. package/fesm2022/acorex-components-sliding-item.mjs.map +1 -1
  189. package/fesm2022/acorex-components-step-wizard.mjs +14 -14
  190. package/fesm2022/acorex-components-step-wizard.mjs.map +1 -1
  191. package/fesm2022/acorex-components-switch.mjs +14 -14
  192. package/fesm2022/acorex-components-switch.mjs.map +1 -1
  193. package/fesm2022/acorex-components-tabs.mjs +15 -15
  194. package/fesm2022/acorex-components-tabs.mjs.map +1 -1
  195. package/fesm2022/acorex-components-tag-box.mjs +9 -9
  196. package/fesm2022/acorex-components-tag-box.mjs.map +1 -1
  197. package/fesm2022/acorex-components-tag.mjs +9 -9
  198. package/fesm2022/acorex-components-tag.mjs.map +1 -1
  199. package/fesm2022/acorex-components-text-area.mjs +9 -9
  200. package/fesm2022/acorex-components-text-area.mjs.map +1 -1
  201. package/fesm2022/acorex-components-text-box.mjs +12 -12
  202. package/fesm2022/acorex-components-text-box.mjs.map +1 -1
  203. package/fesm2022/acorex-components-time-duration.mjs +7 -7
  204. package/fesm2022/acorex-components-time-duration.mjs.map +1 -1
  205. package/fesm2022/acorex-components-time-line.mjs +12 -12
  206. package/fesm2022/acorex-components-time-line.mjs.map +1 -1
  207. package/fesm2022/acorex-components-toast.mjs +14 -14
  208. package/fesm2022/acorex-components-toast.mjs.map +1 -1
  209. package/fesm2022/acorex-components-toolbar.mjs +8 -8
  210. package/fesm2022/acorex-components-toolbar.mjs.map +1 -1
  211. package/fesm2022/acorex-components-tooltip.mjs +11 -11
  212. package/fesm2022/acorex-components-tooltip.mjs.map +1 -1
  213. package/fesm2022/acorex-components-tree-view-legacy.mjs +511 -0
  214. package/fesm2022/acorex-components-tree-view-legacy.mjs.map +1 -0
  215. package/fesm2022/acorex-components-tree-view.mjs +2016 -405
  216. package/fesm2022/acorex-components-tree-view.mjs.map +1 -1
  217. package/fesm2022/acorex-components-uploader.mjs +16 -16
  218. package/fesm2022/acorex-components-uploader.mjs.map +1 -1
  219. package/fesm2022/acorex-components-video-player.mjs +7 -7
  220. package/fesm2022/acorex-components-video-player.mjs.map +1 -1
  221. package/fesm2022/acorex-components-wysiwyg.mjs +42 -42
  222. package/fesm2022/acorex-components-wysiwyg.mjs.map +1 -1
  223. package/fesm2022/acorex-components.mjs.map +1 -1
  224. package/file-explorer/index.d.ts +6 -6
  225. package/grid-layout-builder/index.d.ts +2 -1
  226. package/loading/index.d.ts +1 -1
  227. package/map/index.d.ts +28 -1
  228. package/notification/index.d.ts +2 -0
  229. package/number-box/index.d.ts +1 -1
  230. package/package.json +6 -6
  231. package/paint/index.d.ts +6 -1
  232. package/rate-picker/index.d.ts +15 -5
  233. package/tree-view/index.d.ts +826 -168
  234. package/tree-view-legacy/README.md +3 -0
  235. package/tree-view-legacy/index.d.ts +184 -0
  236. package/fesm2022/acorex-components-modal-acorex-components-modal-BmmAkCKJ.mjs.map +0 -1
  237. package/fesm2022/acorex-components-modal-modal-content.component-5GqTzNOs.mjs +0 -214
  238. package/fesm2022/acorex-components-modal-modal-content.component-5GqTzNOs.mjs.map +0 -1
  239. package/fesm2022/acorex-components-tree2.mjs +0 -730
  240. package/fesm2022/acorex-components-tree2.mjs.map +0 -1
  241. package/tree2/README.md +0 -3
  242. package/tree2/index.d.ts +0 -346
@@ -1,505 +1,2116 @@
1
- import { AXClickEvent, NXComponent, AXComponent, AXCommonModule } from '@acorex/cdk/common';
2
- import { AXLoadingComponent, AXLoadingModule } from '@acorex/components/loading';
3
- import { AXTooltipDirective, AXTooltipModule } from '@acorex/components/tooltip';
1
+ import { moveItemInArray, transferArrayItem, AXDragDirective, AXDragHandleDirective, AXDropListDirective } from '@acorex/cdk/drag-drop';
2
+ import { AXFocusTrapDirective } from '@acorex/cdk/focus-trap';
3
+ import { AXBadgeComponent } from '@acorex/components/badge';
4
+ import { AXButtonComponent } from '@acorex/components/button';
5
+ import { AXCheckBoxComponent } from '@acorex/components/check-box';
6
+ import { AXDecoratorIconComponent } from '@acorex/components/decorators';
7
+ import { AXTooltipDirective } from '@acorex/components/tooltip';
4
8
  import { AXPlatform } from '@acorex/core/platform';
5
- import { AXTranslatorPipe } from '@acorex/core/translation';
6
9
  import * as i1 from '@angular/common';
7
- import { CommonModule, NgTemplateOutlet, AsyncPipe } from '@angular/common';
10
+ import { CommonModule, NgTemplateOutlet } from '@angular/common';
8
11
  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';
12
+ import { Injectable, inject, DestroyRef, model, input, output, signal, computed, effect, afterNextRender, ViewEncapsulation, ChangeDetectionStrategy, Component, NgModule } from '@angular/core';
13
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
14
+ import * as i2 from '@angular/forms';
13
15
  import { FormsModule } from '@angular/forms';
14
- import { AXFormModule } from '@acorex/components/form';
16
+ import { map } from 'rxjs/operators';
15
17
 
16
- class AXTreeItemClickBaseEvent extends AXClickEvent {
17
- }
18
- class AXTreeViewBase {
18
+ /**
19
+ * Service for tree node operations
20
+ * Handles all business logic for tree node manipulation
21
+ */
22
+ class AXTreeViewService {
23
+ // ==================== Constants ====================
24
+ static { this.ROOT_LIST_ID = 'ax-tree-view-root-list'; }
25
+ static { this.NODE_DROP_PREFIX = 'ax-tree-view-node-drop-'; }
26
+ static { this.LIST_PREFIX = 'ax-tree-view-list-'; }
27
+ // ==================== Node Finding & Traversal ====================
28
+ /**
29
+ * Find a node by ID in the tree
30
+ */
31
+ findNodeById(nodes, id, idField = 'id') {
32
+ for (const node of nodes) {
33
+ if (node[idField] === id)
34
+ return node;
35
+ const children = node['children'];
36
+ if (children) {
37
+ const found = this.findNodeById(children, id, idField);
38
+ if (found)
39
+ return found;
40
+ }
41
+ }
42
+ return null;
43
+ }
44
+ /**
45
+ * Find parent node of a given node
46
+ */
47
+ findParentNode(nodes, targetNode, idField = 'id', childrenField = 'children') {
48
+ const targetId = targetNode[idField];
49
+ for (const node of nodes) {
50
+ const children = node[childrenField];
51
+ if (children?.some((child) => child[idField] === targetId)) {
52
+ return node;
53
+ }
54
+ if (children) {
55
+ const found = this.findParentNode(children, targetNode, idField, childrenField);
56
+ if (found)
57
+ return found;
58
+ }
59
+ }
60
+ return undefined;
61
+ }
62
+ /**
63
+ * Check if targetNode is a descendant of ancestorNode (or the same node)
64
+ * Prevents circular references by checking if target exists in ancestor's children tree
65
+ */
66
+ isValidDropTarget(movedNode, targetNode, idField = 'id', childrenField = 'children') {
67
+ const movedId = movedNode[idField];
68
+ const targetId = targetNode[idField];
69
+ if (movedId === targetId || this.isNodeDescendantOf(targetNode, movedNode, idField, childrenField)) {
70
+ return false;
71
+ }
72
+ return true;
73
+ }
74
+ /**
75
+ * Check if targetNode is a descendant of ancestorNode
76
+ */
77
+ isNodeDescendantOf(targetNode, ancestorNode, idField = 'id', childrenField = 'children') {
78
+ const targetId = targetNode[idField];
79
+ const ancestorId = ancestorNode[idField];
80
+ if (targetId === ancestorId) {
81
+ return true;
82
+ }
83
+ const children = ancestorNode[childrenField];
84
+ if (!children || children.length === 0) {
85
+ return false;
86
+ }
87
+ for (const child of children) {
88
+ const childId = child[idField];
89
+ if (childId === targetId) {
90
+ return true;
91
+ }
92
+ if (this.isNodeDescendantOf(targetNode, child, idField, childrenField)) {
93
+ return true;
94
+ }
95
+ }
96
+ return false;
97
+ }
98
+ /**
99
+ * Build a flat list of all visible focusable nodes
100
+ */
101
+ buildFlatNodeList(nodes, hiddenField = 'hidden', disabledField = 'disabled', expandedField = 'expanded', childrenField = 'children') {
102
+ const flatList = [];
103
+ const traverse = (nodeList, level, parent) => {
104
+ for (const node of nodeList) {
105
+ const hidden = node[hiddenField];
106
+ const disabled = node[disabledField];
107
+ if (hidden !== true && !disabled) {
108
+ flatList.push({ node, level, parent });
109
+ const expanded = node[expandedField];
110
+ const children = node[childrenField];
111
+ if (expanded && children) {
112
+ traverse(children, level + 1, node);
113
+ }
114
+ }
115
+ }
116
+ };
117
+ traverse(nodes, 0);
118
+ return flatList;
119
+ }
120
+ // ==================== Node State Checks ====================
121
+ /**
122
+ * Check if node has children
123
+ */
124
+ hasChildren(node, childrenField = 'children') {
125
+ const children = node[childrenField];
126
+ return Boolean(children?.length);
127
+ }
128
+ /**
129
+ * Check if node can be lazy loaded
130
+ */
131
+ canLazyLoad(node, isLazyDataSource, childrenCountField = 'childrenCount', childrenField = 'children') {
132
+ const childrenCount = node[childrenCountField];
133
+ return isLazyDataSource && Boolean(childrenCount && childrenCount > 0 && !this.hasChildren(node, childrenField));
134
+ }
135
+ // ==================== Selection Management ====================
136
+ /**
137
+ * Recursively select/deselect all children
138
+ */
139
+ selectAllChildren(children, selected, selectedField = 'selected', indeterminateField = 'indeterminate', childrenField = 'children') {
140
+ for (const child of children) {
141
+ child[selectedField] = selected;
142
+ child[indeterminateField] = false;
143
+ const childChildren = child[childrenField];
144
+ if (childChildren) {
145
+ this.selectAllChildren(childChildren, selected, selectedField, indeterminateField, childrenField);
146
+ }
147
+ }
148
+ }
149
+ /**
150
+ * Get selection state of children
151
+ */
152
+ getChildrenSelectionState(children, selectedField = 'selected', indeterminateField = 'indeterminate') {
153
+ let selectedCount = 0;
154
+ let indeterminateCount = 0;
155
+ for (const child of children) {
156
+ const selected = child[selectedField];
157
+ const indeterminate = child[indeterminateField];
158
+ if (selected && !indeterminate) {
159
+ selectedCount++;
160
+ }
161
+ if (indeterminate) {
162
+ indeterminateCount++;
163
+ }
164
+ }
165
+ return {
166
+ allSelected: selectedCount === children.length,
167
+ someSelected: selectedCount > 0 || indeterminateCount > 0,
168
+ };
169
+ }
170
+ /**
171
+ * Update parent node states based on children selection (with intermediate state support)
172
+ */
173
+ updateParentStates(nodes, changedNode, intermediateState, idField = 'id', childrenField = 'children', selectedField = 'selected', indeterminateField = 'indeterminate') {
174
+ const parent = this.findParentNode(nodes, changedNode, idField, childrenField);
175
+ const parentChildren = parent?.[childrenField];
176
+ if (!parent || !parentChildren)
177
+ return;
178
+ const { allSelected, someSelected } = this.getChildrenSelectionState(parentChildren, selectedField, indeterminateField);
179
+ if (allSelected) {
180
+ parent[selectedField] = true;
181
+ parent[indeterminateField] = false;
182
+ }
183
+ else if (someSelected) {
184
+ if (intermediateState) {
185
+ parent[selectedField] = true;
186
+ parent[indeterminateField] = true;
187
+ }
188
+ else {
189
+ parent[selectedField] = false;
190
+ parent[indeterminateField] = false;
191
+ }
192
+ }
193
+ else {
194
+ parent[selectedField] = false;
195
+ parent[indeterminateField] = false;
196
+ }
197
+ this.updateParentStates(nodes, parent, intermediateState, idField, childrenField, selectedField, indeterminateField);
198
+ }
199
+ /**
200
+ * Recursively deselect all nodes
201
+ */
202
+ deselectAllNodes(nodes, selectedField = 'selected', indeterminateField = 'indeterminate', childrenField = 'children') {
203
+ for (const node of nodes) {
204
+ node[selectedField] = false;
205
+ node[indeterminateField] = false;
206
+ const children = node[childrenField];
207
+ if (children) {
208
+ this.deselectAllNodes(children, selectedField, indeterminateField, childrenField);
209
+ }
210
+ }
211
+ }
212
+ /**
213
+ * Recursively set selection state for all nodes
214
+ */
215
+ setAllSelection(nodes, selected, selectedField = 'selected', indeterminateField = 'indeterminate', childrenField = 'children') {
216
+ for (const node of nodes) {
217
+ node[selectedField] = selected;
218
+ node[indeterminateField] = false;
219
+ const children = node[childrenField];
220
+ if (children) {
221
+ this.setAllSelection(children, selected, selectedField, indeterminateField, childrenField);
222
+ }
223
+ }
224
+ }
225
+ /**
226
+ * Recursively count selected nodes
227
+ */
228
+ countSelected(nodes, selectedField = 'selected', childrenField = 'children') {
229
+ let count = 0;
230
+ for (const node of nodes) {
231
+ if (node[selectedField])
232
+ count++;
233
+ const children = node[childrenField];
234
+ if (children) {
235
+ count += this.countSelected(children, selectedField, childrenField);
236
+ }
237
+ }
238
+ return count;
239
+ }
240
+ /**
241
+ * Recursively collect selected nodes
242
+ */
243
+ collectSelected(nodes, result, selectedField = 'selected', childrenField = 'children') {
244
+ for (const node of nodes) {
245
+ if (node[selectedField])
246
+ result.push(node);
247
+ const children = node[childrenField];
248
+ if (children) {
249
+ this.collectSelected(children, result, selectedField, childrenField);
250
+ }
251
+ }
252
+ }
253
+ /**
254
+ * Recursively remove selected nodes
255
+ */
256
+ removeSelected(nodes, selectedField = 'selected', indeterminateField = 'indeterminate', childrenField = 'children') {
257
+ for (let i = nodes.length - 1; i >= 0; i--) {
258
+ const node = nodes[i];
259
+ const selected = node[selectedField];
260
+ const indeterminate = node[indeterminateField];
261
+ if (selected && !indeterminate) {
262
+ nodes.splice(i, 1);
263
+ }
264
+ else {
265
+ const children = node[childrenField];
266
+ if (children) {
267
+ this.removeSelected(children, selectedField, indeterminateField, childrenField);
268
+ }
269
+ }
270
+ }
271
+ }
272
+ /**
273
+ * Recursively update all parent states in the tree (used after deletion)
274
+ */
275
+ updateAllParentStates(nodes, intermediateState, childrenField = 'children', selectedField = 'selected', indeterminateField = 'indeterminate') {
276
+ for (const node of nodes) {
277
+ const children = node[childrenField];
278
+ if (children && children.length > 0) {
279
+ this.updateAllParentStates(children, intermediateState, childrenField, selectedField, indeterminateField);
280
+ const { allSelected, someSelected } = this.getChildrenSelectionState(children, selectedField, indeterminateField);
281
+ if (allSelected) {
282
+ node[selectedField] = true;
283
+ node[indeterminateField] = false;
284
+ }
285
+ else if (someSelected) {
286
+ if (intermediateState) {
287
+ node[selectedField] = true;
288
+ node[indeterminateField] = true;
289
+ }
290
+ else {
291
+ node[selectedField] = false;
292
+ node[indeterminateField] = false;
293
+ }
294
+ }
295
+ else {
296
+ node[selectedField] = false;
297
+ node[indeterminateField] = false;
298
+ }
299
+ }
300
+ }
301
+ }
302
+ // ==================== Expansion Management ====================
303
+ /**
304
+ * Recursively set expanded state (with lazy loading)
305
+ */
306
+ async setExpandedState(nodes, expanded, isLazyDataSource, loadNodeChildren, expandedField = 'expanded', childrenField = 'children', childrenCountField = 'childrenCount') {
307
+ for (const node of nodes) {
308
+ const hasChildren = this.hasChildren(node, childrenField);
309
+ const canLazyLoad = this.canLazyLoad(node, isLazyDataSource, childrenCountField, childrenField);
310
+ if (hasChildren || canLazyLoad) {
311
+ if (expanded && canLazyLoad) {
312
+ await loadNodeChildren(node);
313
+ }
314
+ node[expandedField] = expanded;
315
+ const children = node[childrenField];
316
+ if (children) {
317
+ await this.setExpandedState(children, expanded, isLazyDataSource, loadNodeChildren, expandedField, childrenField, childrenCountField);
318
+ }
319
+ }
320
+ }
321
+ }
322
+ // ==================== Drag & Drop Helpers ====================
323
+ /**
324
+ * Get array reference by drop list ID
325
+ */
326
+ getArrayByListId(nodes, listId, idField = 'id', childrenField = 'children') {
327
+ if (listId === AXTreeViewService.ROOT_LIST_ID) {
328
+ return nodes;
329
+ }
330
+ if (listId.startsWith(AXTreeViewService.NODE_DROP_PREFIX)) {
331
+ const nodeId = listId.replace(AXTreeViewService.NODE_DROP_PREFIX, '');
332
+ const node = this.findNodeById(nodes, nodeId, idField);
333
+ return node ? [node] : null;
334
+ }
335
+ const nodeId = listId.replace(AXTreeViewService.LIST_PREFIX, '');
336
+ const node = this.findNodeById(nodes, nodeId, idField);
337
+ const children = node?.[childrenField];
338
+ return children ?? null;
339
+ }
340
+ /**
341
+ * Find parent node by list ID
342
+ */
343
+ findParentByListId(nodes, listId, idField = 'id') {
344
+ if (listId === AXTreeViewService.ROOT_LIST_ID) {
345
+ return undefined;
346
+ }
347
+ const prefix = listId.startsWith(AXTreeViewService.NODE_DROP_PREFIX)
348
+ ? AXTreeViewService.NODE_DROP_PREFIX
349
+ : AXTreeViewService.LIST_PREFIX;
350
+ const nodeId = listId.replace(prefix, '');
351
+ return this.findNodeById(nodes, nodeId, idField) ?? undefined;
352
+ }
353
+ /**
354
+ * Generate unique list ID for each node
355
+ */
356
+ getListId(node, idField = 'id') {
357
+ if (!node)
358
+ return AXTreeViewService.ROOT_LIST_ID;
359
+ const nodeId = node[idField];
360
+ return `${AXTreeViewService.LIST_PREFIX}${nodeId}`;
361
+ }
362
+ /**
363
+ * Get root list ID constant
364
+ */
365
+ getRootListId() {
366
+ return AXTreeViewService.ROOT_LIST_ID;
367
+ }
368
+ /**
369
+ * Get node drop prefix constant
370
+ */
371
+ getNodeDropPrefix() {
372
+ return AXTreeViewService.NODE_DROP_PREFIX;
373
+ }
374
+ /**
375
+ * Get list prefix constant
376
+ */
377
+ getListPrefix() {
378
+ return AXTreeViewService.LIST_PREFIX;
379
+ }
380
+ // ==================== Node Utilities ====================
381
+ /**
382
+ * Get all nodes in a flat array
383
+ */
384
+ getAllNodes(nodes, childrenField = 'children') {
385
+ const allNodes = [];
386
+ const traverse = (nodeList) => {
387
+ for (const node of nodeList) {
388
+ allNodes.push(node);
389
+ const children = node[childrenField];
390
+ if (children) {
391
+ traverse(children);
392
+ }
393
+ }
394
+ };
395
+ traverse(nodes);
396
+ return allNodes;
397
+ }
398
+ /**
399
+ * Get the path to a node (array of parent nodes from root to node)
400
+ */
401
+ getNodePath(nodes, nodeId) {
402
+ const path = [];
403
+ const node = this.findNodeById(nodes, nodeId);
404
+ if (!node) {
405
+ return path;
406
+ }
407
+ let current = node;
408
+ while (current) {
409
+ path.unshift(current);
410
+ const parent = this.findParentNode(nodes, current);
411
+ current = parent ?? null;
412
+ }
413
+ return path;
414
+ }
415
+ /**
416
+ * Get the level/depth of a node (0 = root level)
417
+ */
418
+ getNodeLevel(nodes, nodeId) {
419
+ const path = this.getNodePath(nodes, nodeId);
420
+ return path.length > 0 ? path.length - 1 : -1;
421
+ }
422
+ /**
423
+ * Get sibling nodes of a given node
424
+ */
425
+ getSiblings(nodes, nodeId, idField = 'id', childrenField = 'children') {
426
+ const node = this.findNodeById(nodes, nodeId, idField);
427
+ if (!node) {
428
+ return [];
429
+ }
430
+ const parent = this.findParentNode(nodes, node, idField, childrenField);
431
+ const siblingsArray = parent?.[childrenField] ?? nodes;
432
+ return siblingsArray.filter((n) => n[idField] !== nodeId);
433
+ }
434
+ /**
435
+ * Clone a node (creates a deep copy)
436
+ */
437
+ cloneNode(node, idField = 'id', titleField = 'title', tooltipField = 'tooltip', iconField = 'icon', expandedField = 'expanded', selectedField = 'selected', indeterminateField = 'indeterminate', disabledField = 'disabled', hiddenField = 'hidden', childrenCountField = 'childrenCount', dataField = 'data', childrenField = 'children') {
438
+ const cloned = {
439
+ [idField]: `${node[idField]}-clone-${Date.now()}`,
440
+ [titleField]: node[titleField],
441
+ [tooltipField]: node[tooltipField],
442
+ [iconField]: node[iconField],
443
+ [expandedField]: node[expandedField],
444
+ [selectedField]: false, // Cloned nodes are not selected by default
445
+ [indeterminateField]: false,
446
+ [disabledField]: node[disabledField],
447
+ [hiddenField]: node[hiddenField],
448
+ [childrenCountField]: node[childrenCountField],
449
+ [dataField]: node[dataField] ? JSON.parse(JSON.stringify(node[dataField])) : undefined,
450
+ };
451
+ const children = node[childrenField];
452
+ if (children && children.length > 0) {
453
+ cloned[childrenField] = children.map((child) => this.cloneNode(child, idField, titleField, tooltipField, iconField, expandedField, selectedField, indeterminateField, disabledField, hiddenField, childrenCountField, dataField, childrenField));
454
+ cloned[childrenCountField] = cloned[childrenField].length;
455
+ }
456
+ return cloned;
457
+ }
458
+ /**
459
+ * Validate node structure (check for required fields and circular references)
460
+ */
461
+ validateNode(node, visitedIds = new Set(), idField = 'id', titleField = 'title', childrenField = 'children', childrenCountField = 'childrenCount') {
462
+ const errors = [];
463
+ const nodeId = node[idField];
464
+ const nodeTitle = node[titleField];
465
+ if (!nodeId) {
466
+ errors.push(`Node must have an ${idField}`);
467
+ }
468
+ if (!nodeTitle) {
469
+ errors.push(`Node must have a ${titleField}`);
470
+ }
471
+ if (nodeId && visitedIds.has(nodeId)) {
472
+ errors.push(`Circular reference detected: node ${nodeId} appears multiple times in the tree`);
473
+ }
474
+ const children = node[childrenField];
475
+ if (children) {
476
+ const newVisited = new Set(visitedIds);
477
+ if (nodeId) {
478
+ newVisited.add(nodeId);
479
+ }
480
+ for (const child of children) {
481
+ const childValidation = this.validateNode(child, newVisited, idField, titleField, childrenField, childrenCountField);
482
+ if (!childValidation.valid) {
483
+ errors.push(...childValidation.errors.map((e) => `Child of ${nodeId}: ${e}`));
484
+ }
485
+ }
486
+ const childrenCount = node[childrenCountField];
487
+ if (childrenCount !== undefined && childrenCount !== children.length) {
488
+ errors.push(`Node ${nodeId}: ${childrenCountField} (${childrenCount}) does not match ${childrenField} array length (${children.length})`);
489
+ }
490
+ }
491
+ return {
492
+ valid: errors.length === 0,
493
+ errors,
494
+ };
495
+ }
496
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
497
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewService }); }
19
498
  }
499
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewService, decorators: [{
500
+ type: Injectable
501
+ }] });
20
502
 
21
- class AXTreeViewItemComponent extends NXComponent {
503
+ class AXTreeViewComponent {
22
504
  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" }] : []));
505
+ // ==================== Dependencies ====================
506
+ this.treeService = inject(AXTreeViewService);
30
507
  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`;
39
- }
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') {
508
+ this.destroyRef = inject(DestroyRef);
509
+ // ==================== Inputs ====================
510
+ /** Tree data source - can be static array or lazy loading function */
511
+ this.datasource = model.required(...(ngDevMode ? [{ debugName: "datasource" }] : []));
512
+ /** Selection mode: 'single' (click to select) or 'multiple' (checkbox selection) */
513
+ this.selectMode = input('multiple', ...(ngDevMode ? [{ debugName: "selectMode" }] : []));
514
+ /** Whether to show checkboxes for selection (only applies to multiple mode) */
515
+ this.showCheckbox = input(true, ...(ngDevMode ? [{ debugName: "showCheckbox" }] : []));
516
+ /** Selection behavior: 'all' (select anything, no special behavior), 'intermediate' (parent indeterminate state when children selected), 'leaf' (only leaf nodes selectable), 'nested' (selecting parent selects all children) */
517
+ this.selectionBehavior = input('all', ...(ngDevMode ? [{ debugName: "selectionBehavior" }] : []));
518
+ /** When true, clicking on a node toggles its selection (works for both single and multiple modes) */
519
+ this.checkOnClick = input(false, ...(ngDevMode ? [{ debugName: "checkOnClick" }] : []));
520
+ /** Drag and drop mode: 'none' (disabled), 'handler' (drag handle), 'item' (entire item) */
521
+ this.dragMode = input('handler', ...(ngDevMode ? [{ debugName: "dragMode" }] : []));
522
+ /** Drag operation type: 'order-only' (reorder only), 'move' (move between parents), 'both' (allow both) */
523
+ this.dragOperationType = input('both', ...(ngDevMode ? [{ debugName: "dragOperationType" }] : []));
524
+ /** Whether to show icons */
525
+ this.showIcons = input(true, ...(ngDevMode ? [{ debugName: "showIcons" }] : []));
526
+ /** Whether to show children count badge */
527
+ this.showChildrenBadge = input(true, ...(ngDevMode ? [{ debugName: "showChildrenBadge" }] : []));
528
+ /** Custom icon for expanded nodes */
529
+ this.expandedIcon = input('fa-solid fa-chevron-down', ...(ngDevMode ? [{ debugName: "expandedIcon" }] : []));
530
+ /** Custom icon for collapsed nodes */
531
+ this.collapsedIcon = input('fa-solid fa-chevron-right', ...(ngDevMode ? [{ debugName: "collapsedIcon" }] : []));
532
+ /** Indent size in pixels for each level */
533
+ this.indentSize = input(16, ...(ngDevMode ? [{ debugName: "indentSize" }] : []));
534
+ /** Visual style variant */
535
+ this.look = input('default', ...(ngDevMode ? [{ debugName: "look" }] : []));
536
+ /** Custom template for tree items */
537
+ this.nodeTemplate = input(...(ngDevMode ? [undefined, { debugName: "nodeTemplate" }] : []));
538
+ /** Field name for node ID (default: 'id') */
539
+ this.idField = input('id', ...(ngDevMode ? [{ debugName: "idField" }] : []));
540
+ /** Field name for node title (default: 'title') */
541
+ this.titleField = input('title', ...(ngDevMode ? [{ debugName: "titleField" }] : []));
542
+ /** Field name for node tooltip (default: 'tooltip') */
543
+ this.tooltipField = input('tooltip', ...(ngDevMode ? [{ debugName: "tooltipField" }] : []));
544
+ /** Field name for node icon (default: 'icon') */
545
+ this.iconField = input('icon', ...(ngDevMode ? [{ debugName: "iconField" }] : []));
546
+ /** Field name for expanded state (default: 'expanded') */
547
+ this.expandedField = input('expanded', ...(ngDevMode ? [{ debugName: "expandedField" }] : []));
548
+ /** Field name for selected state (default: 'selected') */
549
+ this.selectedField = input('selected', ...(ngDevMode ? [{ debugName: "selectedField" }] : []));
550
+ /** Field name for indeterminate state (default: 'indeterminate') */
551
+ this.indeterminateField = input('indeterminate', ...(ngDevMode ? [{ debugName: "indeterminateField" }] : []));
552
+ /** Field name for disabled state (default: 'disabled') */
553
+ this.disabledField = input('disabled', ...(ngDevMode ? [{ debugName: "disabledField" }] : []));
554
+ /** Field name for hidden state (default: 'hidden') */
555
+ this.hiddenField = input('hidden', ...(ngDevMode ? [{ debugName: "hiddenField" }] : []));
556
+ /** Field name for children array (default: 'children') */
557
+ this.childrenField = input('children', ...(ngDevMode ? [{ debugName: "childrenField" }] : []));
558
+ /** Field name for children count (default: 'childrenCount') */
559
+ this.childrenCountField = input('childrenCount', ...(ngDevMode ? [{ debugName: "childrenCountField" }] : []));
560
+ /** Field name for custom data (default: 'data') */
561
+ this.dataField = input('data', ...(ngDevMode ? [{ debugName: "dataField" }] : []));
562
+ // ==================== Outputs ====================
563
+ /** Emitted before a drop operation - set canceled to true to prevent drop */
564
+ this.onBeforeDrop = output();
565
+ /** Emitted when a node is toggled (expanded/collapsed) */
566
+ this.onNodeToggle = output();
567
+ /** Emitted when a node is selected/deselected */
568
+ this.onNodeSelect = output();
569
+ /** Emitted when selection changes - returns all currently selected nodes */
570
+ this.onSelectionChange = output();
571
+ /** Emitted when nodes are reordered within the same parent */
572
+ this.onOrderChange = output();
573
+ /** Emitted when a node is moved to a different parent */
574
+ this.onMoveChange = output();
575
+ /** Emitted for any item change (order or move) */
576
+ this.onItemsChange = output();
577
+ // ==================== Internal State ====================
578
+ /** Internal signal for tree nodes */
579
+ this.nodes = signal([], ...(ngDevMode ? [{ debugName: "nodes" }] : []));
580
+ /** Internal signal for tracking loading state */
581
+ this.loadingNodes = signal(new Set(), ...(ngDevMode ? [{ debugName: "loadingNodes" }] : []));
582
+ /** Currently focused node ID for keyboard navigation */
583
+ this.focusedNodeId = signal(null, ...(ngDevMode ? [{ debugName: "focusedNodeId" }] : []));
584
+ /** RTL detection signal */
585
+ this.isRtl = signal(this.platformService.isRtl(), ...(ngDevMode ? [{ debugName: "isRtl" }] : []));
586
+ /** Computed chevron icons that flip for RTL */
587
+ this.directionExpandedIcon = computed(() => this.expandedIcon(), ...(ngDevMode ? [{ debugName: "directionExpandedIcon" }] : []));
588
+ this.directionCollapsedIcon = computed(() => {
589
+ const isRtlDirection = this.isRtl();
590
+ const defaultIcon = this.collapsedIcon();
591
+ if (isRtlDirection && defaultIcon === 'fa-solid fa-chevron-right') {
592
+ return 'fa-solid fa-chevron-left';
593
+ }
594
+ if (!isRtlDirection && defaultIcon === 'fa-solid fa-chevron-left') {
595
+ return 'fa-solid fa-chevron-right';
596
+ }
597
+ return defaultIcon;
598
+ }, ...(ngDevMode ? [{ debugName: "directionCollapsedIcon" }] : []));
599
+ /** Flag to prevent infinite loops when syncing datasource */
600
+ this.isUpdatingFromDatasource = false;
601
+ /** Computed to check if datasource is a function */
602
+ this.isLazyDataSource = computed(() => typeof this.datasource() === 'function', ...(ngDevMode ? [{ debugName: "isLazyDataSource" }] : []));
603
+ /** Computed: Returns true when selection is restricted to leaf nodes only */
604
+ this.isLeafOnlyMode = computed(() => this.selectionBehavior() === 'leaf', ...(ngDevMode ? [{ debugName: "isLeafOnlyMode" }] : []));
605
+ /** Computed: Returns true when selecting a parent automatically selects all its children */
606
+ this.cascadesToChildren = computed(() => {
607
+ const behavior = this.selectionBehavior();
608
+ return behavior === 'nested' || behavior === 'intermediate-nested';
609
+ }, ...(ngDevMode ? [{ debugName: "cascadesToChildren" }] : []));
610
+ /** Computed: Returns true when parent nodes show indeterminate state based on children selection */
611
+ this.hasIntermediateState = computed(() => {
612
+ const behavior = this.selectionBehavior();
613
+ return behavior === 'intermediate' || behavior === 'intermediate-nested';
614
+ }, ...(ngDevMode ? [{ debugName: "hasIntermediateState" }] : []));
615
+ // ==================== Effects ====================
616
+ /** Effect to handle datasource changes */
617
+ this.#datasourceEffect = effect(async () => {
618
+ if (this.isUpdatingFromDatasource) {
619
+ return;
620
+ }
621
+ const ds = this.datasource();
622
+ if (Array.isArray(ds)) {
623
+ this.nodes.set([...ds]);
624
+ }
625
+ else if (typeof ds === 'function') {
626
+ try {
627
+ await this.loadRootItems(ds);
628
+ }
629
+ catch (error) {
630
+ this.handleError('Failed to load root items', error);
631
+ }
632
+ }
633
+ }, ...(ngDevMode ? [{ debugName: "#datasourceEffect" }] : []));
634
+ /** Initialize direction change listener */
635
+ this.#initDirectionListener = afterNextRender(() => {
636
+ this.platformService.directionChange
637
+ .pipe(map((event) => event.data === 'rtl'), takeUntilDestroyed(this.destroyRef))
638
+ .subscribe((isRtl) => this.isRtl.set(isRtl));
639
+ });
640
+ }
641
+ // ==================== Node Property Helpers ====================
642
+ /**
643
+ * Get a property value from a node using the configured field name
644
+ */
645
+ getNodeProp(node, fieldName, defaultValue) {
646
+ return node[fieldName] ?? defaultValue;
647
+ }
648
+ /**
649
+ * Set a property value on a node using the configured field name
650
+ */
651
+ setNodeProp(node, fieldName, value) {
652
+ node[fieldName] = value;
653
+ }
654
+ /**
655
+ * Get node ID
656
+ */
657
+ getNodeId(node) {
658
+ return this.getNodeProp(node, this.idField(), '');
659
+ }
660
+ /**
661
+ * Get node title
662
+ */
663
+ getNodeTitle(node) {
664
+ return this.getNodeProp(node, this.titleField(), '');
665
+ }
666
+ /**
667
+ * Get node tooltip
668
+ */
669
+ getNodeTooltip(node) {
670
+ return this.getNodeProp(node, this.tooltipField(), undefined);
671
+ }
672
+ /**
673
+ * Get node icon
674
+ */
675
+ getNodeIcon(node) {
676
+ return this.getNodeProp(node, this.iconField(), undefined);
677
+ }
678
+ /**
679
+ * Get node expanded state
680
+ */
681
+ getNodeExpanded(node) {
682
+ return this.getNodeProp(node, this.expandedField(), false);
683
+ }
684
+ /**
685
+ * Set node expanded state
686
+ */
687
+ setNodeExpanded(node, value) {
688
+ this.setNodeProp(node, this.expandedField(), value);
689
+ }
690
+ /**
691
+ * Get node selected state
692
+ */
693
+ getNodeSelected(node) {
694
+ return this.getNodeProp(node, this.selectedField(), false);
695
+ }
696
+ /**
697
+ * Set node selected state
698
+ */
699
+ setNodeSelected(node, value) {
700
+ this.setNodeProp(node, this.selectedField(), value);
701
+ }
702
+ /**
703
+ * Get node indeterminate state
704
+ */
705
+ getNodeIndeterminate(node) {
706
+ return this.getNodeProp(node, this.indeterminateField(), false);
707
+ }
708
+ /**
709
+ * Set node indeterminate state
710
+ */
711
+ setNodeIndeterminate(node, value) {
712
+ this.setNodeProp(node, this.indeterminateField(), value);
713
+ }
714
+ /**
715
+ * Get node disabled state
716
+ */
717
+ getNodeDisabled(node) {
718
+ return this.getNodeProp(node, this.disabledField(), false);
719
+ }
720
+ /**
721
+ * Get node hidden state
722
+ */
723
+ getNodeHidden(node) {
724
+ return this.getNodeProp(node, this.hiddenField(), false);
725
+ }
726
+ /**
727
+ * Get node children array
728
+ */
729
+ getNodeChildren(node) {
730
+ return this.getNodeProp(node, this.childrenField(), undefined);
731
+ }
732
+ /**
733
+ * Set node children array
734
+ */
735
+ setNodeChildren(node, value) {
736
+ this.setNodeProp(node, this.childrenField(), value);
737
+ }
738
+ /**
739
+ * Get node children count
740
+ */
741
+ getNodeChildrenCount(node) {
742
+ return this.getNodeProp(node, this.childrenCountField(), undefined);
743
+ }
744
+ /**
745
+ * Set node children count
746
+ */
747
+ setNodeChildrenCount(node, value) {
748
+ this.setNodeProp(node, this.childrenCountField(), value);
749
+ }
750
+ // ==================== Effects ====================
751
+ /** Effect to handle datasource changes */
752
+ #datasourceEffect;
753
+ /** Initialize direction change listener */
754
+ #initDirectionListener;
755
+ // ==================== Public API ====================
756
+ /**
757
+ * Expand all nodes in the tree (with lazy loading support)
758
+ */
759
+ async expandAll() {
760
+ await this.treeService.setExpandedState(this.nodes(), true, this.isLazyDataSource(), (node) => this.loadNodeChildren(node), this.expandedField(), this.childrenField(), this.childrenCountField());
761
+ this.refreshNodes();
762
+ }
763
+ /**
764
+ * Collapse all nodes in the tree
765
+ */
766
+ collapseAll() {
767
+ this.treeService.setExpandedState(this.nodes(), false, this.isLazyDataSource(), (node) => this.loadNodeChildren(node), this.expandedField(), this.childrenField(), this.childrenCountField());
768
+ this.refreshNodes();
769
+ }
770
+ /**
771
+ * Get count of selected nodes
772
+ */
773
+ getSelectedCount() {
774
+ return this.treeService.countSelected(this.nodes(), this.selectedField(), this.childrenField());
775
+ }
776
+ /**
777
+ * Check if any nodes are selected
778
+ */
779
+ hasSelection() {
780
+ return this.getSelectedCount() > 0;
781
+ }
782
+ /**
783
+ * Get all selected nodes
784
+ */
785
+ getSelectedNodes() {
786
+ const selected = [];
787
+ this.treeService.collectSelected(this.nodes(), selected, this.selectedField(), this.childrenField());
788
+ return selected;
789
+ }
790
+ /**
791
+ * Delete selected nodes from the tree
792
+ */
793
+ deleteSelected() {
794
+ this.treeService.removeSelected(this.nodes(), this.selectedField(), this.indeterminateField(), this.childrenField());
795
+ if (!this.isLeafOnlyMode()) {
796
+ this.treeService.updateAllParentStates(this.nodes(), this.hasIntermediateState(), this.childrenField(), this.selectedField(), this.indeterminateField());
797
+ }
798
+ this.refreshNodes();
799
+ this.emitSelectionChange();
800
+ }
801
+ /**
802
+ * Select all nodes in the tree
803
+ */
804
+ selectAll() {
805
+ if (this.selectMode() === 'none') {
47
806
  return;
48
807
  }
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);
808
+ if (this.isLeafOnlyMode()) {
809
+ // Only select leaf nodes
810
+ const selectLeafs = (nodes) => {
811
+ for (const node of nodes) {
812
+ if (this.isLeafNode(node) && !this.getNodeDisabled(node)) {
813
+ this.setNodeSelected(node, true);
814
+ this.setNodeIndeterminate(node, false);
815
+ }
816
+ const children = this.getNodeChildren(node);
817
+ if (children) {
818
+ selectLeafs(children);
819
+ }
820
+ }
821
+ };
822
+ selectLeafs(this.nodes());
823
+ }
824
+ else {
825
+ this.treeService.setAllSelection(this.nodes(), true, this.selectedField(), this.indeterminateField(), this.childrenField());
826
+ }
827
+ this.refreshNodes();
828
+ this.emitSelectionChange();
829
+ }
830
+ /**
831
+ * Deselect all nodes in the tree
832
+ */
833
+ deselectAll() {
834
+ this.treeService.setAllSelection(this.nodes(), false, this.selectedField(), this.indeterminateField(), this.childrenField());
835
+ this.refreshNodes();
836
+ this.emitSelectionChange();
837
+ }
838
+ /**
839
+ * Find a node by ID in the tree
840
+ */
841
+ findNode(id) {
842
+ return this.treeService.findNodeById(this.nodes(), id, this.idField());
843
+ }
844
+ /**
845
+ * Refresh the tree to trigger change detection
846
+ */
847
+ refresh() {
848
+ this.refreshNodes();
849
+ }
850
+ /**
851
+ * Check if a node is currently loading
852
+ */
853
+ isNodeLoading(nodeId) {
854
+ return this.loadingNodes().has(nodeId);
855
+ }
856
+ /**
857
+ * Get loading state for a node (internal state)
858
+ */
859
+ getNodeLoading(node) {
860
+ return this.loadingNodes().has(this.getNodeId(node));
861
+ }
862
+ /**
863
+ * Edit/update a node's properties
864
+ * @param nodeId - The ID of the node to edit
865
+ * @param updates - Partial node object with properties to update
866
+ * @returns true if node was found and updated, false otherwise
867
+ */
868
+ editNode(nodeId, updates) {
869
+ const node = this.findNode(nodeId);
870
+ if (!node) {
871
+ return false;
872
+ }
873
+ // Update node properties
874
+ Object.assign(node, updates);
875
+ // If children array is provided, ensure it exists
876
+ const childrenField = this.childrenField();
877
+ if (updates[childrenField] !== undefined) {
878
+ this.setNodeChildren(node, updates[childrenField]);
879
+ }
880
+ // Update childrenCount if children array is provided
881
+ if (updates[childrenField] !== undefined) {
882
+ const children = updates[childrenField];
883
+ this.setNodeChildrenCount(node, children?.length);
884
+ }
885
+ this.refreshNodes();
886
+ return true;
887
+ }
888
+ /**
889
+ * Add a child node to a parent node
890
+ * @param parentId - The ID of the parent node
891
+ * @param childNode - The child node to add
892
+ * @param index - Optional index to insert at (default: append to end)
893
+ * @returns true if parent was found and child was added, false otherwise
894
+ */
895
+ addChild(parentId, childNode, index) {
896
+ const parent = this.findNode(parentId);
897
+ if (!parent) {
898
+ return false;
899
+ }
900
+ // Ensure children array exists
901
+ let children = this.getNodeChildren(parent);
902
+ if (!children) {
903
+ children = [];
904
+ this.setNodeChildren(parent, children);
905
+ }
906
+ // Insert or append child
907
+ if (index !== undefined && index >= 0 && index <= children.length) {
908
+ children.splice(index, 0, childNode);
909
+ }
910
+ else {
911
+ children.push(childNode);
912
+ }
913
+ // Update childrenCount
914
+ this.setNodeChildrenCount(parent, children.length);
915
+ // Auto-expand parent if it was collapsed
916
+ if (!this.getNodeExpanded(parent)) {
917
+ this.setNodeExpanded(parent, true);
918
+ }
919
+ this.refreshNodes();
920
+ return true;
921
+ }
922
+ /**
923
+ * Remove a node from the tree
924
+ * @param nodeId - The ID of the node to remove
925
+ * @returns The removed node if found, null otherwise
926
+ */
927
+ removeNode(nodeId) {
928
+ const node = this.findNode(nodeId);
929
+ if (!node) {
930
+ return null;
931
+ }
932
+ // Find parent to remove from its children array
933
+ const parent = this.treeService.findParentNode(this.nodes(), node, this.idField(), this.childrenField());
934
+ const parentChildren = parent ? this.getNodeChildren(parent) : undefined;
935
+ const targetArray = parentChildren ?? this.nodes();
936
+ // Find and remove the node
937
+ const index = targetArray.findIndex((n) => this.getNodeId(n) === nodeId);
938
+ if (index !== -1) {
939
+ const removed = targetArray.splice(index, 1)[0];
940
+ // Update parent's childrenCount if it exists
941
+ if (parent) {
942
+ const updatedChildren = this.getNodeChildren(parent);
943
+ this.setNodeChildrenCount(parent, updatedChildren?.length ?? 0);
944
+ }
945
+ // Update parent states if needed
946
+ if (this.hasIntermediateState()) {
947
+ this.treeService.updateAllParentStates(this.nodes(), this.hasIntermediateState(), this.childrenField(), this.selectedField(), this.indeterminateField());
948
+ }
949
+ this.refreshNodes();
950
+ return removed;
951
+ }
952
+ return null;
953
+ }
954
+ /**
955
+ * Expand a specific node
956
+ * @param nodeId - The ID of the node to expand
957
+ * @returns Promise that resolves when expansion is complete (if lazy loading)
958
+ */
959
+ async expandNode(nodeId) {
960
+ const node = this.findNode(nodeId);
961
+ if (!node) {
962
+ return;
963
+ }
964
+ const hasChildren = this.treeService.hasChildren(node, this.childrenField());
965
+ const canLazyLoad = this.treeService.canLazyLoad(node, this.isLazyDataSource(), this.childrenCountField(), this.childrenField());
966
+ if (hasChildren || canLazyLoad) {
967
+ if (canLazyLoad) {
968
+ await this.loadNodeChildren(node);
969
+ }
970
+ this.setNodeExpanded(node, true);
971
+ this.refreshNodes();
972
+ this.onNodeToggle.emit({ component: this, node, nativeEvent: new Event('expand') });
973
+ }
974
+ }
975
+ /**
976
+ * Collapse a specific node
977
+ * @param nodeId - The ID of the node to collapse
978
+ */
979
+ collapseNode(nodeId) {
980
+ const node = this.findNode(nodeId);
981
+ if (!node) {
982
+ return;
983
+ }
984
+ if (this.getNodeExpanded(node)) {
985
+ this.setNodeExpanded(node, false);
986
+ this.refreshNodes();
987
+ this.onNodeToggle.emit({ component: this, node, nativeEvent: new Event('collapse') });
988
+ }
989
+ }
990
+ /**
991
+ * Toggle expansion state of a specific node
992
+ * @param nodeId - The ID of the node to toggle
993
+ * @returns Promise that resolves when toggle is complete (if lazy loading)
994
+ */
995
+ async toggleNodeExpansion(nodeId) {
996
+ const node = this.findNode(nodeId);
997
+ if (!node) {
998
+ return;
999
+ }
1000
+ if (this.getNodeExpanded(node)) {
1001
+ this.collapseNode(nodeId);
1002
+ }
1003
+ else {
1004
+ await this.expandNode(nodeId);
1005
+ }
1006
+ }
1007
+ /**
1008
+ * Programmatically select a node
1009
+ * @param nodeId - The ID of the node to select
1010
+ * @returns true if node was found and selected, false otherwise
1011
+ */
1012
+ selectNode(nodeId) {
1013
+ if (this.selectMode() === 'none') {
1014
+ return false;
1015
+ }
1016
+ const node = this.findNode(nodeId);
1017
+ if (!node || this.getNodeDisabled(node) || !this.canSelectNode(node)) {
1018
+ return false;
1019
+ }
1020
+ const mode = this.selectMode();
1021
+ if (mode === 'single') {
1022
+ this.treeService.deselectAllNodes(this.nodes(), this.selectedField(), this.indeterminateField(), this.childrenField());
1023
+ this.setNodeSelected(node, true);
1024
+ this.setNodeIndeterminate(node, false);
1025
+ }
1026
+ else {
1027
+ this.setNodeSelected(node, true);
1028
+ this.setNodeIndeterminate(node, false);
1029
+ const children = this.getNodeChildren(node);
1030
+ if (this.cascadesToChildren() && children && !this.isLeafOnlyMode()) {
1031
+ this.treeService.selectAllChildren(children, true, this.selectedField(), this.indeterminateField(), this.childrenField());
1032
+ }
1033
+ if (this.hasIntermediateState() && !this.isLeafOnlyMode()) {
1034
+ this.treeService.updateParentStates(this.nodes(), node, this.hasIntermediateState(), this.idField(), this.childrenField(), this.selectedField(), this.indeterminateField());
1035
+ }
1036
+ }
1037
+ this.refreshNodes();
1038
+ this.onNodeSelect.emit({
1039
+ component: this,
1040
+ node,
1041
+ isUserInteraction: false,
1042
+ });
1043
+ this.emitSelectionChange();
1044
+ return true;
1045
+ }
1046
+ /**
1047
+ * Programmatically deselect a node
1048
+ * @param nodeId - The ID of the node to deselect
1049
+ * @returns true if node was found and deselected, false otherwise
1050
+ */
1051
+ deselectNode(nodeId) {
1052
+ const node = this.findNode(nodeId);
1053
+ if (!node) {
1054
+ return false;
1055
+ }
1056
+ this.setNodeSelected(node, false);
1057
+ this.setNodeIndeterminate(node, false);
1058
+ const children = this.getNodeChildren(node);
1059
+ if (this.cascadesToChildren() && children && !this.isLeafOnlyMode()) {
1060
+ this.treeService.selectAllChildren(children, false, this.selectedField(), this.indeterminateField(), this.childrenField());
1061
+ }
1062
+ if (this.hasIntermediateState() && !this.isLeafOnlyMode()) {
1063
+ this.treeService.updateParentStates(this.nodes(), node, this.hasIntermediateState(), this.idField(), this.childrenField(), this.selectedField(), this.indeterminateField());
1064
+ }
1065
+ this.refreshNodes();
1066
+ this.onNodeSelect.emit({
1067
+ component: this,
1068
+ node,
1069
+ isUserInteraction: false,
1070
+ });
1071
+ this.emitSelectionChange();
1072
+ return true;
1073
+ }
1074
+ /**
1075
+ * Get parent node of a given node
1076
+ * @param nodeId - The ID of the node
1077
+ * @returns The parent node if found, null otherwise
1078
+ */
1079
+ getParent(nodeId) {
1080
+ const node = this.findNode(nodeId);
1081
+ if (!node) {
1082
+ return null;
1083
+ }
1084
+ return this.treeService.findParentNode(this.nodes(), node, this.idField(), this.childrenField()) ?? null;
1085
+ }
1086
+ /**
1087
+ * Get children of a node
1088
+ * @param nodeId - The ID of the parent node
1089
+ * @returns Array of child nodes, or null if node not found
1090
+ */
1091
+ getChildren(nodeId) {
1092
+ const node = this.findNode(nodeId);
1093
+ if (!node) {
1094
+ return null;
1095
+ }
1096
+ return this.getNodeChildren(node) ?? [];
1097
+ }
1098
+ /**
1099
+ * Get all root nodes
1100
+ * @returns Array of root nodes
1101
+ */
1102
+ getRootNodes() {
1103
+ return [...this.nodes()];
1104
+ }
1105
+ /**
1106
+ * Get all nodes in a flat array
1107
+ * @returns Array of all nodes in the tree
1108
+ */
1109
+ getAllNodes() {
1110
+ const allNodes = [];
1111
+ const traverse = (nodes) => {
1112
+ for (const node of nodes) {
1113
+ allNodes.push(node);
1114
+ const children = this.getNodeChildren(node);
1115
+ if (children) {
1116
+ traverse(children);
1117
+ }
1118
+ }
1119
+ };
1120
+ traverse(this.nodes());
1121
+ return allNodes;
1122
+ }
1123
+ /**
1124
+ * Get the path to a node (array of parent IDs from root to node)
1125
+ * @param nodeId - The ID of the node
1126
+ * @returns Array of node IDs representing the path, or empty array if node not found
1127
+ */
1128
+ getNodePath(nodeId) {
1129
+ const path = [];
1130
+ const node = this.findNode(nodeId);
1131
+ if (!node) {
1132
+ return path;
1133
+ }
1134
+ let current = node;
1135
+ while (current) {
1136
+ path.unshift(this.getNodeId(current));
1137
+ const parent = this.treeService.findParentNode(this.nodes(), current, this.idField(), this.childrenField());
1138
+ current = parent ?? null;
1139
+ }
1140
+ return path;
1141
+ }
1142
+ /**
1143
+ * Get the level/depth of a node (0 = root level)
1144
+ * @param nodeId - The ID of the node
1145
+ * @returns The level of the node, or -1 if node not found
1146
+ */
1147
+ getNodeLevel(nodeId) {
1148
+ const path = this.getNodePath(nodeId);
1149
+ return path.length > 0 ? path.length - 1 : -1;
1150
+ }
1151
+ /**
1152
+ * Programmatically move a node to a new parent
1153
+ * @param nodeId - The ID of the node to move
1154
+ * @param newParentId - The ID of the new parent (undefined for root level)
1155
+ * @param index - Optional index to insert at (default: append to end)
1156
+ * @returns true if move was successful, false otherwise
1157
+ */
1158
+ moveNode(nodeId, newParentId, index) {
1159
+ const node = this.findNode(nodeId);
1160
+ if (!node) {
1161
+ return false;
1162
+ }
1163
+ // Find current parent
1164
+ const currentParent = this.treeService.findParentNode(this.nodes(), node, this.idField(), this.childrenField());
1165
+ const currentParentChildren = currentParent ? this.getNodeChildren(currentParent) : undefined;
1166
+ const currentArray = currentParentChildren ?? this.nodes();
1167
+ // Find and remove from current location
1168
+ const currentIndex = currentArray.findIndex((n) => this.getNodeId(n) === nodeId);
1169
+ if (currentIndex === -1) {
1170
+ return false;
1171
+ }
1172
+ const movedNode = currentArray.splice(currentIndex, 1)[0];
1173
+ // Find new parent
1174
+ let targetArray;
1175
+ let newParent;
1176
+ if (newParentId) {
1177
+ newParent = this.findNode(newParentId);
1178
+ if (!newParent) {
1179
+ // Restore node if new parent not found
1180
+ currentArray.splice(currentIndex, 0, movedNode);
1181
+ return false;
1182
+ }
1183
+ // Validate drop target
1184
+ if (!this.treeService.isValidDropTarget(movedNode, newParent, this.idField(), this.childrenField())) {
1185
+ // Restore node if invalid drop target
1186
+ currentArray.splice(currentIndex, 0, movedNode);
1187
+ return false;
1188
+ }
1189
+ let newParentChildren = this.getNodeChildren(newParent);
1190
+ if (!newParentChildren) {
1191
+ newParentChildren = [];
1192
+ this.setNodeChildren(newParent, newParentChildren);
1193
+ }
1194
+ targetArray = newParentChildren;
1195
+ }
1196
+ else {
1197
+ targetArray = this.nodes();
1198
+ }
1199
+ // Calculate new index before inserting
1200
+ const newIndex = index !== undefined && index >= 0 && index <= targetArray.length ? index : targetArray.length;
1201
+ // Insert at new location
1202
+ if (index !== undefined && index >= 0 && index <= targetArray.length) {
1203
+ targetArray.splice(index, 0, movedNode);
1204
+ }
1205
+ else {
1206
+ targetArray.push(movedNode);
1207
+ }
1208
+ // Update childrenCount
1209
+ if (currentParent) {
1210
+ const updatedChildren = this.getNodeChildren(currentParent);
1211
+ this.setNodeChildrenCount(currentParent, updatedChildren?.length ?? 0);
1212
+ }
1213
+ if (newParent) {
1214
+ const updatedChildren = this.getNodeChildren(newParent);
1215
+ this.setNodeChildrenCount(newParent, updatedChildren?.length ?? 0);
1216
+ this.setNodeExpanded(newParent, true); // Auto-expand new parent
1217
+ }
1218
+ // Emit drop events
1219
+ this.emitDropEvents(movedNode, currentParent, newParent, currentIndex, newIndex, false);
1220
+ this.refreshNodes();
1221
+ return true;
1222
+ }
1223
+ /**
1224
+ * Clone a node (creates a deep copy)
1225
+ * @param nodeId - The ID of the node to clone
1226
+ * @returns The cloned node, or null if node not found
1227
+ */
1228
+ cloneNode(nodeId) {
1229
+ const node = this.findNode(nodeId);
1230
+ if (!node) {
1231
+ return null;
1232
+ }
1233
+ return this.treeService.cloneNode(node, this.idField(), this.titleField(), this.tooltipField(), this.iconField(), this.expandedField(), this.selectedField(), this.indeterminateField(), this.disabledField(), this.hiddenField(), this.childrenCountField(), this.dataField(), this.childrenField());
1234
+ }
1235
+ /**
1236
+ * Focus a specific node by ID
1237
+ * @param nodeId - The ID of the node to focus
1238
+ * @returns true if node was found and focused, false otherwise
1239
+ */
1240
+ focusNode(nodeId) {
1241
+ const node = this.findNode(nodeId);
1242
+ if (!node || this.getNodeHidden(node) === true || this.getNodeDisabled(node)) {
1243
+ return false;
1244
+ }
1245
+ this.focusNodeById(nodeId);
1246
+ return true;
1247
+ }
1248
+ /**
1249
+ * Get all expanded nodes
1250
+ * @returns Array of expanded nodes
1251
+ */
1252
+ getExpandedNodes() {
1253
+ const expanded = [];
1254
+ const traverse = (nodes) => {
1255
+ for (const node of nodes) {
1256
+ if (this.getNodeExpanded(node)) {
1257
+ expanded.push(node);
1258
+ }
1259
+ const children = this.getNodeChildren(node);
1260
+ if (children) {
1261
+ traverse(children);
1262
+ }
1263
+ }
1264
+ };
1265
+ traverse(this.nodes());
1266
+ return expanded;
1267
+ }
1268
+ /**
1269
+ * Get all collapsed nodes that have children
1270
+ * @returns Array of collapsed nodes with children
1271
+ */
1272
+ getCollapsedNodes() {
1273
+ const collapsed = [];
1274
+ const traverse = (nodes) => {
1275
+ for (const node of nodes) {
1276
+ const children = this.getNodeChildren(node);
1277
+ const childrenCount = this.getNodeChildrenCount(node);
1278
+ if (!this.getNodeExpanded(node) && (children?.length || childrenCount)) {
1279
+ collapsed.push(node);
1280
+ }
1281
+ if (children) {
1282
+ traverse(children);
1283
+ }
1284
+ }
1285
+ };
1286
+ traverse(this.nodes());
1287
+ return collapsed;
1288
+ }
1289
+ /**
1290
+ * Check if a node is expanded
1291
+ * @param nodeId - The ID of the node
1292
+ * @returns true if node is expanded, false otherwise
1293
+ */
1294
+ isNodeExpanded(nodeId) {
1295
+ const node = this.findNode(nodeId);
1296
+ return node ? this.getNodeExpanded(node) : false;
1297
+ }
1298
+ /**
1299
+ * Check if a node is selected
1300
+ * @param nodeId - The ID of the node
1301
+ * @returns true if node is selected, false otherwise
1302
+ */
1303
+ isNodeSelected(nodeId) {
1304
+ const node = this.findNode(nodeId);
1305
+ return node ? this.getNodeSelected(node) : false;
1306
+ }
1307
+ /**
1308
+ * Check if a node has children
1309
+ * @param nodeId - The ID of the node
1310
+ * @returns true if node has children, false otherwise
1311
+ */
1312
+ hasChildren(nodeId) {
1313
+ const node = this.findNode(nodeId);
1314
+ return this.treeService.hasChildren(node ?? {}, this.childrenField());
1315
+ }
1316
+ /**
1317
+ * Get template context for a node
1318
+ */
1319
+ getTemplateContext(node, level = 0) {
1320
+ const children = this.getNodeChildren(node);
1321
+ const childrenCount = this.getNodeChildrenCount(node);
1322
+ return {
1323
+ $implicit: node,
1324
+ node,
1325
+ level,
1326
+ expanded: this.getNodeExpanded(node),
1327
+ childrenCount: childrenCount ?? children?.length ?? 0,
1328
+ loading: this.getNodeLoading(node),
1329
+ };
1330
+ }
1331
+ /**
1332
+ * Calculate padding-inline for a node based on its level
1333
+ */
1334
+ getNodePaddingInline(level) {
1335
+ const indent = this.indentSize();
1336
+ const currentLook = this.look();
1337
+ const multiplier = currentLook === 'with-line' ? 1 / 3 : 1;
1338
+ return level * indent * multiplier;
1339
+ }
1340
+ /**
1341
+ * Check if node should show expand toggle
1342
+ */
1343
+ shouldShowExpandToggle(node) {
1344
+ return (this.treeService.hasChildren(node, this.childrenField()) ||
1345
+ this.treeService.canLazyLoad(node, this.isLazyDataSource(), this.childrenCountField(), this.childrenField()));
1346
+ }
1347
+ /**
1348
+ * Check if checkboxes should be shown (only for multiple mode)
1349
+ */
1350
+ shouldShowCheckbox() {
1351
+ return this.selectMode() === 'multiple' && this.showCheckbox();
1352
+ }
1353
+ /**
1354
+ * Check if a node is a leaf (has no children)
1355
+ * A node is a leaf if it has no loaded children AND no childrenCount (or childrenCount is 0)
1356
+ */
1357
+ isLeafNode(node) {
1358
+ const hasChildren = this.treeService.hasChildren(node, this.childrenField());
1359
+ const childrenCount = this.getNodeChildrenCount(node);
1360
+ const hasChildrenCount = childrenCount && childrenCount > 0;
1361
+ const canLazyLoad = this.treeService.canLazyLoad(node, this.isLazyDataSource(), this.childrenCountField(), this.childrenField());
1362
+ // A node is a leaf if:
1363
+ // 1. It has no loaded children
1364
+ // 2. AND it has no childrenCount (or childrenCount is 0)
1365
+ // 3. AND it cannot be lazy loaded
1366
+ return !hasChildren && !hasChildrenCount && !canLazyLoad;
1367
+ }
1368
+ /**
1369
+ * Check if a node can be selected (considering selectMode and isLeafOnlyMode)
1370
+ */
1371
+ canSelectNode(node) {
1372
+ if (this.selectMode() === 'none') {
1373
+ return false;
1374
+ }
1375
+ if (this.isLeafOnlyMode()) {
1376
+ return this.isLeafNode(node);
1377
+ }
1378
+ return true;
1379
+ }
1380
+ /**
1381
+ * Check if checkbox should be shown for a specific node
1382
+ */
1383
+ shouldShowCheckboxForNode(node) {
1384
+ if (!this.shouldShowCheckbox()) {
1385
+ return false;
1386
+ }
1387
+ if (this.isLeafOnlyMode()) {
1388
+ return this.isLeafNode(node);
1389
+ }
1390
+ return true;
1391
+ }
1392
+ /**
1393
+ * Generate unique list ID for each node
1394
+ */
1395
+ getListId(node) {
1396
+ return this.treeService.getListId(node, this.idField());
1397
+ }
1398
+ /**
1399
+ * Check if a node is currently focused
1400
+ */
1401
+ isNodeFocused(nodeId) {
1402
+ return this.focusedNodeId() === nodeId;
1403
+ }
1404
+ /**
1405
+ * Get ARIA level for a node
1406
+ */
1407
+ getNodeAriaLevel(level) {
1408
+ return level + 1;
1409
+ }
1410
+ /**
1411
+ * Get ARIA expanded state for a node
1412
+ */
1413
+ getNodeAriaExpanded(node) {
1414
+ if (!this.shouldShowExpandToggle(node)) {
1415
+ return null;
1416
+ }
1417
+ return this.getNodeExpanded(node) ? 'true' : 'false';
1418
+ }
1419
+ /**
1420
+ * Get ARIA selected state for a node
1421
+ */
1422
+ getNodeAriaSelected(node) {
1423
+ if (this.selectMode() === 'none') {
1424
+ return null;
1425
+ }
1426
+ const selected = this.getNodeSelected(node);
1427
+ if (this.selectMode() === 'single') {
1428
+ return selected ? 'true' : 'false';
53
1429
  }
54
- this.treeView.onCollapsedChanged.emit({ component: this, data: this.item(), nativeElement: this.nativeElement });
1430
+ if (this.selectMode() === 'multiple') {
1431
+ return selected ? 'true' : 'false';
1432
+ }
1433
+ return null;
1434
+ }
1435
+ /**
1436
+ * Emit selection change event with all selected nodes
1437
+ */
1438
+ emitSelectionChange() {
1439
+ const selectedNodes = this.getSelectedNodes();
1440
+ this.onSelectionChange.emit({
1441
+ component: this,
1442
+ selectedNodes,
1443
+ });
55
1444
  }
56
- handleTextClick() {
57
- if (this.item()[this.treeView.disableField()]) {
1445
+ // ==================== Event Handlers ====================
1446
+ /**
1447
+ * Handle node click - for single selection mode or multiple mode with checkOnClick enabled
1448
+ */
1449
+ onNodeClick(node, event) {
1450
+ if (this.getNodeDisabled(node))
58
1451
  return;
1452
+ if (this.selectMode() === 'none')
1453
+ return;
1454
+ if (!this.canSelectNode(node))
1455
+ return;
1456
+ const mode = this.selectMode();
1457
+ const shouldCheckOnClick = this.checkOnClick();
1458
+ if (mode === 'single') {
1459
+ this.handleSingleSelection(node, event);
59
1460
  }
60
- if (this.treeView.focusNodeEnabled()) {
61
- this.treeView.handleUnActiveNode(this.treeView.itemsSignal());
62
- this.item()[this.treeView.activeField()] = true;
1461
+ else if (mode === 'multiple' && shouldCheckOnClick) {
1462
+ this.handleMultipleSelection(node, event);
63
1463
  }
64
- this.treeView.onNodeClick.emit({ component: this, data: this.item(), nativeElement: this.nativeElement });
65
1464
  }
66
- handleTextDbClick() {
67
- if (this.item()[this.treeView.disableField()] || this.treeView.expandOn() === 'click') {
1465
+ /**
1466
+ * Toggle node expansion state with lazy loading support
1467
+ */
1468
+ async toggleNode(node, event) {
1469
+ if (this.getNodeDisabled(node))
68
1470
  return;
1471
+ if (this.isEvent(event) && typeof event.stopPropagation === 'function') {
1472
+ event.stopPropagation();
69
1473
  }
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);
1474
+ const hasChildren = this.treeService.hasChildren(node, this.childrenField());
1475
+ const canLazyLoad = this.treeService.canLazyLoad(node, this.isLazyDataSource(), this.childrenCountField(), this.childrenField());
1476
+ if (hasChildren || canLazyLoad) {
1477
+ const willExpand = !this.getNodeExpanded(node);
1478
+ if (willExpand && canLazyLoad) {
1479
+ await this.loadNodeChildren(node);
75
1480
  }
1481
+ this.setNodeExpanded(node, willExpand);
1482
+ this.refreshNodes();
1483
+ this.onNodeToggle.emit({ component: this, node, nativeEvent: event });
76
1484
  }
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 });
79
1485
  }
80
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXTreeViewItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
81
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", 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.12", 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();
1486
+ /**
1487
+ * Toggle node selection state with indeterminate support (for multiple mode)
1488
+ */
1489
+ toggleSelection(node, event) {
1490
+ if (!event.isUserInteraction)
1491
+ return;
1492
+ if (this.selectMode() === 'none')
1493
+ return;
1494
+ if (!this.canSelectNode(node))
1495
+ return;
1496
+ const mode = this.selectMode();
1497
+ if (mode !== 'multiple')
1498
+ return;
1499
+ const newValue = event.value === null ? true : event.value;
1500
+ this.setNodeSelected(node, newValue);
1501
+ this.setNodeIndeterminate(node, false);
1502
+ const children = this.getNodeChildren(node);
1503
+ if (this.cascadesToChildren() && children && !this.isLeafOnlyMode()) {
1504
+ this.treeService.selectAllChildren(children, newValue, this.selectedField(), this.indeterminateField(), this.childrenField());
1505
+ }
1506
+ if (this.hasIntermediateState() && !this.isLeafOnlyMode()) {
1507
+ this.treeService.updateParentStates(this.nodes(), node, this.hasIntermediateState(), this.idField(), this.childrenField(), this.selectedField(), this.indeterminateField());
1508
+ }
1509
+ this.refreshNodes();
1510
+ this.onNodeSelect.emit({
1511
+ component: this,
1512
+ node,
1513
+ isUserInteraction: event.isUserInteraction,
1514
+ });
1515
+ this.emitSelectionChange();
1516
+ }
1517
+ /**
1518
+ * Handle drop events for tree nodes
1519
+ */
1520
+ onDrop(event, parentNode) {
1521
+ const targetArray = parentNode ? (this.getNodeChildren(parentNode) ?? []) : this.nodes();
1522
+ const isReordering = event.previousContainer === event.container;
1523
+ if (isReordering) {
1524
+ this.handleReorder(event, targetArray, parentNode);
1525
+ }
1526
+ else {
1527
+ this.handleMove(event, targetArray, parentNode);
1528
+ }
1529
+ this.refreshNodes();
1530
+ }
1531
+ /**
1532
+ * Handle drop events when dropping directly onto a node (to make it a child)
1533
+ */
1534
+ onDropOntoNode(event, targetNode) {
1535
+ if (!this.canMoveToParent())
1536
+ return;
1537
+ const sourceListId = event.previousContainer.element.id;
1538
+ const sourceArray = this.getArrayByListId(sourceListId);
1539
+ if (!sourceArray)
1540
+ return;
1541
+ const movedNode = sourceArray[event.previousIndex];
1542
+ if (!this.treeService.isValidDropTarget(movedNode, targetNode, this.idField(), this.childrenField()))
1543
+ return;
1544
+ if (!this.emitBeforeDropEvent(movedNode, sourceListId, targetNode, event.previousIndex, 0))
1545
+ return;
1546
+ let targetChildren = this.getNodeChildren(targetNode);
1547
+ if (!targetChildren) {
1548
+ targetChildren = [];
1549
+ this.setNodeChildren(targetNode, targetChildren);
1550
+ }
1551
+ sourceArray.splice(event.previousIndex, 1);
1552
+ targetChildren.unshift(movedNode);
1553
+ this.setNodeExpanded(targetNode, true);
1554
+ this.emitDropEvents(movedNode, this.findParentByListId(sourceListId), targetNode, event.previousIndex, 0, false);
1555
+ this.refreshNodes();
1556
+ }
1557
+ /**
1558
+ * Handle node focus event
1559
+ */
1560
+ onNodeFocus(nodeId) {
1561
+ this.focusedNodeId.set(nodeId);
1562
+ }
1563
+ /**
1564
+ * Handle tree container focus - focus first node if none is focused
1565
+ */
1566
+ onTreeFocus(event) {
1567
+ if (event.target === event.currentTarget) {
1568
+ const flatList = this.treeService.buildFlatNodeList(this.nodes(), this.hiddenField(), this.disabledField(), this.expandedField(), this.childrenField());
1569
+ if (flatList.length > 0) {
1570
+ const focusedId = this.focusedNodeId();
1571
+ if (focusedId) {
1572
+ // Check if the focused node still exists and is not hidden
1573
+ const focusedNode = this.treeService.findNodeById(this.nodes(), focusedId, this.idField());
1574
+ if (focusedNode && this.getNodeHidden(focusedNode) !== true) {
1575
+ this.focusNodeById(focusedId);
1576
+ }
1577
+ else {
1578
+ // Focused node no longer exists, focus first node
1579
+ this.focusNodeById(this.getNodeId(flatList[0].node));
1580
+ }
129
1581
  }
130
1582
  else {
131
- this.itemsSignal.set(result);
132
- this.itemsPromise = null;
1583
+ // No node is focused, focus first node
1584
+ this.focusNodeById(this.getNodeId(flatList[0].node));
133
1585
  }
134
1586
  }
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" }] : []));
142
- }
143
- /** @ignore */
144
- get __hostClass() {
145
- return [`ax-look-${this.look()}`];
1587
+ }
146
1588
  }
147
- get resolvedItems() {
148
- return this.itemsSignal();
1589
+ /**
1590
+ * Handle tree container blur
1591
+ */
1592
+ onTreeBlur(event) {
1593
+ if (event.relatedTarget && !event.currentTarget.contains(event.relatedTarget)) {
1594
+ this.focusedNodeId.set(null);
1595
+ }
149
1596
  }
150
- #effect;
151
- handleNodeSelectionClick(event, item) {
152
- if (item[this.disableField()] || this.isNodeLoading(item[this.valueField()])) {
1597
+ /**
1598
+ * Handle keyboard navigation
1599
+ */
1600
+ handleKeyDown(event) {
1601
+ const flatList = this.treeService.buildFlatNodeList(this.nodes(), this.hiddenField(), this.disabledField(), this.expandedField(), this.childrenField());
1602
+ if (flatList.length === 0)
153
1603
  return;
1604
+ const currentFocused = this.getFocusedNode();
1605
+ let currentIndex = currentFocused
1606
+ ? flatList.findIndex((item) => this.getNodeId(item.node) === this.getNodeId(currentFocused))
1607
+ : -1;
1608
+ if (currentIndex === -1 && event.target === event.currentTarget) {
1609
+ currentIndex = 0;
154
1610
  }
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
- }
1611
+ const navigationResult = this.handleNavigationKey(event, flatList, currentIndex, currentFocused);
1612
+ if (navigationResult.handled) {
1613
+ if (navigationResult.shouldPreventDefault) {
1614
+ event.preventDefault();
1615
+ event.stopPropagation();
1616
+ }
1617
+ if (navigationResult.targetIndex !== null &&
1618
+ navigationResult.targetIndex >= 0 &&
1619
+ navigationResult.targetIndex < flatList.length) {
1620
+ this.focusNodeById(this.getNodeId(flatList[navigationResult.targetIndex].node));
183
1621
  }
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
1622
  }
196
1623
  }
1624
+ // ==================== Private Methods ====================
197
1625
  /**
198
- *
199
- * auto expand
200
- *
1626
+ * Load root items when datasource is a function
201
1627
  */
202
- toggleExpand(item) {
203
- if (!item[this.expandedField()]) {
204
- item[this.expandedField()] = true;
1628
+ async loadRootItems(loadFn) {
1629
+ try {
1630
+ const result = loadFn();
1631
+ const rootNodes = result instanceof Promise ? await result : result;
1632
+ this.nodes.set(rootNodes);
1633
+ }
1634
+ catch (error) {
1635
+ this.handleError('Failed to load root items', error);
1636
+ this.nodes.set([]);
205
1637
  }
206
1638
  }
207
1639
  /**
208
- *
209
- * expand and change value parent change
210
- *
1640
+ * Load children for a node using lazy loading
211
1641
  */
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);
1642
+ async loadNodeChildren(node) {
1643
+ const nodeId = this.getNodeId(node);
1644
+ if (!this.isLazyDataSource() || this.loadingNodes().has(nodeId))
1645
+ return;
1646
+ if (this.treeService.hasChildren(node, this.childrenField())) {
1647
+ const childrenCount = this.getNodeChildrenCount(node);
1648
+ if (!childrenCount || childrenCount === 0) {
1649
+ return;
1650
+ }
216
1651
  }
217
- this.toggleExpand(item);
218
- if (item[this.childrenField()]?.length) {
219
- this.applySelectionToChildren(item, selected, item[this.valueField()]);
1652
+ const ds = this.datasource();
1653
+ if (typeof ds !== 'function')
1654
+ return;
1655
+ try {
1656
+ this.loadingNodes.update((set) => new Set(set).add(nodeId));
1657
+ this.refreshNodes();
1658
+ const result = ds(nodeId);
1659
+ const children = result instanceof Promise ? await result : result;
1660
+ this.setNodeChildren(node, children);
1661
+ this.setNodeChildrenCount(node, children.length);
1662
+ }
1663
+ catch (error) {
1664
+ this.handleError('Failed to load children', error);
1665
+ this.setNodeChildrenCount(node, 0);
1666
+ }
1667
+ finally {
1668
+ this.loadingNodes.update((set) => {
1669
+ const newSet = new Set(set);
1670
+ newSet.delete(nodeId);
1671
+ return newSet;
1672
+ });
1673
+ this.refreshNodes();
220
1674
  }
221
- }
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);
231
- }
232
- child[this.parentField()] = parentId;
233
- child[this.selectedField()] = isSelected;
234
- if (child[this.childrenField()]?.length) {
235
- this.applySelectionToChildren(child, isSelected, child[this.valueField()]);
236
- }
237
- });
238
1675
  }
239
1676
  /**
240
- *
241
- * indeterminate logic
242
- *
1677
+ * Internal method to refresh nodes signal and sync back to datasource if it's an array
1678
+ * Creates new array references for all nested children to ensure reactivity
243
1679
  */
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;
253
- }
254
- else if (!allSelected) {
255
- parent[this.indeterminateField()] = true;
256
- parent[this.selectedField()] = null;
257
- }
258
- else if (allSelected) {
259
- parent[this.selectedField()] = true;
260
- parent[this.indeterminateField()] = false;
261
- }
262
- else {
263
- parent[this.indeterminateField()] = false;
264
- parent[this.selectedField()] = true;
265
- }
266
- parent = this.findParent(parent, this.itemsSignal());
1680
+ refreshNodes() {
1681
+ const currentNodes = this.nodes();
1682
+ // Create new array references for all nested children to ensure reactivity
1683
+ // This ensures Angular's change detection picks up changes even with callback datasource
1684
+ this.ensureNewArrayReferences(currentNodes);
1685
+ this.nodes.set([...currentNodes]);
1686
+ if (!this.isLazyDataSource() && !this.isUpdatingFromDatasource) {
1687
+ this.isUpdatingFromDatasource = true;
1688
+ this.datasource.set([...currentNodes]);
1689
+ setTimeout(() => {
1690
+ this.isUpdatingFromDatasource = false;
1691
+ }, 0);
267
1692
  }
268
1693
  }
269
- findParent(item, nodes) {
1694
+ /**
1695
+ * Recursively ensure all children arrays have new references to trigger change detection
1696
+ * Mutates the tree structure by replacing children arrays with new array references
1697
+ */
1698
+ ensureNewArrayReferences(nodes) {
270
1699
  for (const node of nodes) {
271
- if (node[this.childrenField()]?.includes(item)) {
272
- return node;
273
- }
274
- else if (node[this.childrenField()]) {
275
- const parent = this.findParent(item, node[this.childrenField()]);
276
- if (parent)
277
- return parent;
1700
+ const children = this.getNodeChildren(node);
1701
+ if (children && children.length > 0) {
1702
+ // Create new array reference for children
1703
+ this.setNodeChildren(node, [...children]);
1704
+ // Recursively process nested children
1705
+ this.ensureNewArrayReferences(children);
278
1706
  }
279
1707
  }
280
- return null;
281
1708
  }
282
1709
  /**
283
- *
284
- * find node selected true for emit Selections
285
- *
1710
+ * Handle single selection mode
286
1711
  */
287
- findSelectedNodes(nodes) {
288
- let selectedNodes = [];
289
- nodes.forEach((node) => {
290
- if (node[this.selectedField()]) {
291
- selectedNodes.push(node);
292
- }
293
- if (node[this.childrenField()]) {
294
- selectedNodes = selectedNodes.concat(this.findSelectedNodes(node[this.childrenField()]));
295
- }
1712
+ handleSingleSelection(node, event) {
1713
+ this.treeService.deselectAllNodes(this.nodes(), this.selectedField(), this.indeterminateField(), this.childrenField());
1714
+ this.setNodeSelected(node, true);
1715
+ this.setNodeIndeterminate(node, false);
1716
+ this.refreshNodes();
1717
+ this.onNodeSelect.emit({
1718
+ component: this,
1719
+ node,
1720
+ nativeEvent: event,
1721
+ isUserInteraction: true,
296
1722
  });
297
- return selectedNodes;
1723
+ this.emitSelectionChange();
298
1724
  }
299
1725
  /**
300
- *
301
- * find for emit Selections single mode
302
- *
1726
+ * Handle multiple selection mode with checkOnClick
303
1727
  */
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
- }
1728
+ handleMultipleSelection(node, event) {
1729
+ const newValue = !this.getNodeSelected(node);
1730
+ this.setNodeSelected(node, newValue);
1731
+ this.setNodeIndeterminate(node, false);
1732
+ const children = this.getNodeChildren(node);
1733
+ if (this.cascadesToChildren() && children && !this.isLeafOnlyMode()) {
1734
+ this.treeService.selectAllChildren(children, newValue, this.selectedField(), this.indeterminateField(), this.childrenField());
1735
+ }
1736
+ if (this.hasIntermediateState() && !this.isLeafOnlyMode()) {
1737
+ this.treeService.updateParentStates(this.nodes(), node, this.hasIntermediateState(), this.idField(), this.childrenField(), this.selectedField(), this.indeterminateField());
1738
+ }
1739
+ this.refreshNodes();
1740
+ this.onNodeSelect.emit({
1741
+ component: this,
1742
+ node,
1743
+ nativeEvent: event,
1744
+ isUserInteraction: true,
310
1745
  });
1746
+ this.emitSelectionChange();
311
1747
  }
312
1748
  /**
313
- *
314
- * lazy load logic
315
- *
1749
+ * Get array reference by drop list ID
316
1750
  */
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
- }
331
- }
332
- })
333
- .finally(() => {
334
- this.setNodeLoading(selectedNode?.[this.valueField()], false);
335
- });
1751
+ getArrayByListId(listId) {
1752
+ return this.treeService.getArrayByListId(this.nodes(), listId, this.idField(), this.childrenField());
336
1753
  }
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));
343
- }
344
- element[this.childrenField()] = _children;
345
- }
346
- else {
347
- if (element?.[this.childrenField()])
348
- this.findNode(parentId, _children, element[this.childrenField()]);
349
- }
350
- });
1754
+ /**
1755
+ * Find parent node by list ID
1756
+ */
1757
+ findParentByListId(listId) {
1758
+ return this.treeService.findParentByListId(this.nodes(), listId, this.idField());
1759
+ }
1760
+ /**
1761
+ * Check if move operation is allowed based on dragOperationType
1762
+ */
1763
+ canMoveToParent() {
1764
+ return this.dragOperationType() !== 'order-only';
1765
+ }
1766
+ /**
1767
+ * Check if reorder operation is allowed based on dragOperationType
1768
+ */
1769
+ canReorder() {
1770
+ return this.dragOperationType() !== 'move';
1771
+ }
1772
+ /**
1773
+ * Handle reordering within the same list */
1774
+ handleReorder(event, targetArray, parentNode) {
1775
+ if (!this.canReorder())
1776
+ return;
1777
+ const movedNode = targetArray[event.previousIndex];
1778
+ moveItemInArray(targetArray, event.previousIndex, event.currentIndex);
1779
+ this.emitDropEvents(movedNode, parentNode, parentNode, event.previousIndex, event.currentIndex, true);
1780
+ }
1781
+ /**
1782
+ * Handle moving between different lists
1783
+ */
1784
+ handleMove(event, targetArray, parentNode) {
1785
+ if (!this.canMoveToParent())
1786
+ return;
1787
+ const sourceListId = event.previousContainer.element.id;
1788
+ const sourceArray = this.getArrayByListId(sourceListId);
1789
+ if (!sourceArray)
1790
+ return;
1791
+ const movedNode = sourceArray[event.previousIndex];
1792
+ if (parentNode && !this.treeService.isValidDropTarget(movedNode, parentNode))
1793
+ return;
1794
+ if (!this.emitBeforeDropEvent(movedNode, sourceListId, parentNode, event.previousIndex, event.currentIndex)) {
1795
+ return;
351
1796
  }
1797
+ transferArrayItem(sourceArray, targetArray, event.previousIndex, event.currentIndex);
1798
+ this.emitDropEvents(movedNode, this.findParentByListId(sourceListId), parentNode, event.previousIndex, event.currentIndex, false);
352
1799
  }
353
1800
  /**
354
- *
355
- * emit when arrow click
356
- *
1801
+ * Emit beforeDrop event and return whether to continue
357
1802
  */
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);
1803
+ emitBeforeDropEvent(movedNode, sourceListId, currentParent, previousIndex, currentIndex) {
1804
+ const beforeDropEvent = {
1805
+ component: this,
1806
+ movedNode,
1807
+ previousParent: this.findParentByListId(sourceListId),
1808
+ currentParent,
1809
+ previousIndex,
1810
+ currentIndex,
1811
+ canceled: false,
1812
+ };
1813
+ this.onBeforeDrop.emit(beforeDropEvent);
1814
+ return !beforeDropEvent.canceled;
1815
+ }
1816
+ /**
1817
+ * Emit drop events based on operation type
1818
+ */
1819
+ emitDropEvents(node, previousParent, currentParent, previousIndex, currentIndex, isReorder) {
1820
+ const dropEvent = {
1821
+ component: this,
1822
+ node,
1823
+ previousParent,
1824
+ currentParent,
1825
+ previousIndex,
1826
+ currentIndex,
1827
+ };
1828
+ if (isReorder) {
1829
+ this.onOrderChange.emit(dropEvent);
1830
+ }
1831
+ else {
1832
+ this.onMoveChange.emit(dropEvent);
363
1833
  }
364
- this.onCollapsedChanged.emit({ component: this, data: node.data, nativeElement: this.nativeElement });
1834
+ this.onItemsChange.emit(dropEvent);
365
1835
  }
366
- handleUnActiveNode(unActiveSource) {
367
- unActiveSource.forEach((child) => {
368
- child[this.activeField()] = false;
369
- if (child?.[this.childrenField()]?.length) {
370
- this.handleUnActiveNode(child[this.childrenField()]);
1836
+ /**
1837
+ * Get the currently focused node
1838
+ */
1839
+ getFocusedNode() {
1840
+ const focusedId = this.focusedNodeId();
1841
+ if (!focusedId)
1842
+ return null;
1843
+ return this.treeService.findNodeById(this.nodes(), focusedId, this.idField());
1844
+ }
1845
+ /**
1846
+ * Set focus to a node by ID
1847
+ */
1848
+ focusNodeById(nodeId) {
1849
+ this.focusedNodeId.set(nodeId);
1850
+ setTimeout(() => {
1851
+ const element = document.querySelector(`[data-tree-node-id="${nodeId}"]`);
1852
+ if (element) {
1853
+ element.focus();
1854
+ element.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
371
1855
  }
372
- });
1856
+ }, 0);
373
1857
  }
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;
1858
+ /**
1859
+ * Handle keyboard navigation keys
1860
+ */
1861
+ handleNavigationKey(event, flatList, currentIndex, currentFocused) {
1862
+ let targetIndex = currentIndex;
1863
+ let shouldPreventDefault = true;
1864
+ let handled = true;
1865
+ switch (event.key) {
1866
+ case 'ArrowUp':
1867
+ if (currentIndex > 0) {
1868
+ targetIndex = currentIndex - 1;
1869
+ }
1870
+ else {
1871
+ shouldPreventDefault = false;
1872
+ }
1873
+ break;
1874
+ case 'ArrowDown':
1875
+ if (currentIndex < flatList.length - 1) {
1876
+ targetIndex = currentIndex + 1;
1877
+ }
1878
+ else if (currentIndex === -1) {
1879
+ targetIndex = 0;
1880
+ }
1881
+ else {
1882
+ shouldPreventDefault = false;
1883
+ }
1884
+ break;
1885
+ case 'ArrowLeft':
1886
+ if (currentFocused) {
1887
+ if (this.getNodeExpanded(currentFocused) && this.shouldShowExpandToggle(currentFocused)) {
1888
+ this.toggleNode(currentFocused, event);
1889
+ return { handled: true, shouldPreventDefault: true, targetIndex: null };
1890
+ }
1891
+ else {
1892
+ const currentItem = flatList[currentIndex];
1893
+ if (currentItem?.parent) {
1894
+ targetIndex = flatList.findIndex((item) => this.getNodeId(item.node) === this.getNodeId(currentItem.parent));
1895
+ }
1896
+ else {
1897
+ shouldPreventDefault = false;
1898
+ }
1899
+ }
1900
+ }
1901
+ else {
1902
+ shouldPreventDefault = false;
1903
+ }
387
1904
  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 });
1905
+ case 'ArrowRight':
1906
+ if (currentFocused) {
1907
+ if (!this.getNodeExpanded(currentFocused) && this.shouldShowExpandToggle(currentFocused)) {
1908
+ this.toggleNode(currentFocused, event);
1909
+ return { handled: true, shouldPreventDefault: true, targetIndex: null };
1910
+ }
1911
+ else if (this.getNodeExpanded(currentFocused) &&
1912
+ this.treeService.hasChildren(currentFocused, this.childrenField())) {
1913
+ const children = this.getNodeChildren(currentFocused);
1914
+ if (children && children.length > 0) {
1915
+ const firstChild = children[0];
1916
+ targetIndex = flatList.findIndex((item) => this.getNodeId(item.node) === this.getNodeId(firstChild));
1917
+ if (targetIndex === -1) {
1918
+ const updatedFlatList = this.treeService.buildFlatNodeList(this.nodes(), this.hiddenField(), this.disabledField(), this.expandedField(), this.childrenField());
1919
+ targetIndex = updatedFlatList.findIndex((item) => this.getNodeId(item.node) === this.getNodeId(firstChild));
1920
+ if (targetIndex >= 0 && targetIndex < updatedFlatList.length) {
1921
+ this.focusNodeById(this.getNodeId(updatedFlatList[targetIndex].node));
1922
+ return { handled: true, shouldPreventDefault: true, targetIndex: null };
1923
+ }
1924
+ }
1925
+ }
1926
+ else {
1927
+ shouldPreventDefault = false;
1928
+ }
1929
+ }
1930
+ else {
1931
+ shouldPreventDefault = false;
1932
+ }
1933
+ }
1934
+ else {
1935
+ shouldPreventDefault = false;
392
1936
  }
393
1937
  break;
394
- case 'visible':
395
- node[this.visibleField()] = value;
1938
+ case 'Home':
1939
+ targetIndex = 0;
1940
+ break;
1941
+ case 'End':
1942
+ targetIndex = flatList.length - 1;
1943
+ break;
1944
+ case ' ':
1945
+ case 'Space':
1946
+ if (currentFocused && this.selectMode() === 'multiple' && this.canSelectNode(currentFocused)) {
1947
+ event.preventDefault();
1948
+ this.handleSpaceKeySelection(currentFocused, event);
1949
+ return { handled: true, shouldPreventDefault: true, targetIndex: null };
1950
+ }
1951
+ shouldPreventDefault = false;
396
1952
  break;
397
- case 'disabled':
398
- node[this.disableField()] = value;
1953
+ case 'Enter':
1954
+ if (currentFocused && this.canSelectNode(currentFocused)) {
1955
+ event.preventDefault();
1956
+ this.handleEnterKeySelection(currentFocused, event);
1957
+ return { handled: true, shouldPreventDefault: true, targetIndex: null };
1958
+ }
1959
+ shouldPreventDefault = false;
399
1960
  break;
400
1961
  default:
1962
+ if ((event.ctrlKey || event.metaKey) && event.key === 'Enter') {
1963
+ if (currentFocused && this.selectMode() === 'multiple' && this.canSelectNode(currentFocused)) {
1964
+ event.preventDefault();
1965
+ this.handleCtrlEnterSelection(currentFocused, event);
1966
+ return { handled: true, shouldPreventDefault: true, targetIndex: null };
1967
+ }
1968
+ }
1969
+ handled = false;
1970
+ shouldPreventDefault = false;
401
1971
  break;
402
1972
  }
403
- /**
404
- *
405
- * for detect changes treeviewitem
406
- *
407
- */
408
- this.executorChanges.set(operation);
1973
+ return { handled, shouldPreventDefault, targetIndex };
409
1974
  }
410
- refresh() {
411
- if (this.itemsPromise) {
412
- this.fetchData();
1975
+ /**
1976
+ * Handle Space key selection
1977
+ */
1978
+ handleSpaceKeySelection(node, event) {
1979
+ if (!this.canSelectNode(node))
1980
+ return;
1981
+ const newValue = !this.getNodeSelected(node);
1982
+ this.setNodeSelected(node, newValue);
1983
+ this.setNodeIndeterminate(node, false);
1984
+ const children = this.getNodeChildren(node);
1985
+ if (this.cascadesToChildren() && children && !this.isLeafOnlyMode()) {
1986
+ this.treeService.selectAllChildren(children, newValue, this.selectedField(), this.indeterminateField(), this.childrenField());
413
1987
  }
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);
1988
+ if (this.hasIntermediateState() && !this.isLeafOnlyMode()) {
1989
+ this.treeService.updateParentStates(this.nodes(), node, this.hasIntermediateState(), this.idField(), this.childrenField(), this.selectedField(), this.indeterminateField());
420
1990
  }
421
- await Promise.all(nodesToExpand.map((node) => this.expandNodeAndAllChildren(node, value)));
1991
+ this.refreshNodes();
1992
+ this.onNodeSelect.emit({
1993
+ component: this,
1994
+ node,
1995
+ nativeEvent: event,
1996
+ isUserInteraction: true,
1997
+ });
1998
+ this.emitSelectionChange();
422
1999
  }
423
- findNodesByValueField(nodes, valueField) {
424
- const results = [];
425
- for (const node of nodes) {
426
- if (node[this.valueField()] === valueField) {
427
- results.push(node);
2000
+ /**
2001
+ * Handle Enter key selection
2002
+ */
2003
+ handleEnterKeySelection(node, event) {
2004
+ if (!this.canSelectNode(node))
2005
+ return;
2006
+ const mode = this.selectMode();
2007
+ this.treeService.deselectAllNodes(this.nodes(), this.selectedField(), this.indeterminateField(), this.childrenField());
2008
+ this.setNodeSelected(node, true);
2009
+ this.setNodeIndeterminate(node, false);
2010
+ if (mode === 'multiple') {
2011
+ const children = this.getNodeChildren(node);
2012
+ if (this.cascadesToChildren() && children && !this.isLeafOnlyMode()) {
2013
+ this.treeService.selectAllChildren(children, true, this.selectedField(), this.indeterminateField(), this.childrenField());
428
2014
  }
429
- if (node[this.childrenField()]?.length) {
430
- results.push(...this.findNodesByValueField(node[this.childrenField()], valueField));
2015
+ if (this.hasIntermediateState() && !this.isLeafOnlyMode()) {
2016
+ this.treeService.updateParentStates(this.nodes(), node, this.hasIntermediateState(), this.idField(), this.childrenField(), this.selectedField(), this.indeterminateField());
431
2017
  }
432
2018
  }
433
- return results;
2019
+ this.refreshNodes();
2020
+ this.onNodeSelect.emit({
2021
+ component: this,
2022
+ node,
2023
+ nativeEvent: event,
2024
+ isUserInteraction: true,
2025
+ });
2026
+ this.emitSelectionChange();
2027
+ }
2028
+ /**
2029
+ * Handle Ctrl/Cmd + Enter key selection
2030
+ */
2031
+ handleCtrlEnterSelection(node, event) {
2032
+ if (!this.canSelectNode(node))
2033
+ return;
2034
+ const newValue = !this.getNodeSelected(node);
2035
+ this.setNodeSelected(node, newValue);
2036
+ this.setNodeIndeterminate(node, false);
2037
+ const children = this.getNodeChildren(node);
2038
+ if (this.cascadesToChildren() && children && !this.isLeafOnlyMode()) {
2039
+ this.treeService.selectAllChildren(children, newValue, this.selectedField(), this.indeterminateField(), this.childrenField());
2040
+ }
2041
+ if (this.hasIntermediateState() && !this.isLeafOnlyMode()) {
2042
+ this.treeService.updateParentStates(this.nodes(), node, this.hasIntermediateState(), this.idField(), this.childrenField(), this.selectedField(), this.indeterminateField());
2043
+ }
2044
+ this.refreshNodes();
2045
+ this.onNodeSelect.emit({
2046
+ component: this,
2047
+ node,
2048
+ nativeEvent: event,
2049
+ isUserInteraction: true,
2050
+ });
2051
+ this.emitSelectionChange();
2052
+ }
2053
+ /**
2054
+ * Type guard to check if value is an Event
2055
+ */
2056
+ isEvent(value) {
2057
+ return value instanceof Event;
434
2058
  }
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);
2059
+ /**
2060
+ * Handle errors consistently
2061
+ */
2062
+ handleError(message, error) {
2063
+ if (error instanceof Error) {
2064
+ console.error(`${message}:`, error.message);
440
2065
  }
441
- if (node[this.childrenField()]?.length) {
442
- await Promise.all(node[this.childrenField()].map((child) => this.expandNodeAndAllChildren(child, value)));
2066
+ else {
2067
+ console.error(`${message}:`, error);
443
2068
  }
444
2069
  }
445
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXTreeViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
446
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", 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 }); }
2070
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2071
+ 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 }, selectionBehavior: { classPropertyName: "selectionBehavior", publicName: "selectionBehavior", 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 }, look: { classPropertyName: "look", publicName: "look", isSignal: true, isRequired: false, transformFunction: null }, nodeTemplate: { classPropertyName: "nodeTemplate", publicName: "nodeTemplate", isSignal: true, isRequired: false, transformFunction: null }, idField: { classPropertyName: "idField", publicName: "idField", isSignal: true, isRequired: false, transformFunction: null }, titleField: { classPropertyName: "titleField", publicName: "titleField", isSignal: true, isRequired: false, transformFunction: null }, tooltipField: { classPropertyName: "tooltipField", publicName: "tooltipField", isSignal: true, isRequired: false, transformFunction: null }, iconField: { classPropertyName: "iconField", publicName: "iconField", isSignal: true, isRequired: false, transformFunction: null }, expandedField: { classPropertyName: "expandedField", publicName: "expandedField", isSignal: true, isRequired: false, transformFunction: null }, selectedField: { classPropertyName: "selectedField", publicName: "selectedField", isSignal: true, isRequired: false, transformFunction: null }, indeterminateField: { classPropertyName: "indeterminateField", publicName: "indeterminateField", isSignal: true, isRequired: false, transformFunction: null }, disabledField: { classPropertyName: "disabledField", publicName: "disabledField", isSignal: true, isRequired: false, transformFunction: null }, hiddenField: { classPropertyName: "hiddenField", publicName: "hiddenField", isSignal: true, isRequired: false, transformFunction: null }, childrenField: { classPropertyName: "childrenField", publicName: "childrenField", isSignal: true, isRequired: false, transformFunction: null }, childrenCountField: { classPropertyName: "childrenCountField", publicName: "childrenCountField", isSignal: true, isRequired: false, transformFunction: null }, dataField: { classPropertyName: "dataField", publicName: "dataField", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { datasource: "datasourceChange", onBeforeDrop: "onBeforeDrop", onNodeToggle: "onNodeToggle", onNodeSelect: "onNodeSelect", onSelectionChange: "onSelectionChange", 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 role=\"group\"\n>\n @for (node of nodes(); track getNodeId(node)) {\n @if (getNodeHidden(node) !== true) {\n <div\n [axDrag]=\"dragMode() !== 'none'\"\n [dragDisabled]=\"getNodeDisabled(node)\"\n [dragData]=\"node\"\n class=\"ax-tree-view-node\"\n [class.ax-tree-view-node-selected]=\"getNodeSelected(node)\"\n [class.ax-tree-view-node-disabled]=\"getNodeDisabled(node)\"\n [class.ax-tree-view-node-loading]=\"getNodeLoading(node)\"\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]=\"getNodeDisabled(node) || (isLeafOnlyMode() && !isLeafNode(node)) ? 'true' : null\"\n >\n <div\n class=\"ax-tree-view-node-content\"\n [axDropList]=\"dragMode() !== 'none'\"\n [id]=\"'ax-tree-view-node-drop-' + getNodeId(node)\"\n [attr.data-node-id]=\"getNodeId(node)\"\n [attr.data-tree-node-id]=\"getNodeId(node)\"\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(getNodeId(node))\"\n [tabindex]=\"isNodeFocused(getNodeId(node)) ? 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]=\"getNodeExpanded(node)\"\n [disabled]=\"getNodeDisabled(node) || getNodeLoading(node)\"\n [style.visibility]=\"shouldShowExpandToggle(node) ? 'visible' : 'hidden'\"\n >\n @if (getNodeLoading(node)) {\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]=\"getNodeExpanded(node) ? directionExpandedIcon() : directionCollapsedIcon()\"\n class=\"ax-tree-view-toggle-icon\"\n ></i>\n </ax-icon>\n }\n </ax-button>\n @if (nodeTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"nodeTemplate()!\"\n [ngTemplateOutletContext]=\"getTemplateContext(node, 0)\"\n ></ng-container>\n } @else {\n @if (shouldShowCheckboxForNode(node)) {\n <ax-check-box\n class=\"ax-tree-view-checkbox\"\n [ngModel]=\"getNodeIndeterminate(node) ? null : getNodeSelected(node) || false\"\n [indeterminate]=\"getNodeIndeterminate(node) || false\"\n (onValueChanged)=\"toggleSelection(node, $event)\"\n ></ax-check-box>\n }\n @if (showIcons() && getNodeIcon(node)) {\n <i [class]=\"getNodeIcon(node)\" class=\"ax-tree-view-node-icon\"></i>\n }\n <span\n class=\"ax-tree-view-node-label\"\n [axTooltip]=\"getNodeTooltip(node) || ''\"\n [axTooltipDisabled]=\"!getNodeTooltip(node)\"\n [axTooltipPlacement]=\"'top-start'\"\n >\n {{ getNodeTitle(node) }}\n </span>\n @if (\n showChildrenBadge() &&\n (getNodeChildrenCount(node) || (getNodeChildren(node) && getNodeChildren(node)!.length > 0))\n ) {\n <span class=\"ax-tree-view-node-badge\">\n <ax-badge\n class=\"ax-tree-view-children-badge\"\n [text]=\"(getNodeChildrenCount(node) ?? getNodeChildren(node)?.length ?? 0).toString()\"\n ></ax-badge>\n </span>\n }\n }\n </div>\n </div>\n @if (getNodeExpanded(node) && getNodeChildren(node) && getNodeChildren(node)!.length > 0) {\n <div class=\"ax-tree-view-children\" role=\"group\">\n <ng-container\n [ngTemplateOutlet]=\"childrenList\"\n [ngTemplateOutletContext]=\"{ children: getNodeChildren(node), 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]=\"getNodeId(parent)\"\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 getNodeId(node)) {\n @if (getNodeHidden(node) !== true) {\n <div\n [axDrag]=\"dragMode() !== 'none'\"\n [dragDisabled]=\"getNodeDisabled(node)\"\n [dragData]=\"node\"\n class=\"ax-tree-view-node\"\n [class.ax-tree-view-node-selected]=\"getNodeSelected(node)\"\n [class.ax-tree-view-node-disabled]=\"getNodeDisabled(node)\"\n [class.ax-tree-view-node-loading]=\"getNodeLoading(node)\"\n [class.ax-tree-view-node-focused]=\"isNodeFocused(getNodeId(node))\"\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]=\"getNodeDisabled(node) ? 'true' : null\"\n >\n <div\n class=\"ax-tree-view-node-content\"\n [axDropList]=\"dragMode() !== 'none'\"\n [id]=\"'ax-tree-view-node-drop-' + getNodeId(node)\"\n [attr.data-node-id]=\"getNodeId(node)\"\n [attr.data-tree-node-id]=\"getNodeId(node)\"\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(getNodeId(node))\"\n (blur)=\"focusedNodeId.set(null)\"\n [tabindex]=\"isNodeFocused(getNodeId(node)) ? 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]=\"getNodeExpanded(node)\"\n [disabled]=\"getNodeDisabled(node) || getNodeLoading(node)\"\n [style.visibility]=\"shouldShowExpandToggle(node) ? 'visible' : 'hidden'\"\n >\n @if (getNodeLoading(node)) {\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]=\"getNodeExpanded(node) ? directionExpandedIcon() : directionCollapsedIcon()\"\n class=\"ax-tree-view-toggle-icon\"\n ></i>\n </ax-icon>\n }\n </ax-button>\n\n @if (nodeTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"nodeTemplate()!\"\n [ngTemplateOutletContext]=\"getTemplateContext(node, level)\"\n ></ng-container>\n } @else {\n @if (shouldShowCheckboxForNode(node)) {\n <ax-check-box\n class=\"ax-tree-view-checkbox\"\n [ngModel]=\"getNodeIndeterminate(node) ? null : getNodeSelected(node) || false\"\n [indeterminate]=\"getNodeIndeterminate(node) || false\"\n (onValueChanged)=\"toggleSelection(node, $event)\"\n ></ax-check-box>\n }\n @if (showIcons() && getNodeIcon(node)) {\n <i [class]=\"getNodeIcon(node)\" class=\"ax-tree-view-node-icon\"></i>\n }\n <span\n class=\"ax-tree-view-node-label\"\n [axTooltip]=\"getNodeTooltip(node) || ''\"\n [axTooltipDisabled]=\"!getNodeTooltip(node)\"\n [axTooltipPlacement]=\"'top-start'\"\n >\n {{ getNodeTitle(node) }}\n </span>\n @if (\n showChildrenBadge() &&\n (getNodeChildrenCount(node) || (getNodeChildren(node) && getNodeChildren(node)!.length > 0))\n ) {\n <span class=\"ax-tree-view-node-badge\">\n <ax-badge\n class=\"ax-tree-view-children-badge\"\n [text]=\"(getNodeChildrenCount(node) ?? getNodeChildren(node)?.length ?? 0).toString()\"\n ></ax-badge>\n </span>\n }\n }\n </div>\n </div>\n @if (getNodeExpanded(node) && getNodeChildren(node) && getNodeChildren(node)!.length > 0) {\n <div class=\"ax-tree-view-children\" role=\"group\">\n <ng-container\n [ngTemplateOutlet]=\"childrenList\"\n [ngTemplateOutletContext]=\"{ children: getNodeChildren(node), parent: node, level: level + 1 }\"\n ></ng-container>\n </div>\n }\n }\n }\n </div>\n</ng-template>\n", styles: [".ax-tree-view{display:block;width:100%;--ax-comp-tree-view-indent-size: 12px;--ax-comp-tree-view-node-hover-bg: rgba(var(--ax-sys-color-on-lightest-surface), .04);--ax-comp-tree-view-node-selected-bg: rgba(var(--ax-sys-color-primary-500), .12);--ax-comp-tree-view-node-border-radius: 6px;--ax-comp-tree-view-node-margin: .25rem;--ax-comp-tree-view-line-color: rgba(var(--ax-sys-color-on-lightest-surface), .15);--ax-comp-tree-view-drag-preview-opacity: .9;--ax-comp-tree-view-drag-placeholder-bg: rgba(var(--ax-sys-color-on-lightest-surface), .02);--ax-comp-tree-view-drop-active-bg: rgba(var(--ax-sys-color-primary-500), .08);--ax-comp-tree-view-drop-active-outline: rgba(var(--ax-sys-color-primary-500), .3);--ax-comp-tree-view-content-padding: 0;--ax-comp-tree-view-content-gap: .5rem;--ax-comp-tree-view-drop-list-min-height: 2rem;--ax-comp-tree-view-drag-handle-padding: .25rem;--ax-comp-tree-view-badge-padding: .25rem;--ax-comp-tree-view-expand-toggle-padding: .25rem;--ax-comp-tree-view-outline-offset: 2px;--ax-comp-tree-view-outline-offset-negative: -2px}.ax-tree-view-drop-list{min-height:var(--ax-comp-tree-view-drop-list-min-height)}.ax-tree-view-node{position:relative;margin:var(--ax-comp-tree-view-node-margin) 0;border-radius:var(--ax-comp-tree-view-node-border-radius);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)}.ax-tree-view-node.ax-dragging{opacity:var(--ax-comp-tree-view-drag-placeholder-opacity);cursor:grabbing!important}.ax-tree-view-node.ax-drag-placeholder{background:var(--ax-comp-tree-view-drag-placeholder-bg)}.ax-drag-preview{opacity:var(--ax-comp-tree-view-drag-preview-opacity)!important;box-shadow:0 4px 12px rgba(var(--ax-sys-color-on-lightest-surface),.2)!important;cursor:grabbing!important;border:2px dashed currentColor!important}.ax-tree-view-node-content.ax-drop-list-sorting-active{background:var(--ax-comp-tree-view-drop-active-bg);border-radius:var(--ax-comp-tree-view-node-border-radius);outline:2px dashed var(--ax-comp-tree-view-drop-active-outline);outline-offset:var(--ax-comp-tree-view-outline-offset-negative)}.ax-tree-view-node-content{display:flex;align-items:center;gap:var(--ax-comp-tree-view-content-gap);padding:var(--ax-comp-tree-view-content-padding);cursor:pointer;-webkit-user-select:none;user-select:none;outline:none;border-radius:var(--ax-comp-tree-view-node-border-radius)}.ax-tree-view-node-content:focus{outline:none}.ax-tree-view-node-content:focus-visible{outline:2px solid rgba(var(--ax-sys-color-primary-500),.8);outline-offset:var(--ax-comp-tree-view-outline-offset);border-radius:var(--ax-comp-tree-view-node-border-radius)}.ax-tree-view-drag-handle{cursor:grab;opacity:.6;padding:var(--ax-comp-tree-view-drag-handle-padding);padding-inline-start:calc(var(--ax-comp-tree-view-drag-handle-padding) * 2)}.ax-tree-view-drag-handle:hover{opacity:1}.ax-tree-view-drag-handle:active{cursor:grabbing}.ax-tree-view-expand-toggle{background:none;border:none;cursor:pointer;padding:var(--ax-comp-tree-view-expand-toggle-padding);min-width:1.5rem;height:1.5rem}.ax-tree-view-expand-toggle:not(.ax-tree-view-has-children){opacity:0;pointer-events:none}.ax-tree-view-toggle-icon{font-size:.75rem}.ax-tree-view-node-icon{font-size:1.125rem;flex-shrink:0}.ax-tree-view-node-label{flex:1;font-size:.875rem;line-height:1rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ax-tree-view-node-badge{padding:var(--ax-comp-tree-view-badge-padding);padding-inline-end:calc(var(--ax-comp-tree-view-badge-padding) * 1.5)}.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)}.ax-tree-view-card .ax-tree-view-node.ax-tree-view-node-selected{border:1px solid rgba(var(--ax-sys-color-border-surface),1)}.ax-tree-view-with-lines .ax-tree-view-children{position:relative;padding-inline-start:var(--ax-tree-view-indent-size, var(--ax-comp-tree-view-indent-size))}.ax-tree-view-with-lines .ax-tree-view-children:before{content:\"\";position:absolute;inset-inline-start:var(--ax-tree-view-line-offset, calc(var(--ax-comp-tree-view-indent-size) / 2));top:0;height:calc(100% - .875rem);width:1px;background:var(--ax-tree-view-line-color, var(--ax-comp-tree-view-line-color))}.ax-tree-view-with-lines .ax-tree-view-node{position:relative}.ax-tree-view-with-lines .ax-tree-view-node:before{content:\"\";position:absolute;inset-inline-start:calc(-1 * var(--ax-tree-view-line-offset, calc(var(--ax-comp-tree-view-indent-size) / 2)));top:60%;width:var(--ax-tree-view-line-offset, calc(var(--ax-comp-tree-view-indent-size) / 2));height:1px;background:var(--ax-tree-view-line-color, var(--ax-comp-tree-view-line-color))}.ax-tree-view-with-lines>.ax-tree-view-drop-list>.ax-tree-view-node:before,.ax-tree-view-with-lines>.ax-tree-view-node:before{display:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: AXDragDirective, selector: "[axDrag]", inputs: ["axDrag", "dragData", "dragDisabled", "dragTransition", "dragElementClone", "dropZoneGroup", "dragStartDelay", "dragResetOnDblClick", "dragLockAxis", "dragClonedTemplate", "dragCursor", "dragBoundary", "dragTransitionDuration"], outputs: ["dragPositionChanged"] }, { kind: "directive", type: AXDragHandleDirective, selector: "[axDragHandle]" }, { kind: "directive", type: AXDropListDirective, selector: "[axDropList]", inputs: ["axDropList", "sortingDisabled", "dropListGroup", "dropListOrientation"], outputs: ["dropListDropped"], exportAs: ["axDropList"] }, { kind: "directive", type: AXFocusTrapDirective, selector: "[axFocusTrap]" }, { kind: "component", type: AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "component", type: AXCheckBoxComponent, selector: "ax-check-box", inputs: ["disabled", "tabIndex", "readonly", "color", "value", "name", "id", "isLoading", "indeterminate"], outputs: ["onBlur", "onFocus", "valueChange", "onValueChanged"] }, { kind: "component", type: AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "component", type: AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "directive", type: AXTooltipDirective, selector: "[axTooltip]", inputs: ["axTooltipDisabled", "axTooltip", "axTooltipContext", "axTooltipPlacement", "axTooltipOffsetX", "axTooltipOffsetY", "axTooltipOpenAfter", "axTooltipCloseAfter"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
450
2072
  }
451
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXTreeViewComponent, decorators: [{
2073
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewComponent, decorators: [{
452
2074
  type: Component,
453
- args: [{ selector: 'ax-tree-view', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
2075
+ args: [{ selector: 'ax-tree-view', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, providers: [AXTreeViewService], imports: [
2076
+ CommonModule,
2077
+ FormsModule,
2078
+ AXDragDirective,
2079
+ AXDragHandleDirective,
2080
+ AXDropListDirective,
2081
+ AXFocusTrapDirective,
454
2082
  NgTemplateOutlet,
455
- AXTreeViewItemComponent,
2083
+ AXButtonComponent,
456
2084
  AXCheckBoxComponent,
457
- FormsModule,
458
- AXDecoratorGenericComponent,
2085
+ AXBadgeComponent,
459
2086
  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 }] }] } });
2087
+ AXTooltipDirective,
2088
+ ], host: {
2089
+ class: 'ax-tree-view',
2090
+ '[class.ax-tree-view-default]': "look() === 'default'",
2091
+ '[class.ax-tree-view-card]': "look() === 'card'",
2092
+ '[class.ax-tree-view-with-line]': "look() === 'with-line'",
2093
+ '[class.ax-tree-view-rtl]': 'isRtl',
2094
+ '[style.--ax-tree-view-indent-size]': "indentSize() + 'px'",
2095
+ '[style.--ax-tree-view-line-offset]': "(indentSize() / 2) + 'px'",
2096
+ role: 'tree',
2097
+ '[attr.aria-label]': '"Tree navigation"',
2098
+ '(keydown)': 'handleKeyDown($event)',
2099
+ '(focus)': 'onTreeFocus($event)',
2100
+ '(blur)': 'onTreeBlur($event)',
2101
+ tabindex: '0',
2102
+ }, 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 role=\"group\"\n>\n @for (node of nodes(); track getNodeId(node)) {\n @if (getNodeHidden(node) !== true) {\n <div\n [axDrag]=\"dragMode() !== 'none'\"\n [dragDisabled]=\"getNodeDisabled(node)\"\n [dragData]=\"node\"\n class=\"ax-tree-view-node\"\n [class.ax-tree-view-node-selected]=\"getNodeSelected(node)\"\n [class.ax-tree-view-node-disabled]=\"getNodeDisabled(node)\"\n [class.ax-tree-view-node-loading]=\"getNodeLoading(node)\"\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]=\"getNodeDisabled(node) || (isLeafOnlyMode() && !isLeafNode(node)) ? 'true' : null\"\n >\n <div\n class=\"ax-tree-view-node-content\"\n [axDropList]=\"dragMode() !== 'none'\"\n [id]=\"'ax-tree-view-node-drop-' + getNodeId(node)\"\n [attr.data-node-id]=\"getNodeId(node)\"\n [attr.data-tree-node-id]=\"getNodeId(node)\"\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(getNodeId(node))\"\n [tabindex]=\"isNodeFocused(getNodeId(node)) ? 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]=\"getNodeExpanded(node)\"\n [disabled]=\"getNodeDisabled(node) || getNodeLoading(node)\"\n [style.visibility]=\"shouldShowExpandToggle(node) ? 'visible' : 'hidden'\"\n >\n @if (getNodeLoading(node)) {\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]=\"getNodeExpanded(node) ? directionExpandedIcon() : directionCollapsedIcon()\"\n class=\"ax-tree-view-toggle-icon\"\n ></i>\n </ax-icon>\n }\n </ax-button>\n @if (nodeTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"nodeTemplate()!\"\n [ngTemplateOutletContext]=\"getTemplateContext(node, 0)\"\n ></ng-container>\n } @else {\n @if (shouldShowCheckboxForNode(node)) {\n <ax-check-box\n class=\"ax-tree-view-checkbox\"\n [ngModel]=\"getNodeIndeterminate(node) ? null : getNodeSelected(node) || false\"\n [indeterminate]=\"getNodeIndeterminate(node) || false\"\n (onValueChanged)=\"toggleSelection(node, $event)\"\n ></ax-check-box>\n }\n @if (showIcons() && getNodeIcon(node)) {\n <i [class]=\"getNodeIcon(node)\" class=\"ax-tree-view-node-icon\"></i>\n }\n <span\n class=\"ax-tree-view-node-label\"\n [axTooltip]=\"getNodeTooltip(node) || ''\"\n [axTooltipDisabled]=\"!getNodeTooltip(node)\"\n [axTooltipPlacement]=\"'top-start'\"\n >\n {{ getNodeTitle(node) }}\n </span>\n @if (\n showChildrenBadge() &&\n (getNodeChildrenCount(node) || (getNodeChildren(node) && getNodeChildren(node)!.length > 0))\n ) {\n <span class=\"ax-tree-view-node-badge\">\n <ax-badge\n class=\"ax-tree-view-children-badge\"\n [text]=\"(getNodeChildrenCount(node) ?? getNodeChildren(node)?.length ?? 0).toString()\"\n ></ax-badge>\n </span>\n }\n }\n </div>\n </div>\n @if (getNodeExpanded(node) && getNodeChildren(node) && getNodeChildren(node)!.length > 0) {\n <div class=\"ax-tree-view-children\" role=\"group\">\n <ng-container\n [ngTemplateOutlet]=\"childrenList\"\n [ngTemplateOutletContext]=\"{ children: getNodeChildren(node), 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]=\"getNodeId(parent)\"\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 getNodeId(node)) {\n @if (getNodeHidden(node) !== true) {\n <div\n [axDrag]=\"dragMode() !== 'none'\"\n [dragDisabled]=\"getNodeDisabled(node)\"\n [dragData]=\"node\"\n class=\"ax-tree-view-node\"\n [class.ax-tree-view-node-selected]=\"getNodeSelected(node)\"\n [class.ax-tree-view-node-disabled]=\"getNodeDisabled(node)\"\n [class.ax-tree-view-node-loading]=\"getNodeLoading(node)\"\n [class.ax-tree-view-node-focused]=\"isNodeFocused(getNodeId(node))\"\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]=\"getNodeDisabled(node) ? 'true' : null\"\n >\n <div\n class=\"ax-tree-view-node-content\"\n [axDropList]=\"dragMode() !== 'none'\"\n [id]=\"'ax-tree-view-node-drop-' + getNodeId(node)\"\n [attr.data-node-id]=\"getNodeId(node)\"\n [attr.data-tree-node-id]=\"getNodeId(node)\"\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(getNodeId(node))\"\n (blur)=\"focusedNodeId.set(null)\"\n [tabindex]=\"isNodeFocused(getNodeId(node)) ? 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]=\"getNodeExpanded(node)\"\n [disabled]=\"getNodeDisabled(node) || getNodeLoading(node)\"\n [style.visibility]=\"shouldShowExpandToggle(node) ? 'visible' : 'hidden'\"\n >\n @if (getNodeLoading(node)) {\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]=\"getNodeExpanded(node) ? directionExpandedIcon() : directionCollapsedIcon()\"\n class=\"ax-tree-view-toggle-icon\"\n ></i>\n </ax-icon>\n }\n </ax-button>\n\n @if (nodeTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"nodeTemplate()!\"\n [ngTemplateOutletContext]=\"getTemplateContext(node, level)\"\n ></ng-container>\n } @else {\n @if (shouldShowCheckboxForNode(node)) {\n <ax-check-box\n class=\"ax-tree-view-checkbox\"\n [ngModel]=\"getNodeIndeterminate(node) ? null : getNodeSelected(node) || false\"\n [indeterminate]=\"getNodeIndeterminate(node) || false\"\n (onValueChanged)=\"toggleSelection(node, $event)\"\n ></ax-check-box>\n }\n @if (showIcons() && getNodeIcon(node)) {\n <i [class]=\"getNodeIcon(node)\" class=\"ax-tree-view-node-icon\"></i>\n }\n <span\n class=\"ax-tree-view-node-label\"\n [axTooltip]=\"getNodeTooltip(node) || ''\"\n [axTooltipDisabled]=\"!getNodeTooltip(node)\"\n [axTooltipPlacement]=\"'top-start'\"\n >\n {{ getNodeTitle(node) }}\n </span>\n @if (\n showChildrenBadge() &&\n (getNodeChildrenCount(node) || (getNodeChildren(node) && getNodeChildren(node)!.length > 0))\n ) {\n <span class=\"ax-tree-view-node-badge\">\n <ax-badge\n class=\"ax-tree-view-children-badge\"\n [text]=\"(getNodeChildrenCount(node) ?? getNodeChildren(node)?.length ?? 0).toString()\"\n ></ax-badge>\n </span>\n }\n }\n </div>\n </div>\n @if (getNodeExpanded(node) && getNodeChildren(node) && getNodeChildren(node)!.length > 0) {\n <div class=\"ax-tree-view-children\" role=\"group\">\n <ng-container\n [ngTemplateOutlet]=\"childrenList\"\n [ngTemplateOutletContext]=\"{ children: getNodeChildren(node), parent: node, level: level + 1 }\"\n ></ng-container>\n </div>\n }\n }\n }\n </div>\n</ng-template>\n", styles: [".ax-tree-view{display:block;width:100%;--ax-comp-tree-view-indent-size: 12px;--ax-comp-tree-view-node-hover-bg: rgba(var(--ax-sys-color-on-lightest-surface), .04);--ax-comp-tree-view-node-selected-bg: rgba(var(--ax-sys-color-primary-500), .12);--ax-comp-tree-view-node-border-radius: 6px;--ax-comp-tree-view-node-margin: .25rem;--ax-comp-tree-view-line-color: rgba(var(--ax-sys-color-on-lightest-surface), .15);--ax-comp-tree-view-drag-preview-opacity: .9;--ax-comp-tree-view-drag-placeholder-bg: rgba(var(--ax-sys-color-on-lightest-surface), .02);--ax-comp-tree-view-drop-active-bg: rgba(var(--ax-sys-color-primary-500), .08);--ax-comp-tree-view-drop-active-outline: rgba(var(--ax-sys-color-primary-500), .3);--ax-comp-tree-view-content-padding: 0;--ax-comp-tree-view-content-gap: .5rem;--ax-comp-tree-view-drop-list-min-height: 2rem;--ax-comp-tree-view-drag-handle-padding: .25rem;--ax-comp-tree-view-badge-padding: .25rem;--ax-comp-tree-view-expand-toggle-padding: .25rem;--ax-comp-tree-view-outline-offset: 2px;--ax-comp-tree-view-outline-offset-negative: -2px}.ax-tree-view-drop-list{min-height:var(--ax-comp-tree-view-drop-list-min-height)}.ax-tree-view-node{position:relative;margin:var(--ax-comp-tree-view-node-margin) 0;border-radius:var(--ax-comp-tree-view-node-border-radius);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)}.ax-tree-view-node.ax-dragging{opacity:var(--ax-comp-tree-view-drag-placeholder-opacity);cursor:grabbing!important}.ax-tree-view-node.ax-drag-placeholder{background:var(--ax-comp-tree-view-drag-placeholder-bg)}.ax-drag-preview{opacity:var(--ax-comp-tree-view-drag-preview-opacity)!important;box-shadow:0 4px 12px rgba(var(--ax-sys-color-on-lightest-surface),.2)!important;cursor:grabbing!important;border:2px dashed currentColor!important}.ax-tree-view-node-content.ax-drop-list-sorting-active{background:var(--ax-comp-tree-view-drop-active-bg);border-radius:var(--ax-comp-tree-view-node-border-radius);outline:2px dashed var(--ax-comp-tree-view-drop-active-outline);outline-offset:var(--ax-comp-tree-view-outline-offset-negative)}.ax-tree-view-node-content{display:flex;align-items:center;gap:var(--ax-comp-tree-view-content-gap);padding:var(--ax-comp-tree-view-content-padding);cursor:pointer;-webkit-user-select:none;user-select:none;outline:none;border-radius:var(--ax-comp-tree-view-node-border-radius)}.ax-tree-view-node-content:focus{outline:none}.ax-tree-view-node-content:focus-visible{outline:2px solid rgba(var(--ax-sys-color-primary-500),.8);outline-offset:var(--ax-comp-tree-view-outline-offset);border-radius:var(--ax-comp-tree-view-node-border-radius)}.ax-tree-view-drag-handle{cursor:grab;opacity:.6;padding:var(--ax-comp-tree-view-drag-handle-padding);padding-inline-start:calc(var(--ax-comp-tree-view-drag-handle-padding) * 2)}.ax-tree-view-drag-handle:hover{opacity:1}.ax-tree-view-drag-handle:active{cursor:grabbing}.ax-tree-view-expand-toggle{background:none;border:none;cursor:pointer;padding:var(--ax-comp-tree-view-expand-toggle-padding);min-width:1.5rem;height:1.5rem}.ax-tree-view-expand-toggle:not(.ax-tree-view-has-children){opacity:0;pointer-events:none}.ax-tree-view-toggle-icon{font-size:.75rem}.ax-tree-view-node-icon{font-size:1.125rem;flex-shrink:0}.ax-tree-view-node-label{flex:1;font-size:.875rem;line-height:1rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ax-tree-view-node-badge{padding:var(--ax-comp-tree-view-badge-padding);padding-inline-end:calc(var(--ax-comp-tree-view-badge-padding) * 1.5)}.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)}.ax-tree-view-card .ax-tree-view-node.ax-tree-view-node-selected{border:1px solid rgba(var(--ax-sys-color-border-surface),1)}.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"] }]
2103
+ }], 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 }] }], selectionBehavior: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionBehavior", 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 }] }], look: [{ type: i0.Input, args: [{ isSignal: true, alias: "look", required: false }] }], nodeTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodeTemplate", required: false }] }], idField: [{ type: i0.Input, args: [{ isSignal: true, alias: "idField", required: false }] }], titleField: [{ type: i0.Input, args: [{ isSignal: true, alias: "titleField", required: false }] }], tooltipField: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipField", required: false }] }], iconField: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconField", required: false }] }], expandedField: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandedField", required: false }] }], selectedField: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedField", required: false }] }], indeterminateField: [{ type: i0.Input, args: [{ isSignal: true, alias: "indeterminateField", required: false }] }], disabledField: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledField", required: false }] }], hiddenField: [{ type: i0.Input, args: [{ isSignal: true, alias: "hiddenField", required: false }] }], childrenField: [{ type: i0.Input, args: [{ isSignal: true, alias: "childrenField", required: false }] }], childrenCountField: [{ type: i0.Input, args: [{ isSignal: true, alias: "childrenCountField", required: false }] }], dataField: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataField", required: false }] }], onBeforeDrop: [{ type: i0.Output, args: ["onBeforeDrop"] }], onNodeToggle: [{ type: i0.Output, args: ["onNodeToggle"] }], onNodeSelect: [{ type: i0.Output, args: ["onNodeSelect"] }], onSelectionChange: [{ type: i0.Output, args: ["onSelectionChange"] }], onOrderChange: [{ type: i0.Output, args: ["onOrderChange"] }], onMoveChange: [{ type: i0.Output, args: ["onMoveChange"] }], onItemsChange: [{ type: i0.Output, args: ["onItemsChange"] }] } });
474
2104
 
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
2105
  class AXTreeViewModule {
487
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXTreeViewModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
488
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.12", 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.12", ngImport: i0, type: AXTreeViewModule, imports: [COMPONENT, MODULES] }); }
2106
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
2107
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewModule, imports: [AXTreeViewComponent] }); }
2108
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewModule, imports: [AXTreeViewComponent] }); }
497
2109
  }
498
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXTreeViewModule, decorators: [{
2110
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXTreeViewModule, decorators: [{
499
2111
  type: NgModule,
500
2112
  args: [{
501
- imports: [...COMPONENT, ...MODULES],
502
- exports: [...COMPONENT],
2113
+ imports: [AXTreeViewComponent],
503
2114
  }]
504
2115
  }] });
505
2116
 
@@ -507,5 +2118,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
507
2118
  * Generated bundle index. Do not edit.
508
2119
  */
509
2120
 
510
- export { AXTreeItemClickBaseEvent, AXTreeViewBase, AXTreeViewComponent, AXTreeViewItemComponent, AXTreeViewModule };
2121
+ export { AXTreeViewComponent, AXTreeViewModule, AXTreeViewService };
511
2122
  //# sourceMappingURL=acorex-components-tree-view.mjs.map