@acorex/components 21.0.0-next.40 → 21.0.0-next.41

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