@acorex/components 21.0.0-next.6 → 21.0.0-next.61

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