@raintonic/formaui 0.3.1 → 0.9.0

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 (238) hide show
  1. package/CHANGELOG.md +80 -35
  2. package/README.md +22 -26
  3. package/fesm2022/raintonic-formaui-cdk-drag-drop.mjs +39 -41
  4. package/fesm2022/raintonic-formaui-cdk-drag-drop.mjs.map +1 -1
  5. package/fesm2022/raintonic-formaui-cdk-form-field.mjs +207 -3
  6. package/fesm2022/raintonic-formaui-cdk-form-field.mjs.map +1 -1
  7. package/fesm2022/raintonic-formaui-cdk-overlay.mjs +27 -2
  8. package/fesm2022/raintonic-formaui-cdk-overlay.mjs.map +1 -1
  9. package/fesm2022/raintonic-formaui-cdk-virtual-scroll.mjs +5 -12
  10. package/fesm2022/raintonic-formaui-cdk-virtual-scroll.mjs.map +1 -1
  11. package/fesm2022/raintonic-formaui-components-accordion.mjs +8 -5
  12. package/fesm2022/raintonic-formaui-components-accordion.mjs.map +1 -1
  13. package/fesm2022/raintonic-formaui-components-alert.mjs +16 -2
  14. package/fesm2022/raintonic-formaui-components-alert.mjs.map +1 -1
  15. package/fesm2022/raintonic-formaui-components-autocomplete.mjs +255 -462
  16. package/fesm2022/raintonic-formaui-components-autocomplete.mjs.map +1 -1
  17. package/fesm2022/raintonic-formaui-components-avatar.mjs +34 -59
  18. package/fesm2022/raintonic-formaui-components-avatar.mjs.map +1 -1
  19. package/fesm2022/raintonic-formaui-components-badge.mjs +2 -2
  20. package/fesm2022/raintonic-formaui-components-badge.mjs.map +1 -1
  21. package/fesm2022/raintonic-formaui-components-breadcrumb.mjs +4 -4
  22. package/fesm2022/raintonic-formaui-components-breadcrumb.mjs.map +1 -1
  23. package/fesm2022/raintonic-formaui-components-button-group.mjs +2 -2
  24. package/fesm2022/raintonic-formaui-components-button-group.mjs.map +1 -1
  25. package/fesm2022/raintonic-formaui-components-button.mjs +15 -20
  26. package/fesm2022/raintonic-formaui-components-button.mjs.map +1 -1
  27. package/fesm2022/raintonic-formaui-components-card.mjs +2 -2
  28. package/fesm2022/raintonic-formaui-components-card.mjs.map +1 -1
  29. package/fesm2022/raintonic-formaui-components-checkbox.mjs +2 -2
  30. package/fesm2022/raintonic-formaui-components-checkbox.mjs.map +1 -1
  31. package/fesm2022/raintonic-formaui-components-chip.mjs +97 -0
  32. package/fesm2022/raintonic-formaui-components-chip.mjs.map +1 -0
  33. package/fesm2022/raintonic-formaui-components-data-table.mjs +69 -29
  34. package/fesm2022/raintonic-formaui-components-data-table.mjs.map +1 -1
  35. package/fesm2022/raintonic-formaui-components-date-picker.mjs +223 -144
  36. package/fesm2022/raintonic-formaui-components-date-picker.mjs.map +1 -1
  37. package/fesm2022/raintonic-formaui-components-divider.mjs +2 -2
  38. package/fesm2022/raintonic-formaui-components-divider.mjs.map +1 -1
  39. package/fesm2022/raintonic-formaui-components-drawer.mjs +2 -2
  40. package/fesm2022/raintonic-formaui-components-drawer.mjs.map +1 -1
  41. package/fesm2022/raintonic-formaui-components-dropdown-menu.mjs +888 -0
  42. package/fesm2022/raintonic-formaui-components-dropdown-menu.mjs.map +1 -0
  43. package/fesm2022/raintonic-formaui-components-dual-tier-navigation.mjs +774 -0
  44. package/fesm2022/raintonic-formaui-components-dual-tier-navigation.mjs.map +1 -0
  45. package/fesm2022/raintonic-formaui-components-empty-state.mjs +2 -2
  46. package/fesm2022/raintonic-formaui-components-empty-state.mjs.map +1 -1
  47. package/fesm2022/raintonic-formaui-components-file-upload.mjs +2 -2
  48. package/fesm2022/raintonic-formaui-components-file-upload.mjs.map +1 -1
  49. package/fesm2022/raintonic-formaui-components-form-field.mjs +81 -50
  50. package/fesm2022/raintonic-formaui-components-form-field.mjs.map +1 -1
  51. package/fesm2022/raintonic-formaui-components-icon.mjs +2 -2
  52. package/fesm2022/raintonic-formaui-components-icon.mjs.map +1 -1
  53. package/fesm2022/raintonic-formaui-components-input.mjs +47 -12
  54. package/fesm2022/raintonic-formaui-components-input.mjs.map +1 -1
  55. package/fesm2022/raintonic-formaui-components-list.mjs +4 -4
  56. package/fesm2022/raintonic-formaui-components-list.mjs.map +1 -1
  57. package/fesm2022/raintonic-formaui-components-number-input.mjs +20 -12
  58. package/fesm2022/raintonic-formaui-components-number-input.mjs.map +1 -1
  59. package/fesm2022/raintonic-formaui-components-paginator.mjs +2 -2
  60. package/fesm2022/raintonic-formaui-components-paginator.mjs.map +1 -1
  61. package/fesm2022/raintonic-formaui-components-password-input.mjs +35 -110
  62. package/fesm2022/raintonic-formaui-components-password-input.mjs.map +1 -1
  63. package/fesm2022/raintonic-formaui-components-popover.mjs +3 -2
  64. package/fesm2022/raintonic-formaui-components-popover.mjs.map +1 -1
  65. package/fesm2022/raintonic-formaui-components-progressbar.mjs +3 -2
  66. package/fesm2022/raintonic-formaui-components-progressbar.mjs.map +1 -1
  67. package/fesm2022/raintonic-formaui-components-radio.mjs +5 -6
  68. package/fesm2022/raintonic-formaui-components-radio.mjs.map +1 -1
  69. package/fesm2022/raintonic-formaui-components-select.mjs +257 -412
  70. package/fesm2022/raintonic-formaui-components-select.mjs.map +1 -1
  71. package/fesm2022/raintonic-formaui-components-side-panel.mjs +2 -2
  72. package/fesm2022/raintonic-formaui-components-side-panel.mjs.map +1 -1
  73. package/fesm2022/raintonic-formaui-components-sidebar-nav-menu.mjs +525 -0
  74. package/fesm2022/raintonic-formaui-components-sidebar-nav-menu.mjs.map +1 -0
  75. package/fesm2022/raintonic-formaui-components-skeleton.mjs +2 -2
  76. package/fesm2022/raintonic-formaui-components-skeleton.mjs.map +1 -1
  77. package/fesm2022/raintonic-formaui-components-slider.mjs +2 -2
  78. package/fesm2022/raintonic-formaui-components-slider.mjs.map +1 -1
  79. package/fesm2022/raintonic-formaui-components-spinner.mjs +2 -2
  80. package/fesm2022/raintonic-formaui-components-spinner.mjs.map +1 -1
  81. package/fesm2022/raintonic-formaui-components-stepper.mjs +50 -45
  82. package/fesm2022/raintonic-formaui-components-stepper.mjs.map +1 -1
  83. package/fesm2022/raintonic-formaui-components-strength-meter.mjs +149 -0
  84. package/fesm2022/raintonic-formaui-components-strength-meter.mjs.map +1 -0
  85. package/fesm2022/raintonic-formaui-components-tab.mjs +2 -2
  86. package/fesm2022/raintonic-formaui-components-tab.mjs.map +1 -1
  87. package/fesm2022/raintonic-formaui-components-time-picker.mjs +194 -154
  88. package/fesm2022/raintonic-formaui-components-time-picker.mjs.map +1 -1
  89. package/fesm2022/raintonic-formaui-components-toggle-group.mjs +302 -0
  90. package/fesm2022/raintonic-formaui-components-toggle-group.mjs.map +1 -0
  91. package/fesm2022/raintonic-formaui-components-toggle.mjs +2 -2
  92. package/fesm2022/raintonic-formaui-components-toggle.mjs.map +1 -1
  93. package/fesm2022/raintonic-formaui-components-toolbar.mjs +2 -2
  94. package/fesm2022/raintonic-formaui-components-toolbar.mjs.map +1 -1
  95. package/fesm2022/raintonic-formaui-components-tooltip.mjs +10 -4
  96. package/fesm2022/raintonic-formaui-components-tooltip.mjs.map +1 -1
  97. package/fesm2022/raintonic-formaui-components-topbar.mjs +60 -0
  98. package/fesm2022/raintonic-formaui-components-topbar.mjs.map +1 -0
  99. package/fesm2022/raintonic-formaui-components-tree-select.mjs +59 -69
  100. package/fesm2022/raintonic-formaui-components-tree-select.mjs.map +1 -1
  101. package/fesm2022/raintonic-formaui-components-tree-table.mjs +2 -2
  102. package/fesm2022/raintonic-formaui-components-tree-table.mjs.map +1 -1
  103. package/fesm2022/raintonic-formaui-components-tree.mjs +31 -5
  104. package/fesm2022/raintonic-formaui-components-tree.mjs.map +1 -1
  105. package/fesm2022/raintonic-formaui-core.mjs +279 -1
  106. package/fesm2022/raintonic-formaui-core.mjs.map +1 -1
  107. package/fesm2022/raintonic-formaui-services-breakpoint.mjs +93 -0
  108. package/fesm2022/raintonic-formaui-services-breakpoint.mjs.map +1 -0
  109. package/fesm2022/raintonic-formaui-services-dialog.mjs +314 -16
  110. package/fesm2022/raintonic-formaui-services-dialog.mjs.map +1 -1
  111. package/fesm2022/raintonic-formaui-services-notification.mjs +93 -29
  112. package/fesm2022/raintonic-formaui-services-notification.mjs.map +1 -1
  113. package/fesm2022/raintonic-formaui-services-theme.mjs +46 -196
  114. package/fesm2022/raintonic-formaui-services-theme.mjs.map +1 -1
  115. package/fesm2022/raintonic-formaui.mjs +1 -1
  116. package/fesm2022/raintonic-formaui.mjs.map +1 -1
  117. package/llms-full.txt +2329 -450
  118. package/llms.txt +36 -33
  119. package/package.json +42 -19
  120. package/styles/fonts/Geist-Bold.woff2 +0 -0
  121. package/styles/fonts/Geist-Italic.woff2 +0 -0
  122. package/styles/fonts/Geist-Light.woff2 +0 -0
  123. package/styles/fonts/Geist-Medium.woff2 +0 -0
  124. package/styles/fonts/Geist-Regular.woff2 +0 -0
  125. package/styles/fonts/Geist-SemiBold.woff2 +0 -0
  126. package/styles/fonts/GeistMono-Regular.woff2 +0 -0
  127. package/styles/generated/_tokens.scss +906 -0
  128. package/styles/index.scss +11 -10
  129. package/styles/partials/_brand.scss +46 -0
  130. package/styles/partials/_constants.scss +22 -20
  131. package/styles/partials/_fonts.scss +54 -10
  132. package/styles/partials/_grid.scss +29 -18
  133. package/styles/partials/_mixins.scss +69 -27
  134. package/styles/partials/_motion.scss +28 -33
  135. package/styles/partials/_theme.scss +28 -255
  136. package/styles/partials/_type.scss +117 -0
  137. package/styles/partials/_typography.scss +45 -45
  138. package/styles/partials/_utilities.scss +198 -98
  139. package/styles/partials/components/_button.scss +144 -75
  140. package/styles/partials/components/_dialog.scss +181 -180
  141. package/styles/partials/components/_overlay.scss +87 -87
  142. package/styles/partials/themes/_dark.scss +3 -268
  143. package/styles/partials/themes/_light.scss +4 -268
  144. package/styles/styles.css +7744 -0
  145. package/styles/styles.entry.scss +3 -0
  146. package/styles/utilities.css +4802 -0
  147. package/styles/utilities.entry.scss +3 -0
  148. package/types/raintonic-formaui-cdk-drag-drop.d.ts +0 -1
  149. package/types/raintonic-formaui-cdk-drag-drop.d.ts.map +1 -1
  150. package/types/raintonic-formaui-cdk-form-field.d.ts +118 -2
  151. package/types/raintonic-formaui-cdk-form-field.d.ts.map +1 -1
  152. package/types/raintonic-formaui-cdk-overlay.d.ts +2 -0
  153. package/types/raintonic-formaui-cdk-overlay.d.ts.map +1 -1
  154. package/types/raintonic-formaui-cdk-virtual-scroll.d.ts +0 -1
  155. package/types/raintonic-formaui-cdk-virtual-scroll.d.ts.map +1 -1
  156. package/types/raintonic-formaui-components-accordion.d.ts +1 -1
  157. package/types/raintonic-formaui-components-accordion.d.ts.map +1 -1
  158. package/types/raintonic-formaui-components-alert.d.ts +6 -1
  159. package/types/raintonic-formaui-components-alert.d.ts.map +1 -1
  160. package/types/raintonic-formaui-components-autocomplete.d.ts +73 -116
  161. package/types/raintonic-formaui-components-autocomplete.d.ts.map +1 -1
  162. package/types/raintonic-formaui-components-avatar.d.ts +13 -31
  163. package/types/raintonic-formaui-components-avatar.d.ts.map +1 -1
  164. package/types/raintonic-formaui-components-button.d.ts +4 -10
  165. package/types/raintonic-formaui-components-button.d.ts.map +1 -1
  166. package/types/raintonic-formaui-components-chip.d.ts +43 -0
  167. package/types/raintonic-formaui-components-chip.d.ts.map +1 -0
  168. package/types/raintonic-formaui-components-data-table.d.ts +48 -11
  169. package/types/raintonic-formaui-components-data-table.d.ts.map +1 -1
  170. package/types/raintonic-formaui-components-date-picker.d.ts +59 -23
  171. package/types/raintonic-formaui-components-date-picker.d.ts.map +1 -1
  172. package/types/raintonic-formaui-components-dropdown-menu.d.ts +394 -0
  173. package/types/raintonic-formaui-components-dropdown-menu.d.ts.map +1 -0
  174. package/types/raintonic-formaui-components-dual-tier-navigation.d.ts +87 -0
  175. package/types/raintonic-formaui-components-dual-tier-navigation.d.ts.map +1 -0
  176. package/types/raintonic-formaui-components-form-field.d.ts +51 -21
  177. package/types/raintonic-formaui-components-form-field.d.ts.map +1 -1
  178. package/types/raintonic-formaui-components-input.d.ts +20 -11
  179. package/types/raintonic-formaui-components-input.d.ts.map +1 -1
  180. package/types/raintonic-formaui-components-number-input.d.ts +5 -3
  181. package/types/raintonic-formaui-components-number-input.d.ts.map +1 -1
  182. package/types/raintonic-formaui-components-password-input.d.ts +18 -32
  183. package/types/raintonic-formaui-components-password-input.d.ts.map +1 -1
  184. package/types/raintonic-formaui-components-popover.d.ts.map +1 -1
  185. package/types/raintonic-formaui-components-progressbar.d.ts +1 -1
  186. package/types/raintonic-formaui-components-progressbar.d.ts.map +1 -1
  187. package/types/raintonic-formaui-components-radio.d.ts +1 -2
  188. package/types/raintonic-formaui-components-radio.d.ts.map +1 -1
  189. package/types/raintonic-formaui-components-select.d.ts +107 -76
  190. package/types/raintonic-formaui-components-select.d.ts.map +1 -1
  191. package/types/raintonic-formaui-components-sidebar-nav-menu.d.ts +223 -0
  192. package/types/raintonic-formaui-components-sidebar-nav-menu.d.ts.map +1 -0
  193. package/types/raintonic-formaui-components-stepper.d.ts +4 -2
  194. package/types/raintonic-formaui-components-stepper.d.ts.map +1 -1
  195. package/types/raintonic-formaui-components-strength-meter.d.ts +78 -0
  196. package/types/raintonic-formaui-components-strength-meter.d.ts.map +1 -0
  197. package/types/raintonic-formaui-components-time-picker.d.ts +44 -24
  198. package/types/raintonic-formaui-components-time-picker.d.ts.map +1 -1
  199. package/types/raintonic-formaui-components-toggle-group.d.ts +100 -0
  200. package/types/raintonic-formaui-components-toggle-group.d.ts.map +1 -0
  201. package/types/raintonic-formaui-components-tooltip.d.ts +2 -1
  202. package/types/raintonic-formaui-components-tooltip.d.ts.map +1 -1
  203. package/types/raintonic-formaui-components-topbar.d.ts +48 -0
  204. package/types/raintonic-formaui-components-topbar.d.ts.map +1 -0
  205. package/types/raintonic-formaui-components-tree-select.d.ts +25 -9
  206. package/types/raintonic-formaui-components-tree-select.d.ts.map +1 -1
  207. package/types/raintonic-formaui-components-tree.d.ts +12 -1
  208. package/types/raintonic-formaui-components-tree.d.ts.map +1 -1
  209. package/types/raintonic-formaui-core.d.ts +243 -5
  210. package/types/raintonic-formaui-core.d.ts.map +1 -1
  211. package/types/raintonic-formaui-services-breakpoint.d.ts +44 -0
  212. package/types/raintonic-formaui-services-breakpoint.d.ts.map +1 -0
  213. package/types/raintonic-formaui-services-dialog.d.ts +141 -2
  214. package/types/raintonic-formaui-services-dialog.d.ts.map +1 -1
  215. package/types/raintonic-formaui-services-notification.d.ts +24 -2
  216. package/types/raintonic-formaui-services-notification.d.ts.map +1 -1
  217. package/types/raintonic-formaui-services-theme.d.ts +13 -103
  218. package/types/raintonic-formaui-services-theme.d.ts.map +1 -1
  219. package/types/raintonic-formaui.d.ts +1 -1
  220. package/fesm2022/raintonic-formaui-components-big-menu.mjs +0 -86
  221. package/fesm2022/raintonic-formaui-components-big-menu.mjs.map +0 -1
  222. package/fesm2022/raintonic-formaui-components-menu.mjs +0 -896
  223. package/fesm2022/raintonic-formaui-components-menu.mjs.map +0 -1
  224. package/fesm2022/raintonic-formaui-components-sidebar.mjs +0 -275
  225. package/fesm2022/raintonic-formaui-components-sidebar.mjs.map +0 -1
  226. package/fesm2022/raintonic-formaui-components-tag.mjs +0 -95
  227. package/fesm2022/raintonic-formaui-components-tag.mjs.map +0 -1
  228. package/styles/_fonts-entry.scss +0 -3
  229. package/styles/fonts/inter-tight-latin-italic.woff2 +0 -0
  230. package/styles/fonts/inter-tight-latin.woff2 +0 -0
  231. package/types/raintonic-formaui-components-big-menu.d.ts +0 -73
  232. package/types/raintonic-formaui-components-big-menu.d.ts.map +0 -1
  233. package/types/raintonic-formaui-components-menu.d.ts +0 -403
  234. package/types/raintonic-formaui-components-menu.d.ts.map +0 -1
  235. package/types/raintonic-formaui-components-sidebar.d.ts +0 -185
  236. package/types/raintonic-formaui-components-sidebar.d.ts.map +0 -1
  237. package/types/raintonic-formaui-components-tag.d.ts +0 -43
  238. package/types/raintonic-formaui-components-tag.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"raintonic-formaui-components-tree-select.mjs","sources":["../../../lib/components/tree-select/fui-tree-select.component.ts","../../../lib/components/tree-select/fui-tree-select.component.html","../../../lib/components/tree-select/raintonic-formaui-components-tree-select.ts"],"sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n computed,\r\n DoCheck,\r\n ElementRef,\r\n forwardRef,\r\n inject,\r\n input,\r\n OnDestroy,\r\n output,\r\n signal,\r\n Signal,\r\n TemplateRef,\r\n ViewChild,\r\n ViewEncapsulation,\r\n} from '@angular/core';\r\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR, NgControl } from '@angular/forms';\r\nimport { Observable, Subject } from 'rxjs';\r\nimport { FUI_FORM_FIELD_CONTROL, FuiFormFieldControl } from '@raintonic/formaui/core';\r\nimport { injectNgControl } from '@raintonic/formaui/cdk/form-field';\r\nimport { FuiTreeComponent, FuiTreeNode, FuiTreeNodeEvent, FuiTreeSelectionMode } from '@raintonic/formaui/components/tree';\r\nimport { FuiIconComponent } from '@raintonic/formaui/components/icon';\r\nimport { FuiBadgeComponent } from '@raintonic/formaui/components/badge';\r\nimport { FuiConnectedPosition, FuiOverlayRef, FuiOverlayService } from '@raintonic/formaui/cdk/overlay';\r\nimport { FuiTreeSelectChange } from './tree-select.types';\r\n\r\nlet nextId = 0;\r\n\r\n@Component({\r\n selector: 'fui-tree-select',\r\n standalone: true,\r\n imports: [FuiTreeComponent, FuiIconComponent, FuiBadgeComponent],\r\n templateUrl: './fui-tree-select.component.html',\r\n styleUrl: './fui-tree-select.component.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.None,\r\n providers: [\r\n { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => FuiTreeSelectComponent), multi: true },\r\n { provide: FUI_FORM_FIELD_CONTROL, useExisting: forwardRef(() => FuiTreeSelectComponent) },\r\n ],\r\n host: {\r\n class: 'fui-tree-select',\r\n role: 'combobox',\r\n '[attr.aria-expanded]': '_panelOpen()',\r\n '[attr.aria-haspopup]': '\"tree\"',\r\n '[attr.aria-owns]': '_panelOpen() ? _treeId : null',\r\n '[class.fui-tree-select--open]': '_panelOpen()',\r\n '[class.fui-tree-select--disabled]': 'disabled()',\r\n '(click)': 'toggle()',\r\n '(keydown)': '_onKeydown($event)',\r\n tabindex: '0',\r\n },\r\n})\r\nexport class FuiTreeSelectComponent<T = any>\r\n implements ControlValueAccessor, FuiFormFieldControl<T | T[]>, OnDestroy, DoCheck\r\n{\r\n // Public API\r\n readonly nodes = input.required<FuiTreeNode<T>[]>();\r\n readonly selectionMode = input<'single' | 'multi' | 'checkbox'>('single');\r\n readonly placeholderInput = input('', { alias: 'placeholder' });\r\n readonly showSearch = input(false);\r\n readonly loadChildren = input<((node: FuiTreeNode<T>) => Observable<FuiTreeNode<T>[]>) | null>(null);\r\n readonly nodeTemplate = input<TemplateRef<any> | null>(null);\r\n readonly displayField = input<string | ((node: FuiTreeNode<T>) => string) | null>(null);\r\n readonly disabledInput = input(false, { alias: 'disabled' });\r\n\r\n readonly selectionChange = output<FuiTreeSelectChange<T>>();\r\n\r\n // FuiFormFieldControl implementation\r\n readonly stateChanges = new Subject<void>();\r\n private readonly _value = signal<T | T[] | null>(null);\r\n readonly value: Signal<T | T[] | null> = this._value;\r\n readonly placeholder = computed(() => this.placeholderInput());\r\n readonly focused = signal(false);\r\n readonly empty = computed(() => {\r\n const v = this._value();\r\n return v === null || v === undefined || (Array.isArray(v) && v.length === 0);\r\n });\r\n readonly required = signal(false);\r\n private readonly _disabled = signal(false);\r\n readonly disabled = computed(() => this._disabled() || this.disabledInput());\r\n readonly errorState = signal(false);\r\n readonly controlType = 'fui-tree-select';\r\n readonly id = `fui-tree-select-${nextId++}`;\r\n\r\n // Internal\r\n readonly _panelOpen = signal(false);\r\n readonly _treeId = `${this.id}-tree`;\r\n readonly _searchFilter = signal('');\r\n private _overlayRef: FuiOverlayRef | null = null;\r\n private readonly _ngControlRef = injectNgControl();\r\n get ngControl(): NgControl | null {\r\n return this._ngControlRef.ngControl;\r\n }\r\n\r\n private readonly _overlayService = inject(FuiOverlayService);\r\n private readonly _elementRef = inject(ElementRef);\r\n\r\n // Track selected nodes internally\r\n readonly _selectedNodes = signal<FuiTreeNode<T>[]>([]);\r\n\r\n @ViewChild('trigger', { static: false }) trigger?: ElementRef<HTMLDivElement>;\r\n @ViewChild('panel', { static: false }) panel?: ElementRef<HTMLDivElement>;\r\n\r\n // CVA callbacks\r\n private _onChange: (value: any) => void = () => {\r\n /* noop */\r\n };\r\n private _onTouched: () => void = () => {\r\n /* noop */\r\n };\r\n\r\n constructor() {\r\n void Promise.resolve().then(() => {\r\n if (this._ngControlRef.ngControl) {\r\n this._ngControlRef.ngControl.valueAccessor = this;\r\n }\r\n });\r\n }\r\n\r\n // Methods\r\n toggle(): void {\r\n if (this._panelOpen()) {\r\n this.close();\r\n } else {\r\n this.open();\r\n }\r\n }\r\n\r\n open(): void {\r\n if (this.disabled() || this._panelOpen()) return;\r\n requestAnimationFrame(() => {\r\n this._panelOpen.set(true);\r\n this.focused.set(true);\r\n this.stateChanges.next();\r\n setTimeout(() => {\r\n this._createOverlay();\r\n });\r\n });\r\n }\r\n\r\n close(): void {\r\n if (!this._panelOpen()) return;\r\n this._panelOpen.set(false);\r\n this.focused.set(false);\r\n this._searchFilter.set('');\r\n this._disposeOverlay();\r\n this._onTouched();\r\n this.stateChanges.next();\r\n }\r\n\r\n onContainerClick(_event: MouseEvent): void {\r\n this.toggle();\r\n }\r\n\r\n setDescribedByIds(_ids: string[]): void {\r\n /* no-op for now */\r\n }\r\n\r\n // Tree selection handlers\r\n _onTreeSelect(event: FuiTreeNodeEvent<T>): void {\r\n const node = event.node;\r\n if (this.selectionMode() === 'single') {\r\n // Deselect all first, then select clicked\r\n this._deselectAll(this.nodes());\r\n node.selected = true;\r\n this._selectedNodes.set([node]);\r\n this._value.set(node.data);\r\n this._onChange(node.data);\r\n this.selectionChange.emit({ value: node, source: this });\r\n this.stateChanges.next();\r\n this.close();\r\n } else {\r\n node.selected = !node.selected;\r\n this._updateMultiSelection();\r\n }\r\n }\r\n\r\n _onTreeUnselect(event: FuiTreeNodeEvent<T>): void {\r\n event.node.selected = false;\r\n if (this.selectionMode() === 'single') {\r\n this._selectedNodes.set([]);\r\n this._value.set(null);\r\n this._onChange(null);\r\n } else {\r\n this._updateMultiSelection();\r\n }\r\n this.stateChanges.next();\r\n }\r\n\r\n _getDisplayValue(): string {\r\n const nodes = this._selectedNodes();\r\n if (nodes.length === 0) return '';\r\n return this._getNodeLabel(nodes[0]);\r\n }\r\n\r\n _getSelectedDisplayValues(): string[] {\r\n return this._selectedNodes().map((n) => this._getNodeLabel(n));\r\n }\r\n\r\n _onSearchInput(event: Event): void {\r\n const value = (event.target as HTMLInputElement).value;\r\n this._searchFilter.set(value);\r\n }\r\n\r\n _onKeydown(event: KeyboardEvent): void {\r\n if (event.key === 'Enter' || event.key === ' ') {\r\n if (!this._panelOpen()) {\r\n event.preventDefault();\r\n this.open();\r\n }\r\n } else if (event.key === 'Escape') {\r\n if (this._panelOpen()) {\r\n event.preventDefault();\r\n this.close();\r\n }\r\n }\r\n }\r\n\r\n readonly _treeSelectionMode = computed((): FuiTreeSelectionMode => {\r\n return this.selectionMode() as FuiTreeSelectionMode;\r\n });\r\n\r\n // CVA\r\n writeValue(value: any): void {\r\n this._value.set(value);\r\n this._syncSelectedFromValue(value);\r\n this.stateChanges.next();\r\n }\r\n\r\n registerOnChange(fn: any): void {\r\n this._onChange = fn;\r\n }\r\n\r\n registerOnTouched(fn: any): void {\r\n this._onTouched = fn;\r\n }\r\n\r\n setDisabledState(disabled: boolean): void {\r\n this._disabled.set(disabled);\r\n this.stateChanges.next();\r\n }\r\n\r\n ngOnDestroy(): void {\r\n this._disposeOverlay();\r\n this.stateChanges.complete();\r\n }\r\n\r\n ngDoCheck(): void {\r\n if (this.ngControl) {\r\n const control = this.ngControl.control;\r\n if (control) {\r\n const isInvalid = control.invalid && (control.touched || false);\r\n this.errorState.set(isInvalid);\r\n }\r\n }\r\n }\r\n\r\n // Private helpers\r\n private _getNodeLabel(node: FuiTreeNode<T>): string {\r\n const displayFn = this.displayField();\r\n if (typeof displayFn === 'function') return displayFn(node);\r\n if (typeof displayFn === 'string' && node.data && typeof node.data === 'object') {\r\n return String((node.data as any)[displayFn] ?? '');\r\n }\r\n return String(node.data ?? '');\r\n }\r\n\r\n private _deselectAll(nodes: FuiTreeNode<T>[]): void {\r\n for (const n of nodes) {\r\n n.selected = false;\r\n if (Array.isArray(n.children)) this._deselectAll(n.children);\r\n }\r\n }\r\n\r\n private _updateMultiSelection(): void {\r\n const selected = this._collectSelected(this.nodes());\r\n this._selectedNodes.set(selected);\r\n const values = selected.map((n) => n.data);\r\n this._value.set(values as any);\r\n this._onChange(values);\r\n this.selectionChange.emit({ value: selected, source: this });\r\n this.stateChanges.next();\r\n }\r\n\r\n private _collectSelected(nodes: FuiTreeNode<T>[]): FuiTreeNode<T>[] {\r\n const result: FuiTreeNode<T>[] = [];\r\n for (const n of nodes) {\r\n if (n.selected) result.push(n);\r\n if (Array.isArray(n.children)) result.push(...this._collectSelected(n.children));\r\n }\r\n return result;\r\n }\r\n\r\n private _syncSelectedFromValue(value: any): void {\r\n if (value === null || value === undefined) {\r\n this._deselectAll(this.nodes());\r\n this._selectedNodes.set([]);\r\n return;\r\n }\r\n // For now, leave nodes as-is since the consumer controls node.selected\r\n }\r\n\r\n private _createOverlay(): void {\r\n if (this._overlayRef || !this.panel) return;\r\n const triggerElement = this._elementRef.nativeElement;\r\n const triggerWidth = triggerElement.getBoundingClientRect().width;\r\n const positions: FuiConnectedPosition[] = [\r\n { originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4 },\r\n { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -4 },\r\n ];\r\n const positionStrategy = this._overlayService\r\n .position()\r\n .connectedTo(triggerElement, positions)\r\n .withPush(true)\r\n .withViewportMargin(8);\r\n this._overlayRef = this._overlayService.create({\r\n positionStrategy,\r\n scrollStrategy: this._overlayService.scrollStrategies.reposition(),\r\n hasBackdrop: true,\r\n backdropClass: 'fui-tree-select-backdrop',\r\n backdropClickBehavior: 'close',\r\n panelClass: ['fui-tree-select-overlay-panel'],\r\n minWidth: triggerWidth,\r\n });\r\n this._overlayRef.backdropClick.subscribe(() => {\r\n this.close();\r\n });\r\n this._overlayRef.keydownEvents.subscribe((event) => {\r\n if (event.key === 'Escape') this.close();\r\n });\r\n this._overlayRef.attach(this.panel.nativeElement);\r\n }\r\n\r\n private _disposeOverlay(): void {\r\n if (this._overlayRef) {\r\n this._overlayRef.dispose();\r\n this._overlayRef = null;\r\n }\r\n }\r\n}\r\n","<!-- Trigger area -->\r\n<div class=\"fui-tree-select__trigger\" #trigger>\r\n @if (empty()) {\r\n <span class=\"fui-tree-select__placeholder\">{{ placeholder() }}</span>\r\n } @else if (selectionMode() === 'single') {\r\n <span class=\"fui-tree-select__value\">{{ _getDisplayValue() }}</span>\r\n } @else {\r\n <div class=\"fui-tree-select__tags\">\r\n @for (tag of _getSelectedDisplayValues(); track tag) {\r\n <fui-badge [label]=\"tag\" size=\"sm\" variant=\"secondary\"></fui-badge>\r\n }\r\n </div>\r\n }\r\n <fui-icon class=\"fui-tree-select__arrow\" [name]=\"_panelOpen() ? 'caret-up' : 'caret-down'\" size=\"sm\"></fui-icon>\r\n</div>\r\n\r\n<!-- Panel (rendered always but hidden, moved to overlay when open) -->\r\n<div class=\"fui-tree-select__panel\" [id]=\"_treeId\" #panel [style.display]=\"_panelOpen() ? '' : 'none'\">\r\n @if (showSearch()) {\r\n <div class=\"fui-tree-select__search\">\r\n <input\r\n class=\"fui-tree-select__search-input\"\r\n type=\"text\"\r\n placeholder=\"Search...\"\r\n (input)=\"_onSearchInput($event)\"\r\n (click)=\"$event.stopPropagation()\"\r\n />\r\n </div>\r\n }\r\n <fui-tree\r\n [nodes]=\"nodes()\"\r\n [selectionMode]=\"_treeSelectionMode()\"\r\n [loadChildren]=\"loadChildren()\"\r\n [nodeTemplate]=\"nodeTemplate()\"\r\n [filter]=\"_searchFilter()\"\r\n (nodeSelect)=\"_onTreeSelect($event)\"\r\n (nodeUnselect)=\"_onTreeUnselect($event)\"\r\n >\r\n </fui-tree>\r\n</div>\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"raintonic-formaui-components-tree-select.mjs","sources":["../../../lib/components/tree-select/fui-tree-select.component.ts","../../../lib/components/tree-select/fui-tree-select.component.html","../../../lib/components/tree-select/raintonic-formaui-components-tree-select.ts"],"sourcesContent":["import {\r\n AfterViewInit,\r\n ChangeDetectionStrategy,\r\n Component,\r\n computed,\r\n ElementRef,\r\n forwardRef,\r\n inject,\r\n input,\r\n OnDestroy,\r\n output,\r\n signal,\r\n Signal,\r\n TemplateRef,\r\n ViewChild,\r\n ViewEncapsulation,\r\n} from '@angular/core';\r\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR, NgControl } from '@angular/forms';\r\nimport { Observable, Subject } from 'rxjs';\r\nimport { FUI_FORM_FIELD_CONTROL, FuiFormFieldControl } from '@raintonic/formaui/core';\r\nimport {\r\n injectNgControl,\r\n FuiPopupOverlayDirective,\r\n FuiFormControlSyncDirective,\r\n} from '@raintonic/formaui/cdk/form-field';\r\nimport {\r\n FuiTreeComponent,\r\n FuiTreeNode,\r\n FuiTreeNodeEvent,\r\n FuiTreeSelectionMode,\r\n} from '@raintonic/formaui/components/tree';\r\nimport { FuiIconComponent } from '@raintonic/formaui/components/icon';\r\nimport { FuiBadgeComponent } from '@raintonic/formaui/components/badge';\r\nimport { FuiTreeSelectChange } from './tree-select.types';\r\n\r\nlet nextId = 0;\r\n\r\n@Component({\r\n selector: 'fui-tree-select',\r\n standalone: true,\r\n imports: [FuiTreeComponent, FuiIconComponent, FuiBadgeComponent],\r\n templateUrl: './fui-tree-select.component.html',\r\n styleUrl: './fui-tree-select.component.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.None,\r\n hostDirectives: [\r\n {\r\n directive: FuiPopupOverlayDirective,\r\n inputs: ['positions', 'panelClass', 'backdropClass', 'scrollStrategy', 'minWidthFromTrigger'],\r\n outputs: ['openedChange', 'escapeKey'],\r\n },\r\n FuiFormControlSyncDirective,\r\n ],\r\n providers: [\r\n { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => FuiTreeSelectComponent), multi: true },\r\n { provide: FUI_FORM_FIELD_CONTROL, useExisting: forwardRef(() => FuiTreeSelectComponent) },\r\n ],\r\n host: {\r\n class: 'fui-tree-select',\r\n role: 'combobox',\r\n '[attr.aria-expanded]': '_panelOpen()',\r\n '[attr.aria-haspopup]': '\"tree\"',\r\n '[attr.aria-owns]': '_panelOpen() ? _treeId : null',\r\n '[attr.aria-activedescendant]': 'activeDescendant()',\r\n '[class.fui-tree-select--open]': '_panelOpen()',\r\n '[class.fui-tree-select--disabled]': 'disabled()',\r\n '(click)': 'toggle()',\r\n '(keydown)': '_onKeydown($event)',\r\n tabindex: '0',\r\n },\r\n})\r\n// No Validator interface: only Validators.required is applicable to tree-select,\r\n// and that is handled by the standard CVA + form integration path.\r\n// If a future public API adds minSelected / maxSelected / requiredLeafOnly inputs,\r\n// implement Validator at that point (mirror the time-picker pattern in Task 23).\r\nexport class FuiTreeSelectComponent<T = any>\r\n implements ControlValueAccessor, FuiFormFieldControl<T | T[]>, OnDestroy, AfterViewInit\r\n{\r\n // Public API\r\n readonly nodes = input.required<FuiTreeNode<T>[]>();\r\n readonly selectionMode = input<'single' | 'multi' | 'checkbox'>('single');\r\n readonly placeholderInput = input('', { alias: 'placeholder' });\r\n readonly showSearch = input(false);\r\n readonly loadChildren = input<((node: FuiTreeNode<T>) => Observable<FuiTreeNode<T>[]>) | null>(null);\r\n readonly nodeTemplate = input<TemplateRef<any> | null>(null);\r\n readonly displayField = input<string | ((node: FuiTreeNode<T>) => string) | null>(null);\r\n readonly disabledInput = input(false, { alias: 'disabled' });\r\n readonly readonlyInput = input(false, { alias: 'readonly' });\r\n\r\n readonly selectionChange = output<FuiTreeSelectChange<T>>();\r\n\r\n // FuiFormFieldControl implementation\r\n readonly stateChanges = new Subject<void>();\r\n private readonly _value = signal<T | T[] | null>(null);\r\n readonly value: Signal<T | T[] | null> = this._value;\r\n readonly placeholder = computed(() => this.placeholderInput());\r\n readonly focused = signal(false);\r\n readonly empty = computed(() => {\r\n const v = this._value();\r\n return v === null || v === undefined || (Array.isArray(v) && v.length === 0);\r\n });\r\n readonly required = signal(false);\r\n private readonly _disabled = signal(false);\r\n readonly disabled = computed(() => this._disabled() || this.disabledInput());\r\n readonly readonly = computed(() => this.readonlyInput());\r\n readonly errorState = signal(false);\r\n readonly controlType = 'fui-tree-select';\r\n readonly id = `fui-tree-select-${nextId++}`;\r\n\r\n // Internal\r\n /** Whether the panel is open — projected from FuiPopupOverlayDirective. */\r\n readonly _panelOpen = computed(() => this._popup.panelOpen());\r\n readonly _treeId = `${this.id}-tree`;\r\n readonly _searchFilter = signal('');\r\n\r\n private readonly _activeNodeId = signal<string | null>(null);\r\n /** ID of the tree-node currently highlighted via keyboard nav. Bound to aria-activedescendant. */\r\n readonly activeDescendant = computed(() => this._activeNodeId());\r\n private readonly _ngControlRef = injectNgControl();\r\n get ngControl(): NgControl | null {\r\n return this._ngControlRef.ngControl;\r\n }\r\n\r\n // Injected host directives\r\n private readonly _popup = inject(FuiPopupOverlayDirective);\r\n private readonly _formSync = inject(FuiFormControlSyncDirective);\r\n\r\n private readonly _elementRef = inject(ElementRef);\r\n\r\n // Track selected nodes internally\r\n readonly _selectedNodes = signal<FuiTreeNode<T>[]>([]);\r\n\r\n @ViewChild('trigger', { static: false }) trigger?: ElementRef<HTMLDivElement>;\r\n @ViewChild('panel', { static: false }) panel?: ElementRef<HTMLDivElement>;\r\n\r\n // CVA callbacks\r\n private _onChange: (value: any) => void = () => {\r\n /* noop */\r\n };\r\n private _onTouched: () => void = () => {\r\n /* noop */\r\n };\r\n\r\n constructor() {\r\n void Promise.resolve().then(() => {\r\n if (this._ngControlRef.ngControl) {\r\n this._ngControlRef.ngControl.valueAccessor = this;\r\n }\r\n });\r\n }\r\n\r\n ngAfterViewInit(): void {\r\n // Wire popup-overlay directive\r\n this._popup.setTrigger(this.trigger ?? null);\r\n this._popup.setPanel(this.panel ?? null);\r\n this._popup.panelClass.set(['fui-tree-select-overlay-panel']);\r\n this._popup.backdropClass.set('fui-tree-select-backdrop');\r\n\r\n // Wire form-control-sync directive signals\r\n this._formSync.errorState.set(this.errorState);\r\n this._formSync.required.set(this.required);\r\n this._formSync.stateChanges.set(this.stateChanges);\r\n }\r\n\r\n // Methods\r\n /** Toggles the tree-select panel. No-op if disabled. */\r\n toggle(): void {\r\n if (this._panelOpen()) {\r\n this.close();\r\n } else {\r\n this.open();\r\n }\r\n }\r\n\r\n /** Opens the tree-select panel. No-op if disabled or already open. */\r\n open(): void {\r\n if (this.disabled() || this._panelOpen()) return;\r\n this.focused.set(true);\r\n this.stateChanges.next();\r\n this._popup.open();\r\n }\r\n\r\n /** Closes the tree-select panel, resets the search filter, and marks the control as touched. */\r\n close(): void {\r\n if (!this._panelOpen()) return;\r\n this._searchFilter.set('');\r\n this._popup.close();\r\n this.focused.set(false);\r\n this._onTouched();\r\n this.stateChanges.next();\r\n }\r\n\r\n /** Opens the panel when the form-field container is clicked. */\r\n onContainerClick(_event: MouseEvent): void {\r\n this.toggle();\r\n }\r\n\r\n /** Stores the space-separated list of IDs for the aria-describedby attribute. */\r\n setDescribedByIds(_ids: string[]): void {\r\n /* no-op for now */\r\n }\r\n\r\n // Tree selection handlers\r\n _onTreeSelect(event: FuiTreeNodeEvent<T>): void {\r\n const node = event.node;\r\n if (this.selectionMode() === 'single') {\r\n // Deselect all first, then select clicked\r\n this._deselectAll(this.nodes());\r\n node.selected = true;\r\n this._selectedNodes.set([node]);\r\n this._value.set(node.data);\r\n this._onChange(node.data);\r\n this.selectionChange.emit({ value: node, source: this });\r\n this.stateChanges.next();\r\n this.close();\r\n } else {\r\n node.selected = !node.selected;\r\n this._updateMultiSelection();\r\n }\r\n }\r\n\r\n _onTreeUnselect(event: FuiTreeNodeEvent<T>): void {\r\n event.node.selected = false;\r\n if (this.selectionMode() === 'single') {\r\n this._selectedNodes.set([]);\r\n this._value.set(null);\r\n this._onChange(null);\r\n } else {\r\n this._updateMultiSelection();\r\n }\r\n this.stateChanges.next();\r\n }\r\n\r\n _getDisplayValue(): string {\r\n const nodes = this._selectedNodes();\r\n if (nodes.length === 0) return '';\r\n return this._getNodeLabel(nodes[0]);\r\n }\r\n\r\n _getSelectedDisplayValues(): string[] {\r\n return this._selectedNodes().map((n) => this._getNodeLabel(n));\r\n }\r\n\r\n _onSearchInput(event: Event): void {\r\n const value = (event.target as HTMLInputElement).value;\r\n this._searchFilter.set(value);\r\n }\r\n\r\n /** Called when the embedded tree reports a keyboard focus change. Updates aria-activedescendant. */\r\n _onTreeFocusChange(nodeId: string | null): void {\r\n this._activeNodeId.set(nodeId);\r\n }\r\n\r\n _onKeydown(event: KeyboardEvent): void {\r\n if (event.key === 'Enter' || event.key === ' ') {\r\n if (!this._panelOpen()) {\r\n event.preventDefault();\r\n this.open();\r\n }\r\n } else if (event.key === 'Escape') {\r\n if (this._panelOpen()) {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n this.close();\r\n }\r\n }\r\n }\r\n\r\n readonly _treeSelectionMode = computed((): FuiTreeSelectionMode => {\r\n return this.selectionMode() as FuiTreeSelectionMode;\r\n });\r\n\r\n // CVA\r\n /** Sets the tree-select value from the form model and syncs node selection state. */\r\n writeValue(value: any): void {\r\n this._value.set(value);\r\n this._syncSelectedFromValue(value);\r\n this.stateChanges.next();\r\n }\r\n\r\n /** Registers the callback Angular calls when the value should propagate to the model. */\r\n registerOnChange(fn: any): void {\r\n this._onChange = fn;\r\n }\r\n\r\n /** Registers the callback Angular calls when the control should be marked as touched. */\r\n registerOnTouched(fn: any): void {\r\n this._onTouched = fn;\r\n }\r\n\r\n /** Enables or disables the control programmatically; mirrors the `disabled` form-control state. */\r\n setDisabledState(disabled: boolean): void {\r\n this._disabled.set(disabled);\r\n this.stateChanges.next();\r\n }\r\n\r\n ngOnDestroy(): void {\r\n this.stateChanges.complete();\r\n }\r\n\r\n // Private helpers\r\n private _getNodeLabel(node: FuiTreeNode<T>): string {\r\n const displayFn = this.displayField();\r\n if (typeof displayFn === 'function') return displayFn(node);\r\n if (typeof displayFn === 'string' && node.data && typeof node.data === 'object') {\r\n return String((node.data as any)[displayFn] ?? '');\r\n }\r\n return String(node.data ?? '');\r\n }\r\n\r\n private _deselectAll(nodes: FuiTreeNode<T>[]): void {\r\n for (const n of nodes) {\r\n n.selected = false;\r\n if (Array.isArray(n.children)) this._deselectAll(n.children);\r\n }\r\n }\r\n\r\n private _updateMultiSelection(): void {\r\n const selected = this._collectSelected(this.nodes());\r\n this._selectedNodes.set(selected);\r\n const values = selected.map((n) => n.data);\r\n this._value.set(values as any);\r\n this._onChange(values);\r\n this.selectionChange.emit({ value: selected, source: this });\r\n this.stateChanges.next();\r\n }\r\n\r\n private _collectSelected(nodes: FuiTreeNode<T>[]): FuiTreeNode<T>[] {\r\n const result: FuiTreeNode<T>[] = [];\r\n for (const n of nodes) {\r\n if (n.selected) result.push(n);\r\n if (Array.isArray(n.children)) result.push(...this._collectSelected(n.children));\r\n }\r\n return result;\r\n }\r\n\r\n private _syncSelectedFromValue(value: any): void {\r\n if (value === null || value === undefined) {\r\n this._deselectAll(this.nodes());\r\n this._selectedNodes.set([]);\r\n return;\r\n }\r\n // For now, leave nodes as-is since the consumer controls node.selected\r\n }\r\n}\r\n","<!-- Trigger area -->\r\n<div class=\"fui-tree-select__trigger\" #trigger>\r\n @if (empty()) {\r\n <span class=\"fui-tree-select__placeholder\">{{ placeholder() }}</span>\r\n } @else if (selectionMode() === 'single') {\r\n <span class=\"fui-tree-select__value\">{{ _getDisplayValue() }}</span>\r\n } @else {\r\n <div class=\"fui-tree-select__tags\">\r\n @for (tag of _getSelectedDisplayValues(); track tag) {\r\n <fui-badge [label]=\"tag\" size=\"sm\" variant=\"secondary\"></fui-badge>\r\n }\r\n </div>\r\n }\r\n <fui-icon class=\"fui-tree-select__arrow\" [name]=\"_panelOpen() ? 'caret-up' : 'caret-down'\" size=\"sm\"></fui-icon>\r\n</div>\r\n\r\n<!-- Panel (rendered always but hidden, moved to overlay when open) -->\r\n<div class=\"fui-tree-select__panel\" [id]=\"_treeId\" #panel [style.display]=\"_panelOpen() ? '' : 'none'\">\r\n @if (showSearch()) {\r\n <div class=\"fui-tree-select__search\">\r\n <input\r\n class=\"fui-tree-select__search-input\"\r\n type=\"text\"\r\n placeholder=\"Search...\"\r\n (input)=\"_onSearchInput($event)\"\r\n (click)=\"$event.stopPropagation()\"\r\n />\r\n </div>\r\n }\r\n <fui-tree\r\n [nodes]=\"nodes()\"\r\n [selectionMode]=\"_treeSelectionMode()\"\r\n [loadChildren]=\"loadChildren()\"\r\n [nodeTemplate]=\"nodeTemplate()\"\r\n [filter]=\"_searchFilter()\"\r\n [nodeIdPrefix]=\"_treeId\"\r\n (nodeSelect)=\"_onTreeSelect($event)\"\r\n (nodeUnselect)=\"_onTreeUnselect($event)\"\r\n (focusChange)=\"_onTreeFocusChange($event)\"\r\n >\r\n </fui-tree>\r\n</div>\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -115,13 +115,13 @@ class FuiTreeTableComponent {
115
115
  return field.split('.').reduce((obj, key) => obj?.[key], row);
116
116
  }
117
117
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiTreeTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
118
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: FuiTreeTableComponent, isStandalone: true, selector: "fui-tree-table", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null }, sort: { classPropertyName: "sort", publicName: "sort", isSignal: true, isRequired: false, transformFunction: null }, filters: { classPropertyName: "filters", publicName: "filters", isSignal: true, isRequired: false, transformFunction: null }, enableRowHighlight: { classPropertyName: "enableRowHighlight", publicName: "enableRowHighlight", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, nodes: { classPropertyName: "nodes", publicName: "nodes", isSignal: true, isRequired: true, transformFunction: null }, loadChildren: { classPropertyName: "loadChildren", publicName: "loadChildren", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sortChange: "sortChange", filtersChange: "filtersChange", rowDblClick: "rowDblClick", rowExpand: "rowExpand", rowCollapse: "rowCollapse" }, host: { classAttribute: "fui-tree-table" }, ngImport: i0, template: "<div class=\"fui-tree-table__wrapper\">\r\n <table class=\"fui-tree-table__table\">\r\n <thead class=\"fui-tree-table__head\" [class.fui-tree-table__head--sticky]=\"config().headerSticky\">\r\n <tr class=\"fui-tree-table__header-row\">\r\n @for (header of config().headers; track header.field) {\r\n <th\r\n class=\"fui-tree-table__header-cell\"\r\n [class.fui-tree-table__header-cell--sortable]=\"header.hasSort\"\r\n (click)=\"header.hasSort ? onSortColumn(header.field) : null\"\r\n >\r\n <div class=\"fui-tree-table__header-content\">\r\n <span>{{ header.label }}</span>\r\n @if (header.hasSort) {\r\n @if (sort()?.field === header.field) {\r\n <fui-icon [name]=\"sort()?.direction === 'ASC' ? 'caret-up' : 'caret-down'\" size=\"sm\"></fui-icon>\r\n }\r\n }\r\n </div>\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody class=\"fui-tree-table__body\">\r\n @if (flatRows().length === 0) {\r\n <tr class=\"fui-tree-table__empty-row\">\r\n <td [attr.colspan]=\"config().headers.length\" class=\"fui-tree-table__empty-cell\">\r\n {{ resolvedEmptyMessage() }}\r\n </td>\r\n </tr>\r\n }\r\n @for (flatRow of flatRows(); track flatRow._flatIndex) {\r\n <tr\r\n class=\"fui-tree-table__row\"\r\n [class.fui-tree-table__row--selected]=\"flatRow.selected\"\r\n [class.fui-tree-table__row--disabled]=\"flatRow.disabled\"\r\n [class.fui-tree-table__row--highlight]=\"enableRowHighlight()\"\r\n [attr.aria-level]=\"flatRow.level + 1\"\r\n [attr.aria-expanded]=\"flatRow.expandable ? flatRow.expanded : null\"\r\n (dblclick)=\"rowDblClick.emit(flatRow.data)\"\r\n >\r\n @for (header of config().headers; track header.field) {\r\n <td class=\"fui-tree-table__cell\">\r\n @if (header.field === treeColumnField()) {\r\n <div class=\"fui-tree-table__tree-cell\" [style.padding-left.px]=\"flatRow.level * indentPx()\">\r\n <button\r\n class=\"fui-tree-table__expand-toggle\"\r\n [class.fui-tree-table__expand-toggle--hidden]=\"!flatRow.expandable\"\r\n (click)=\"onToggleRow(flatRow); $event.stopPropagation()\"\r\n type=\"button\"\r\n tabindex=\"-1\"\r\n >\r\n @if (flatRow.loading) {\r\n <fui-icon name=\"spinner\" [spin]=\"true\" size=\"sm\"></fui-icon>\r\n } @else {\r\n <fui-icon [name]=\"flatRow.expanded ? 'caret-down' : 'caret-right'\" size=\"sm\"></fui-icon>\r\n }\r\n </button>\r\n <span class=\"fui-tree-table__cell-text\">{{ getCellValue(flatRow.data, header.field) }}</span>\r\n </div>\r\n } @else {\r\n {{ getCellValue(flatRow.data, header.field) }}\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n</div>\r\n", styles: [".fui-tree-table{display:block;width:100%;font-family:var(--fui-font-family);font-size:var(--fui-font-size-03);color:var(--fui-text-primary)}.fui-tree-table__wrapper{overflow:auto;border:1px solid var(--fui-border-color);border-radius:var(--fui-border-radius-sm)}.fui-tree-table__table{width:100%;border-collapse:collapse}.fui-tree-table__head--sticky{position:sticky;top:0;z-index:1}.fui-tree-table__header-row{background-color:var(--fui-surface-card)}.fui-tree-table__header-cell{padding:12px 16px;text-align:left;font-weight:600;font-size:var(--fui-font-size-02);color:var(--fui-text-secondary);border-bottom:1px solid var(--fui-border-color);white-space:nowrap}.fui-tree-table__header-cell--sortable{cursor:pointer;-webkit-user-select:none;user-select:none}.fui-tree-table__header-cell--sortable:hover{background-color:var(--fui-surface-hover, var(--fui-black-5))}.fui-tree-table__header-content{display:flex;align-items:center;gap:4px}.fui-tree-table__row{border-bottom:1px solid var(--fui-border-color);transition:background-color var(--fui-duration-moderate-01) var(--fui-ease-standard)}.fui-tree-table__row--highlight:hover{background-color:var(--fui-surface-hover, var(--fui-black-5))}.fui-tree-table__row--selected{background-color:var(--fui-primary-10)}.fui-tree-table__row--disabled{opacity:.5;pointer-events:none}.fui-tree-table__cell{padding:8px 16px;vertical-align:middle}.fui-tree-table__tree-cell{display:flex;align-items:center;gap:4px}.fui-tree-table__expand-toggle{all:unset;display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;flex-shrink:0;border-radius:var(--fui-border-radius-sm);cursor:pointer}.fui-tree-table__expand-toggle--hidden{visibility:hidden}.fui-tree-table__expand-toggle:hover{background-color:var(--fui-surface-hover, var(--fui-black-10))}.fui-tree-table__cell-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fui-tree-table__empty-cell{padding:32px 16px;text-align:center;color:var(--fui-text-disabled)}\n"], dependencies: [{ kind: "component", type: FuiIconComponent, selector: "fui-icon", inputs: ["name", "size", "weight", "color", "ariaLabel", "spin", "pulse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
118
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: FuiTreeTableComponent, isStandalone: true, selector: "fui-tree-table", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null }, sort: { classPropertyName: "sort", publicName: "sort", isSignal: true, isRequired: false, transformFunction: null }, filters: { classPropertyName: "filters", publicName: "filters", isSignal: true, isRequired: false, transformFunction: null }, enableRowHighlight: { classPropertyName: "enableRowHighlight", publicName: "enableRowHighlight", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, nodes: { classPropertyName: "nodes", publicName: "nodes", isSignal: true, isRequired: true, transformFunction: null }, loadChildren: { classPropertyName: "loadChildren", publicName: "loadChildren", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sortChange: "sortChange", filtersChange: "filtersChange", rowDblClick: "rowDblClick", rowExpand: "rowExpand", rowCollapse: "rowCollapse" }, host: { classAttribute: "fui-tree-table" }, ngImport: i0, template: "<div class=\"fui-tree-table__wrapper\">\r\n <table class=\"fui-tree-table__table\">\r\n <thead class=\"fui-tree-table__head\" [class.fui-tree-table__head--sticky]=\"config().headerSticky\">\r\n <tr class=\"fui-tree-table__header-row\">\r\n @for (header of config().headers; track header.field) {\r\n <th\r\n class=\"fui-tree-table__header-cell\"\r\n [class.fui-tree-table__header-cell--sortable]=\"header.hasSort\"\r\n (click)=\"header.hasSort ? onSortColumn(header.field) : null\"\r\n >\r\n <div class=\"fui-tree-table__header-content\">\r\n <span>{{ header.label }}</span>\r\n @if (header.hasSort) {\r\n @if (sort()?.field === header.field) {\r\n <fui-icon [name]=\"sort()?.direction === 'ASC' ? 'caret-up' : 'caret-down'\" size=\"sm\"></fui-icon>\r\n }\r\n }\r\n </div>\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody class=\"fui-tree-table__body\">\r\n @if (flatRows().length === 0) {\r\n <tr class=\"fui-tree-table__empty-row\">\r\n <td [attr.colspan]=\"config().headers.length\" class=\"fui-tree-table__empty-cell\">\r\n {{ resolvedEmptyMessage() }}\r\n </td>\r\n </tr>\r\n }\r\n @for (flatRow of flatRows(); track flatRow._flatIndex) {\r\n <tr\r\n class=\"fui-tree-table__row\"\r\n [class.fui-tree-table__row--selected]=\"flatRow.selected\"\r\n [class.fui-tree-table__row--disabled]=\"flatRow.disabled\"\r\n [class.fui-tree-table__row--highlight]=\"enableRowHighlight()\"\r\n [attr.aria-level]=\"flatRow.level + 1\"\r\n [attr.aria-expanded]=\"flatRow.expandable ? flatRow.expanded : null\"\r\n (dblclick)=\"rowDblClick.emit(flatRow.data)\"\r\n >\r\n @for (header of config().headers; track header.field) {\r\n <td class=\"fui-tree-table__cell\">\r\n @if (header.field === treeColumnField()) {\r\n <div class=\"fui-tree-table__tree-cell\" [style.padding-left.px]=\"flatRow.level * indentPx()\">\r\n <button\r\n class=\"fui-tree-table__expand-toggle\"\r\n [class.fui-tree-table__expand-toggle--hidden]=\"!flatRow.expandable\"\r\n (click)=\"onToggleRow(flatRow); $event.stopPropagation()\"\r\n type=\"button\"\r\n tabindex=\"-1\"\r\n >\r\n @if (flatRow.loading) {\r\n <fui-icon name=\"spinner\" [spin]=\"true\" size=\"sm\"></fui-icon>\r\n } @else {\r\n <fui-icon [name]=\"flatRow.expanded ? 'caret-down' : 'caret-right'\" size=\"sm\"></fui-icon>\r\n }\r\n </button>\r\n <span class=\"fui-tree-table__cell-text\">{{ getCellValue(flatRow.data, header.field) }}</span>\r\n </div>\r\n } @else {\r\n {{ getCellValue(flatRow.data, header.field) }}\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n</div>\r\n", styles: [".fui-tree-table{display:block;width:100%;font-family:var(--fui-font-family);font-size:var(--fui-text-md);color:var(--fui-text-primary)}.fui-tree-table__wrapper{overflow:auto;border:1px solid var(--fui-border-default);border-radius:var(--fui-radius-sm)}.fui-tree-table__table{width:100%;border-collapse:collapse}.fui-tree-table__head--sticky{position:sticky;top:0;z-index:1}.fui-tree-table__header-row{background-color:var(--fui-bg-default)}.fui-tree-table__header-cell{padding:12px 16px;text-align:left;font-weight:600;font-size:var(--fui-text-base);color:var(--fui-text-secondary);border-bottom:1px solid var(--fui-border-default);white-space:nowrap}.fui-tree-table__header-cell--sortable{cursor:pointer;-webkit-user-select:none;user-select:none}.fui-tree-table__header-cell--sortable:hover{background-color:var(--fui-bg-subtle)}.fui-tree-table__header-content{display:flex;align-items:center;gap:4px}.fui-tree-table__row{border-bottom:1px solid var(--fui-border-default);transition:background-color var(--fui-duration-base) var(--fui-ease-in-out)}.fui-tree-table__row--highlight:hover{background-color:var(--fui-bg-subtle)}.fui-tree-table__row--selected{background-color:var(--fui-primary-10)}.fui-tree-table__row--disabled{opacity:.5;pointer-events:none}.fui-tree-table__cell{padding:8px 16px;vertical-align:middle}.fui-tree-table__tree-cell{display:flex;align-items:center;gap:4px}.fui-tree-table__expand-toggle{all:unset;display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;flex-shrink:0;border-radius:var(--fui-radius-sm);cursor:pointer}.fui-tree-table__expand-toggle--hidden{visibility:hidden}.fui-tree-table__expand-toggle:hover{background-color:var(--fui-bg-subtle)}.fui-tree-table__cell-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fui-tree-table__empty-cell{padding:32px 16px;text-align:center;color:var(--fui-text-disabled)}\n"], dependencies: [{ kind: "component", type: FuiIconComponent, selector: "fui-icon", inputs: ["name", "size", "weight", "color", "ariaLabel", "spin", "pulse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
119
119
  }
120
120
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiTreeTableComponent, decorators: [{
121
121
  type: Component,
122
122
  args: [{ selector: 'fui-tree-table', standalone: true, imports: [FuiIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
123
123
  class: 'fui-tree-table',
124
- }, template: "<div class=\"fui-tree-table__wrapper\">\r\n <table class=\"fui-tree-table__table\">\r\n <thead class=\"fui-tree-table__head\" [class.fui-tree-table__head--sticky]=\"config().headerSticky\">\r\n <tr class=\"fui-tree-table__header-row\">\r\n @for (header of config().headers; track header.field) {\r\n <th\r\n class=\"fui-tree-table__header-cell\"\r\n [class.fui-tree-table__header-cell--sortable]=\"header.hasSort\"\r\n (click)=\"header.hasSort ? onSortColumn(header.field) : null\"\r\n >\r\n <div class=\"fui-tree-table__header-content\">\r\n <span>{{ header.label }}</span>\r\n @if (header.hasSort) {\r\n @if (sort()?.field === header.field) {\r\n <fui-icon [name]=\"sort()?.direction === 'ASC' ? 'caret-up' : 'caret-down'\" size=\"sm\"></fui-icon>\r\n }\r\n }\r\n </div>\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody class=\"fui-tree-table__body\">\r\n @if (flatRows().length === 0) {\r\n <tr class=\"fui-tree-table__empty-row\">\r\n <td [attr.colspan]=\"config().headers.length\" class=\"fui-tree-table__empty-cell\">\r\n {{ resolvedEmptyMessage() }}\r\n </td>\r\n </tr>\r\n }\r\n @for (flatRow of flatRows(); track flatRow._flatIndex) {\r\n <tr\r\n class=\"fui-tree-table__row\"\r\n [class.fui-tree-table__row--selected]=\"flatRow.selected\"\r\n [class.fui-tree-table__row--disabled]=\"flatRow.disabled\"\r\n [class.fui-tree-table__row--highlight]=\"enableRowHighlight()\"\r\n [attr.aria-level]=\"flatRow.level + 1\"\r\n [attr.aria-expanded]=\"flatRow.expandable ? flatRow.expanded : null\"\r\n (dblclick)=\"rowDblClick.emit(flatRow.data)\"\r\n >\r\n @for (header of config().headers; track header.field) {\r\n <td class=\"fui-tree-table__cell\">\r\n @if (header.field === treeColumnField()) {\r\n <div class=\"fui-tree-table__tree-cell\" [style.padding-left.px]=\"flatRow.level * indentPx()\">\r\n <button\r\n class=\"fui-tree-table__expand-toggle\"\r\n [class.fui-tree-table__expand-toggle--hidden]=\"!flatRow.expandable\"\r\n (click)=\"onToggleRow(flatRow); $event.stopPropagation()\"\r\n type=\"button\"\r\n tabindex=\"-1\"\r\n >\r\n @if (flatRow.loading) {\r\n <fui-icon name=\"spinner\" [spin]=\"true\" size=\"sm\"></fui-icon>\r\n } @else {\r\n <fui-icon [name]=\"flatRow.expanded ? 'caret-down' : 'caret-right'\" size=\"sm\"></fui-icon>\r\n }\r\n </button>\r\n <span class=\"fui-tree-table__cell-text\">{{ getCellValue(flatRow.data, header.field) }}</span>\r\n </div>\r\n } @else {\r\n {{ getCellValue(flatRow.data, header.field) }}\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n</div>\r\n", styles: [".fui-tree-table{display:block;width:100%;font-family:var(--fui-font-family);font-size:var(--fui-font-size-03);color:var(--fui-text-primary)}.fui-tree-table__wrapper{overflow:auto;border:1px solid var(--fui-border-color);border-radius:var(--fui-border-radius-sm)}.fui-tree-table__table{width:100%;border-collapse:collapse}.fui-tree-table__head--sticky{position:sticky;top:0;z-index:1}.fui-tree-table__header-row{background-color:var(--fui-surface-card)}.fui-tree-table__header-cell{padding:12px 16px;text-align:left;font-weight:600;font-size:var(--fui-font-size-02);color:var(--fui-text-secondary);border-bottom:1px solid var(--fui-border-color);white-space:nowrap}.fui-tree-table__header-cell--sortable{cursor:pointer;-webkit-user-select:none;user-select:none}.fui-tree-table__header-cell--sortable:hover{background-color:var(--fui-surface-hover, var(--fui-black-5))}.fui-tree-table__header-content{display:flex;align-items:center;gap:4px}.fui-tree-table__row{border-bottom:1px solid var(--fui-border-color);transition:background-color var(--fui-duration-moderate-01) var(--fui-ease-standard)}.fui-tree-table__row--highlight:hover{background-color:var(--fui-surface-hover, var(--fui-black-5))}.fui-tree-table__row--selected{background-color:var(--fui-primary-10)}.fui-tree-table__row--disabled{opacity:.5;pointer-events:none}.fui-tree-table__cell{padding:8px 16px;vertical-align:middle}.fui-tree-table__tree-cell{display:flex;align-items:center;gap:4px}.fui-tree-table__expand-toggle{all:unset;display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;flex-shrink:0;border-radius:var(--fui-border-radius-sm);cursor:pointer}.fui-tree-table__expand-toggle--hidden{visibility:hidden}.fui-tree-table__expand-toggle:hover{background-color:var(--fui-surface-hover, var(--fui-black-10))}.fui-tree-table__cell-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fui-tree-table__empty-cell{padding:32px 16px;text-align:center;color:var(--fui-text-disabled)}\n"] }]
124
+ }, template: "<div class=\"fui-tree-table__wrapper\">\r\n <table class=\"fui-tree-table__table\">\r\n <thead class=\"fui-tree-table__head\" [class.fui-tree-table__head--sticky]=\"config().headerSticky\">\r\n <tr class=\"fui-tree-table__header-row\">\r\n @for (header of config().headers; track header.field) {\r\n <th\r\n class=\"fui-tree-table__header-cell\"\r\n [class.fui-tree-table__header-cell--sortable]=\"header.hasSort\"\r\n (click)=\"header.hasSort ? onSortColumn(header.field) : null\"\r\n >\r\n <div class=\"fui-tree-table__header-content\">\r\n <span>{{ header.label }}</span>\r\n @if (header.hasSort) {\r\n @if (sort()?.field === header.field) {\r\n <fui-icon [name]=\"sort()?.direction === 'ASC' ? 'caret-up' : 'caret-down'\" size=\"sm\"></fui-icon>\r\n }\r\n }\r\n </div>\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody class=\"fui-tree-table__body\">\r\n @if (flatRows().length === 0) {\r\n <tr class=\"fui-tree-table__empty-row\">\r\n <td [attr.colspan]=\"config().headers.length\" class=\"fui-tree-table__empty-cell\">\r\n {{ resolvedEmptyMessage() }}\r\n </td>\r\n </tr>\r\n }\r\n @for (flatRow of flatRows(); track flatRow._flatIndex) {\r\n <tr\r\n class=\"fui-tree-table__row\"\r\n [class.fui-tree-table__row--selected]=\"flatRow.selected\"\r\n [class.fui-tree-table__row--disabled]=\"flatRow.disabled\"\r\n [class.fui-tree-table__row--highlight]=\"enableRowHighlight()\"\r\n [attr.aria-level]=\"flatRow.level + 1\"\r\n [attr.aria-expanded]=\"flatRow.expandable ? flatRow.expanded : null\"\r\n (dblclick)=\"rowDblClick.emit(flatRow.data)\"\r\n >\r\n @for (header of config().headers; track header.field) {\r\n <td class=\"fui-tree-table__cell\">\r\n @if (header.field === treeColumnField()) {\r\n <div class=\"fui-tree-table__tree-cell\" [style.padding-left.px]=\"flatRow.level * indentPx()\">\r\n <button\r\n class=\"fui-tree-table__expand-toggle\"\r\n [class.fui-tree-table__expand-toggle--hidden]=\"!flatRow.expandable\"\r\n (click)=\"onToggleRow(flatRow); $event.stopPropagation()\"\r\n type=\"button\"\r\n tabindex=\"-1\"\r\n >\r\n @if (flatRow.loading) {\r\n <fui-icon name=\"spinner\" [spin]=\"true\" size=\"sm\"></fui-icon>\r\n } @else {\r\n <fui-icon [name]=\"flatRow.expanded ? 'caret-down' : 'caret-right'\" size=\"sm\"></fui-icon>\r\n }\r\n </button>\r\n <span class=\"fui-tree-table__cell-text\">{{ getCellValue(flatRow.data, header.field) }}</span>\r\n </div>\r\n } @else {\r\n {{ getCellValue(flatRow.data, header.field) }}\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n</div>\r\n", styles: [".fui-tree-table{display:block;width:100%;font-family:var(--fui-font-family);font-size:var(--fui-text-md);color:var(--fui-text-primary)}.fui-tree-table__wrapper{overflow:auto;border:1px solid var(--fui-border-default);border-radius:var(--fui-radius-sm)}.fui-tree-table__table{width:100%;border-collapse:collapse}.fui-tree-table__head--sticky{position:sticky;top:0;z-index:1}.fui-tree-table__header-row{background-color:var(--fui-bg-default)}.fui-tree-table__header-cell{padding:12px 16px;text-align:left;font-weight:600;font-size:var(--fui-text-base);color:var(--fui-text-secondary);border-bottom:1px solid var(--fui-border-default);white-space:nowrap}.fui-tree-table__header-cell--sortable{cursor:pointer;-webkit-user-select:none;user-select:none}.fui-tree-table__header-cell--sortable:hover{background-color:var(--fui-bg-subtle)}.fui-tree-table__header-content{display:flex;align-items:center;gap:4px}.fui-tree-table__row{border-bottom:1px solid var(--fui-border-default);transition:background-color var(--fui-duration-base) var(--fui-ease-in-out)}.fui-tree-table__row--highlight:hover{background-color:var(--fui-bg-subtle)}.fui-tree-table__row--selected{background-color:var(--fui-primary-10)}.fui-tree-table__row--disabled{opacity:.5;pointer-events:none}.fui-tree-table__cell{padding:8px 16px;vertical-align:middle}.fui-tree-table__tree-cell{display:flex;align-items:center;gap:4px}.fui-tree-table__expand-toggle{all:unset;display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;flex-shrink:0;border-radius:var(--fui-radius-sm);cursor:pointer}.fui-tree-table__expand-toggle--hidden{visibility:hidden}.fui-tree-table__expand-toggle:hover{background-color:var(--fui-bg-subtle)}.fui-tree-table__cell-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fui-tree-table__empty-cell{padding:32px 16px;text-align:center;color:var(--fui-text-disabled)}\n"] }]
125
125
  }], ctorParameters: () => [], propDecorators: { config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: true }] }], sort: [{ type: i0.Input, args: [{ isSignal: true, alias: "sort", required: false }] }], filters: [{ type: i0.Input, args: [{ isSignal: true, alias: "filters", required: false }] }], enableRowHighlight: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableRowHighlight", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], nodes: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodes", required: true }] }], loadChildren: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadChildren", required: false }] }], sortChange: [{ type: i0.Output, args: ["sortChange"] }], filtersChange: [{ type: i0.Output, args: ["filtersChange"] }], rowDblClick: [{ type: i0.Output, args: ["rowDblClick"] }], rowExpand: [{ type: i0.Output, args: ["rowExpand"] }], rowCollapse: [{ type: i0.Output, args: ["rowCollapse"] }] } });
126
126
 
127
127
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"raintonic-formaui-components-tree-table.mjs","sources":["../../../lib/components/tree-table/tree-table.intl.ts","../../../lib/components/tree-table/fui-tree-table.component.ts","../../../lib/components/tree-table/fui-tree-table.component.html","../../../lib/components/tree-table/raintonic-formaui-components-tree-table.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\r\nimport { FuiIntlBase } from '@raintonic/formaui/core';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class FuiTreeTableIntl extends FuiIntlBase {\r\n emptyMessage = 'No data available';\r\n}\r\n","import {\r\n Component,\r\n ChangeDetectionStrategy,\r\n ChangeDetectorRef,\r\n ViewEncapsulation,\r\n inject,\r\n input,\r\n output,\r\n signal,\r\n computed,\r\n} from '@angular/core';\r\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\r\nimport { Observable } from 'rxjs';\r\nimport { FuiIconComponent } from '@raintonic/formaui/components/icon';\r\nimport {\r\n FuiTreeTableConfig,\r\n FuiTreeTableNode,\r\n FuiFlatTreeTableRow,\r\n FuiTreeTableColumnFilter,\r\n FuiTreeTableRowEvent,\r\n} from './tree-table.types';\r\nimport { FuiTreeTableIntl } from './tree-table.intl';\r\n\r\n@Component({\r\n selector: 'fui-tree-table',\r\n standalone: true,\r\n imports: [FuiIconComponent],\r\n templateUrl: './fui-tree-table.component.html',\r\n styleUrl: './fui-tree-table.component.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.None,\r\n host: {\r\n class: 'fui-tree-table',\r\n },\r\n})\r\nexport class FuiTreeTableComponent<T = any> {\r\n readonly intl = inject(FuiTreeTableIntl);\r\n private readonly _cdr = inject(ChangeDetectorRef);\r\n\r\n constructor() {\r\n this.intl.changes.pipe(takeUntilDestroyed()).subscribe(() => {\r\n this._refreshCounter.update((v) => v + 1);\r\n this._cdr.markForCheck();\r\n });\r\n }\r\n\r\n // Config & headers\r\n readonly config = input.required<FuiTreeTableConfig>();\r\n readonly sort = input<{ field: string; direction: 'ASC' | 'DESC' } | null>(null);\r\n readonly filters = input<FuiTreeTableColumnFilter[]>([]);\r\n readonly enableRowHighlight = input(false);\r\n /**\r\n * Message shown when the tree is empty.\r\n * Default comes from FuiTreeTableIntl.emptyMessage ('No data available').\r\n */\r\n readonly emptyMessage = input<string | undefined>(undefined);\r\n\r\n /** Resolved empty-state message: input override → intl default. */\r\n readonly resolvedEmptyMessage = computed(() => {\r\n this._refreshCounter();\r\n return this.emptyMessage() ?? this.intl.emptyMessage;\r\n });\r\n\r\n // Tree-specific inputs\r\n readonly nodes = input.required<FuiTreeTableNode<T>[]>();\r\n readonly loadChildren = input<((node: FuiTreeTableNode<T>) => Observable<FuiTreeTableNode<T>[]>) | null>(null);\r\n\r\n // Outputs\r\n readonly sortChange = output<{ field: string; direction: 'ASC' | 'DESC' } | null>();\r\n readonly filtersChange = output<FuiTreeTableColumnFilter[]>();\r\n readonly rowDblClick = output<T>();\r\n readonly rowExpand = output<FuiTreeTableRowEvent<T>>();\r\n readonly rowCollapse = output<FuiTreeTableRowEvent<T>>();\r\n\r\n // Internal\r\n private readonly _refreshCounter = signal(0);\r\n\r\n readonly flatRows = computed(() => {\r\n this._refreshCounter();\r\n return this._flattenNodes(this.nodes());\r\n });\r\n\r\n readonly treeColumnField = computed(() => {\r\n const cfg = this.config();\r\n return cfg.treeColumn ?? cfg.headers[0]?.field ?? '';\r\n });\r\n\r\n readonly indentPx = computed(() => this.config().indentPx ?? 24);\r\n\r\n // Methods\r\n private _flattenNodes(nodes: FuiTreeTableNode<T>[]): FuiFlatTreeTableRow<T>[] {\r\n const result: FuiFlatTreeTableRow<T>[] = [];\r\n let flatIndex = 0;\r\n const recurse = (nodeList: FuiTreeTableNode<T>[], level: number): void => {\r\n for (const node of nodeList) {\r\n const expandable =\r\n !node.leaf && (Array.isArray(node.children) ? node.children.length > 0 : node.children != null);\r\n result.push({\r\n data: node.data,\r\n origin: node,\r\n level,\r\n expandable,\r\n expanded: node.expanded ?? false,\r\n selected: node.selected ?? false,\r\n disabled: node.disabled ?? false,\r\n loading: false,\r\n _flatIndex: flatIndex++,\r\n });\r\n if (node.expanded && Array.isArray(node.children)) {\r\n recurse(node.children, level + 1);\r\n }\r\n }\r\n };\r\n recurse(nodes, 0);\r\n return result;\r\n }\r\n\r\n onToggleRow(flatRow: FuiFlatTreeTableRow<T>): void {\r\n const node = flatRow.origin;\r\n if (flatRow.expanded) {\r\n node.expanded = false;\r\n this.rowCollapse.emit({ row: node, flatRow });\r\n } else {\r\n node.expanded = true;\r\n this.rowExpand.emit({ row: node, flatRow });\r\n }\r\n this._refreshCounter.update((c) => c + 1);\r\n }\r\n\r\n onSortColumn(field: string): void {\r\n const current = this.sort();\r\n if (current?.field === field) {\r\n if (current.direction === 'ASC') {\r\n this.sortChange.emit({ field, direction: 'DESC' });\r\n } else {\r\n this.sortChange.emit(null);\r\n }\r\n } else {\r\n this.sortChange.emit({ field, direction: 'ASC' });\r\n }\r\n }\r\n\r\n getCellValue(row: T, field: string): any {\r\n // Support dot-notation fields like 'address.city'\r\n return field.split('.').reduce((obj: any, key) => obj?.[key], row);\r\n }\r\n}\r\n","<div class=\"fui-tree-table__wrapper\">\r\n <table class=\"fui-tree-table__table\">\r\n <thead class=\"fui-tree-table__head\" [class.fui-tree-table__head--sticky]=\"config().headerSticky\">\r\n <tr class=\"fui-tree-table__header-row\">\r\n @for (header of config().headers; track header.field) {\r\n <th\r\n class=\"fui-tree-table__header-cell\"\r\n [class.fui-tree-table__header-cell--sortable]=\"header.hasSort\"\r\n (click)=\"header.hasSort ? onSortColumn(header.field) : null\"\r\n >\r\n <div class=\"fui-tree-table__header-content\">\r\n <span>{{ header.label }}</span>\r\n @if (header.hasSort) {\r\n @if (sort()?.field === header.field) {\r\n <fui-icon [name]=\"sort()?.direction === 'ASC' ? 'caret-up' : 'caret-down'\" size=\"sm\"></fui-icon>\r\n }\r\n }\r\n </div>\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody class=\"fui-tree-table__body\">\r\n @if (flatRows().length === 0) {\r\n <tr class=\"fui-tree-table__empty-row\">\r\n <td [attr.colspan]=\"config().headers.length\" class=\"fui-tree-table__empty-cell\">\r\n {{ resolvedEmptyMessage() }}\r\n </td>\r\n </tr>\r\n }\r\n @for (flatRow of flatRows(); track flatRow._flatIndex) {\r\n <tr\r\n class=\"fui-tree-table__row\"\r\n [class.fui-tree-table__row--selected]=\"flatRow.selected\"\r\n [class.fui-tree-table__row--disabled]=\"flatRow.disabled\"\r\n [class.fui-tree-table__row--highlight]=\"enableRowHighlight()\"\r\n [attr.aria-level]=\"flatRow.level + 1\"\r\n [attr.aria-expanded]=\"flatRow.expandable ? flatRow.expanded : null\"\r\n (dblclick)=\"rowDblClick.emit(flatRow.data)\"\r\n >\r\n @for (header of config().headers; track header.field) {\r\n <td class=\"fui-tree-table__cell\">\r\n @if (header.field === treeColumnField()) {\r\n <div class=\"fui-tree-table__tree-cell\" [style.padding-left.px]=\"flatRow.level * indentPx()\">\r\n <button\r\n class=\"fui-tree-table__expand-toggle\"\r\n [class.fui-tree-table__expand-toggle--hidden]=\"!flatRow.expandable\"\r\n (click)=\"onToggleRow(flatRow); $event.stopPropagation()\"\r\n type=\"button\"\r\n tabindex=\"-1\"\r\n >\r\n @if (flatRow.loading) {\r\n <fui-icon name=\"spinner\" [spin]=\"true\" size=\"sm\"></fui-icon>\r\n } @else {\r\n <fui-icon [name]=\"flatRow.expanded ? 'caret-down' : 'caret-right'\" size=\"sm\"></fui-icon>\r\n }\r\n </button>\r\n <span class=\"fui-tree-table__cell-text\">{{ getCellValue(flatRow.data, header.field) }}</span>\r\n </div>\r\n } @else {\r\n {{ getCellValue(flatRow.data, header.field) }}\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n</div>\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"raintonic-formaui-components-tree-table.mjs","sources":["../../../lib/components/tree-table/tree-table.intl.ts","../../../lib/components/tree-table/fui-tree-table.component.ts","../../../lib/components/tree-table/fui-tree-table.component.html","../../../lib/components/tree-table/raintonic-formaui-components-tree-table.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\r\nimport { FuiIntlBase } from '@raintonic/formaui/core';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class FuiTreeTableIntl extends FuiIntlBase {\r\n emptyMessage = 'No data available';\r\n}\r\n","import {\r\n Component,\r\n ChangeDetectionStrategy,\r\n ChangeDetectorRef,\r\n ViewEncapsulation,\r\n inject,\r\n input,\r\n output,\r\n signal,\r\n computed,\r\n} from '@angular/core';\r\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\r\nimport { Observable } from 'rxjs';\r\nimport { FuiIconComponent } from '@raintonic/formaui/components/icon';\r\nimport {\r\n FuiTreeTableConfig,\r\n FuiTreeTableNode,\r\n FuiFlatTreeTableRow,\r\n FuiTreeTableColumnFilter,\r\n FuiTreeTableRowEvent,\r\n} from './tree-table.types';\r\nimport { FuiTreeTableIntl } from './tree-table.intl';\r\n\r\n@Component({\r\n selector: 'fui-tree-table',\r\n standalone: true,\r\n imports: [FuiIconComponent],\r\n templateUrl: './fui-tree-table.component.html',\r\n styleUrl: './fui-tree-table.component.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.None,\r\n host: {\r\n class: 'fui-tree-table',\r\n },\r\n})\r\nexport class FuiTreeTableComponent<T = any> {\r\n readonly intl = inject(FuiTreeTableIntl);\r\n private readonly _cdr = inject(ChangeDetectorRef);\r\n\r\n constructor() {\r\n this.intl.changes.pipe(takeUntilDestroyed()).subscribe(() => {\r\n this._refreshCounter.update((v) => v + 1);\r\n this._cdr.markForCheck();\r\n });\r\n }\r\n\r\n // Config & headers\r\n readonly config = input.required<FuiTreeTableConfig>();\r\n readonly sort = input<{ field: string; direction: 'ASC' | 'DESC' } | null>(null);\r\n readonly filters = input<FuiTreeTableColumnFilter[]>([]);\r\n readonly enableRowHighlight = input(false);\r\n /**\r\n * Message shown when the tree is empty.\r\n * Default comes from FuiTreeTableIntl.emptyMessage ('No data available').\r\n */\r\n readonly emptyMessage = input<string | undefined>(undefined);\r\n\r\n /** Resolved empty-state message: input override → intl default. */\r\n readonly resolvedEmptyMessage = computed(() => {\r\n this._refreshCounter();\r\n return this.emptyMessage() ?? this.intl.emptyMessage;\r\n });\r\n\r\n // Tree-specific inputs\r\n readonly nodes = input.required<FuiTreeTableNode<T>[]>();\r\n readonly loadChildren = input<((node: FuiTreeTableNode<T>) => Observable<FuiTreeTableNode<T>[]>) | null>(null);\r\n\r\n // Outputs\r\n readonly sortChange = output<{ field: string; direction: 'ASC' | 'DESC' } | null>();\r\n readonly filtersChange = output<FuiTreeTableColumnFilter[]>();\r\n readonly rowDblClick = output<T>();\r\n readonly rowExpand = output<FuiTreeTableRowEvent<T>>();\r\n readonly rowCollapse = output<FuiTreeTableRowEvent<T>>();\r\n\r\n // Internal\r\n private readonly _refreshCounter = signal(0);\r\n\r\n readonly flatRows = computed(() => {\r\n this._refreshCounter();\r\n return this._flattenNodes(this.nodes());\r\n });\r\n\r\n readonly treeColumnField = computed(() => {\r\n const cfg = this.config();\r\n return cfg.treeColumn ?? cfg.headers[0]?.field ?? '';\r\n });\r\n\r\n readonly indentPx = computed(() => this.config().indentPx ?? 24);\r\n\r\n // Methods\r\n private _flattenNodes(nodes: FuiTreeTableNode<T>[]): FuiFlatTreeTableRow<T>[] {\r\n const result: FuiFlatTreeTableRow<T>[] = [];\r\n let flatIndex = 0;\r\n const recurse = (nodeList: FuiTreeTableNode<T>[], level: number): void => {\r\n for (const node of nodeList) {\r\n const expandable =\r\n !node.leaf && (Array.isArray(node.children) ? node.children.length > 0 : node.children != null);\r\n result.push({\r\n data: node.data,\r\n origin: node,\r\n level,\r\n expandable,\r\n expanded: node.expanded ?? false,\r\n selected: node.selected ?? false,\r\n disabled: node.disabled ?? false,\r\n loading: false,\r\n _flatIndex: flatIndex++,\r\n });\r\n if (node.expanded && Array.isArray(node.children)) {\r\n recurse(node.children, level + 1);\r\n }\r\n }\r\n };\r\n recurse(nodes, 0);\r\n return result;\r\n }\r\n\r\n onToggleRow(flatRow: FuiFlatTreeTableRow<T>): void {\r\n const node = flatRow.origin;\r\n if (flatRow.expanded) {\r\n node.expanded = false;\r\n this.rowCollapse.emit({ row: node, flatRow });\r\n } else {\r\n node.expanded = true;\r\n this.rowExpand.emit({ row: node, flatRow });\r\n }\r\n this._refreshCounter.update((c) => c + 1);\r\n }\r\n\r\n onSortColumn(field: string): void {\r\n const current = this.sort();\r\n if (current?.field === field) {\r\n if (current.direction === 'ASC') {\r\n this.sortChange.emit({ field, direction: 'DESC' });\r\n } else {\r\n this.sortChange.emit(null);\r\n }\r\n } else {\r\n this.sortChange.emit({ field, direction: 'ASC' });\r\n }\r\n }\r\n\r\n getCellValue(row: T, field: string): any {\r\n // Support dot-notation fields like 'address.city'\r\n return field.split('.').reduce((obj: any, key) => obj?.[key], row);\r\n }\r\n}\r\n","<div class=\"fui-tree-table__wrapper\">\r\n <table class=\"fui-tree-table__table\">\r\n <thead class=\"fui-tree-table__head\" [class.fui-tree-table__head--sticky]=\"config().headerSticky\">\r\n <tr class=\"fui-tree-table__header-row\">\r\n @for (header of config().headers; track header.field) {\r\n <th\r\n class=\"fui-tree-table__header-cell\"\r\n [class.fui-tree-table__header-cell--sortable]=\"header.hasSort\"\r\n (click)=\"header.hasSort ? onSortColumn(header.field) : null\"\r\n >\r\n <div class=\"fui-tree-table__header-content\">\r\n <span>{{ header.label }}</span>\r\n @if (header.hasSort) {\r\n @if (sort()?.field === header.field) {\r\n <fui-icon [name]=\"sort()?.direction === 'ASC' ? 'caret-up' : 'caret-down'\" size=\"sm\"></fui-icon>\r\n }\r\n }\r\n </div>\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody class=\"fui-tree-table__body\">\r\n @if (flatRows().length === 0) {\r\n <tr class=\"fui-tree-table__empty-row\">\r\n <td [attr.colspan]=\"config().headers.length\" class=\"fui-tree-table__empty-cell\">\r\n {{ resolvedEmptyMessage() }}\r\n </td>\r\n </tr>\r\n }\r\n @for (flatRow of flatRows(); track flatRow._flatIndex) {\r\n <tr\r\n class=\"fui-tree-table__row\"\r\n [class.fui-tree-table__row--selected]=\"flatRow.selected\"\r\n [class.fui-tree-table__row--disabled]=\"flatRow.disabled\"\r\n [class.fui-tree-table__row--highlight]=\"enableRowHighlight()\"\r\n [attr.aria-level]=\"flatRow.level + 1\"\r\n [attr.aria-expanded]=\"flatRow.expandable ? flatRow.expanded : null\"\r\n (dblclick)=\"rowDblClick.emit(flatRow.data)\"\r\n >\r\n @for (header of config().headers; track header.field) {\r\n <td class=\"fui-tree-table__cell\">\r\n @if (header.field === treeColumnField()) {\r\n <div class=\"fui-tree-table__tree-cell\" [style.padding-left.px]=\"flatRow.level * indentPx()\">\r\n <button\r\n class=\"fui-tree-table__expand-toggle\"\r\n [class.fui-tree-table__expand-toggle--hidden]=\"!flatRow.expandable\"\r\n (click)=\"onToggleRow(flatRow); $event.stopPropagation()\"\r\n type=\"button\"\r\n tabindex=\"-1\"\r\n >\r\n @if (flatRow.loading) {\r\n <fui-icon name=\"spinner\" [spin]=\"true\" size=\"sm\"></fui-icon>\r\n } @else {\r\n <fui-icon [name]=\"flatRow.expanded ? 'caret-down' : 'caret-right'\" size=\"sm\"></fui-icon>\r\n }\r\n </button>\r\n <span class=\"fui-tree-table__cell-text\">{{ getCellValue(flatRow.data, header.field) }}</span>\r\n </div>\r\n } @else {\r\n {{ getCellValue(flatRow.data, header.field) }}\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n</div>\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -35,7 +35,7 @@ class FuiTreeNodeComponent {
35
35
  checkboxChange = output();
36
36
  indentPx = 24;
37
37
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiTreeNodeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
38
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: FuiTreeNodeComponent, isStandalone: true, selector: "fui-tree-node", inputs: { flatNode: { classPropertyName: "flatNode", publicName: "flatNode", isSignal: true, isRequired: true, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, nodeTemplate: { classPropertyName: "nodeTemplate", publicName: "nodeTemplate", isSignal: true, isRequired: false, transformFunction: null }, checkboxState: { classPropertyName: "checkboxState", publicName: "checkboxState", isSignal: true, isRequired: false, transformFunction: null }, focused: { classPropertyName: "focused", publicName: "focused", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { toggle: "toggle", select: "select", checkboxChange: "checkboxChange" }, host: { attributes: { "role": "treeitem" }, properties: { "attr.aria-level": "flatNode().level + 1", "attr.aria-expanded": "flatNode().expandable ? flatNode().expanded : null", "attr.aria-selected": "flatNode().selected", "class.fui-tree-node--focused": "focused()", "class.fui-tree-node--selected": "flatNode().selected", "class.fui-tree-node--disabled": "flatNode().disabled", "style.padding-left.px": "flatNode().level * indentPx" }, classAttribute: "fui-tree-node" }, ngImport: i0, template: "<div class=\"fui-tree-node__content\">\r\n <!-- Expand/collapse toggle -->\r\n <button\r\n class=\"fui-tree-node__toggle\"\r\n [class.fui-tree-node__toggle--hidden]=\"!flatNode().expandable\"\r\n (click)=\"toggle.emit(); $event.stopPropagation()\"\r\n [attr.aria-label]=\"flatNode().expanded ? intl.collapseAriaLabel : intl.expandAriaLabel\"\r\n tabindex=\"-1\"\r\n type=\"button\"\r\n >\r\n @if (flatNode().loading) {\r\n <fui-icon name=\"spinner\" [spin]=\"true\" size=\"sm\"></fui-icon>\r\n } @else {\r\n <fui-icon [name]=\"flatNode().expanded ? 'caret-down' : 'caret-right'\" size=\"sm\"></fui-icon>\r\n }\r\n </button>\r\n\r\n <!-- Checkbox (only in checkbox mode) -->\r\n @if (selectionMode() === 'checkbox') {\r\n <fui-checkbox\r\n [checked]=\"checkboxState() === 'checked'\"\r\n [indeterminate]=\"checkboxState() === 'indeterminate'\"\r\n [disabled]=\"flatNode().disabled\"\r\n (change)=\"checkboxChange.emit()\"\r\n >\r\n </fui-checkbox>\r\n }\r\n\r\n <!-- Node content -->\r\n <div class=\"fui-tree-node__label\" (click)=\"select.emit()\" (dblclick)=\"toggle.emit()\">\r\n @if (nodeTemplate()) {\r\n <ng-container *ngTemplateOutlet=\"nodeTemplate()!; context: { $implicit: flatNode().origin, node: flatNode() }\">\r\n </ng-container>\r\n } @else {\r\n {{ flatNode().origin.data }}\r\n }\r\n </div>\r\n</div>\r\n", styles: [".fui-tree-node{display:flex;align-items:center;cursor:pointer;transition:background-color var(--fui-duration-moderate-01) var(--fui-ease-standard)}.fui-tree-node:hover{background-color:var(--fui-surface-hover, var(--fui-black-5))}.fui-tree-node--focused{outline:2px solid var(--fui-primary-60);outline-offset:-2px}.fui-tree-node--selected{background-color:var(--fui-primary-10)}.fui-tree-node--disabled{opacity:.5;pointer-events:none}.fui-tree-node__content{display:flex;align-items:center;width:100%;min-height:32px;padding:4px 8px;gap:4px}.fui-tree-node__toggle{all:unset;display:flex;align-items:center;justify-content:center;width:20px;height:20px;flex-shrink:0;border-radius:var(--fui-border-radius-sm);cursor:pointer}.fui-tree-node__toggle--hidden{visibility:hidden}.fui-tree-node__toggle:hover{background-color:var(--fui-surface-hover, var(--fui-black-10))}.fui-tree-node__label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: FuiIconComponent, selector: "fui-icon", inputs: ["name", "size", "weight", "color", "ariaLabel", "spin", "pulse"] }, { kind: "component", type: FuiCheckboxComponent, selector: "fui-checkbox", inputs: ["readonly", "checked", "disabled", "indeterminate", "required", "labelPosition", "name", "value", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "errorStateMatcher"], outputs: ["change", "indeterminateChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
38
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: FuiTreeNodeComponent, isStandalone: true, selector: "fui-tree-node", inputs: { flatNode: { classPropertyName: "flatNode", publicName: "flatNode", isSignal: true, isRequired: true, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, nodeTemplate: { classPropertyName: "nodeTemplate", publicName: "nodeTemplate", isSignal: true, isRequired: false, transformFunction: null }, checkboxState: { classPropertyName: "checkboxState", publicName: "checkboxState", isSignal: true, isRequired: false, transformFunction: null }, focused: { classPropertyName: "focused", publicName: "focused", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { toggle: "toggle", select: "select", checkboxChange: "checkboxChange" }, host: { attributes: { "role": "treeitem" }, properties: { "attr.aria-level": "flatNode().level + 1", "attr.aria-expanded": "flatNode().expandable ? flatNode().expanded : null", "attr.aria-selected": "flatNode().selected", "class.fui-tree-node--focused": "focused()", "class.fui-tree-node--selected": "flatNode().selected", "class.fui-tree-node--disabled": "flatNode().disabled", "style.padding-left.px": "flatNode().level * indentPx" }, classAttribute: "fui-tree-node" }, ngImport: i0, template: "<div class=\"fui-tree-node__content\">\r\n <!-- Expand/collapse toggle -->\r\n <button\r\n class=\"fui-tree-node__toggle\"\r\n [class.fui-tree-node__toggle--hidden]=\"!flatNode().expandable\"\r\n (click)=\"toggle.emit(); $event.stopPropagation()\"\r\n [attr.aria-label]=\"flatNode().expanded ? intl.collapseAriaLabel : intl.expandAriaLabel\"\r\n tabindex=\"-1\"\r\n type=\"button\"\r\n >\r\n @if (flatNode().loading) {\r\n <fui-icon name=\"spinner\" [spin]=\"true\" size=\"sm\"></fui-icon>\r\n } @else {\r\n <fui-icon [name]=\"flatNode().expanded ? 'caret-down' : 'caret-right'\" size=\"sm\"></fui-icon>\r\n }\r\n </button>\r\n\r\n <!-- Checkbox (only in checkbox mode) -->\r\n @if (selectionMode() === 'checkbox') {\r\n <fui-checkbox\r\n [checked]=\"checkboxState() === 'checked'\"\r\n [indeterminate]=\"checkboxState() === 'indeterminate'\"\r\n [disabled]=\"flatNode().disabled\"\r\n (change)=\"checkboxChange.emit()\"\r\n >\r\n </fui-checkbox>\r\n }\r\n\r\n <!-- Node content -->\r\n <div class=\"fui-tree-node__label\" (click)=\"select.emit()\" (dblclick)=\"toggle.emit()\">\r\n @if (nodeTemplate()) {\r\n <ng-container *ngTemplateOutlet=\"nodeTemplate()!; context: { $implicit: flatNode().origin, node: flatNode() }\">\r\n </ng-container>\r\n } @else {\r\n {{ flatNode().origin.data }}\r\n }\r\n </div>\r\n</div>\r\n", styles: [".fui-tree-node{display:flex;align-items:center;cursor:pointer;transition:background-color var(--fui-duration-base) var(--fui-ease-in-out)}.fui-tree-node:hover{background-color:var(--fui-bg-subtle)}.fui-tree-node--focused{outline:2px solid var(--fui-primary-60);outline-offset:-2px}.fui-tree-node--selected{background-color:var(--fui-primary-10)}.fui-tree-node--disabled{opacity:.5;pointer-events:none}.fui-tree-node__content{display:flex;align-items:center;width:100%;min-height:32px;padding:4px 8px;gap:4px}.fui-tree-node__toggle{all:unset;display:flex;align-items:center;justify-content:center;width:20px;height:20px;flex-shrink:0;border-radius:var(--fui-radius-sm);cursor:pointer}.fui-tree-node__toggle--hidden{visibility:hidden}.fui-tree-node__toggle:hover{background-color:var(--fui-bg-subtle)}.fui-tree-node__label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: FuiIconComponent, selector: "fui-icon", inputs: ["name", "size", "weight", "color", "ariaLabel", "spin", "pulse"] }, { kind: "component", type: FuiCheckboxComponent, selector: "fui-checkbox", inputs: ["readonly", "checked", "disabled", "indeterminate", "required", "labelPosition", "name", "value", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "errorStateMatcher"], outputs: ["change", "indeterminateChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
39
39
  }
40
40
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiTreeNodeComponent, decorators: [{
41
41
  type: Component,
@@ -49,7 +49,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImpor
49
49
  '[class.fui-tree-node--selected]': 'flatNode().selected',
50
50
  '[class.fui-tree-node--disabled]': 'flatNode().disabled',
51
51
  '[style.padding-left.px]': 'flatNode().level * indentPx',
52
- }, template: "<div class=\"fui-tree-node__content\">\r\n <!-- Expand/collapse toggle -->\r\n <button\r\n class=\"fui-tree-node__toggle\"\r\n [class.fui-tree-node__toggle--hidden]=\"!flatNode().expandable\"\r\n (click)=\"toggle.emit(); $event.stopPropagation()\"\r\n [attr.aria-label]=\"flatNode().expanded ? intl.collapseAriaLabel : intl.expandAriaLabel\"\r\n tabindex=\"-1\"\r\n type=\"button\"\r\n >\r\n @if (flatNode().loading) {\r\n <fui-icon name=\"spinner\" [spin]=\"true\" size=\"sm\"></fui-icon>\r\n } @else {\r\n <fui-icon [name]=\"flatNode().expanded ? 'caret-down' : 'caret-right'\" size=\"sm\"></fui-icon>\r\n }\r\n </button>\r\n\r\n <!-- Checkbox (only in checkbox mode) -->\r\n @if (selectionMode() === 'checkbox') {\r\n <fui-checkbox\r\n [checked]=\"checkboxState() === 'checked'\"\r\n [indeterminate]=\"checkboxState() === 'indeterminate'\"\r\n [disabled]=\"flatNode().disabled\"\r\n (change)=\"checkboxChange.emit()\"\r\n >\r\n </fui-checkbox>\r\n }\r\n\r\n <!-- Node content -->\r\n <div class=\"fui-tree-node__label\" (click)=\"select.emit()\" (dblclick)=\"toggle.emit()\">\r\n @if (nodeTemplate()) {\r\n <ng-container *ngTemplateOutlet=\"nodeTemplate()!; context: { $implicit: flatNode().origin, node: flatNode() }\">\r\n </ng-container>\r\n } @else {\r\n {{ flatNode().origin.data }}\r\n }\r\n </div>\r\n</div>\r\n", styles: [".fui-tree-node{display:flex;align-items:center;cursor:pointer;transition:background-color var(--fui-duration-moderate-01) var(--fui-ease-standard)}.fui-tree-node:hover{background-color:var(--fui-surface-hover, var(--fui-black-5))}.fui-tree-node--focused{outline:2px solid var(--fui-primary-60);outline-offset:-2px}.fui-tree-node--selected{background-color:var(--fui-primary-10)}.fui-tree-node--disabled{opacity:.5;pointer-events:none}.fui-tree-node__content{display:flex;align-items:center;width:100%;min-height:32px;padding:4px 8px;gap:4px}.fui-tree-node__toggle{all:unset;display:flex;align-items:center;justify-content:center;width:20px;height:20px;flex-shrink:0;border-radius:var(--fui-border-radius-sm);cursor:pointer}.fui-tree-node__toggle--hidden{visibility:hidden}.fui-tree-node__toggle:hover{background-color:var(--fui-surface-hover, var(--fui-black-10))}.fui-tree-node__label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n"] }]
52
+ }, template: "<div class=\"fui-tree-node__content\">\r\n <!-- Expand/collapse toggle -->\r\n <button\r\n class=\"fui-tree-node__toggle\"\r\n [class.fui-tree-node__toggle--hidden]=\"!flatNode().expandable\"\r\n (click)=\"toggle.emit(); $event.stopPropagation()\"\r\n [attr.aria-label]=\"flatNode().expanded ? intl.collapseAriaLabel : intl.expandAriaLabel\"\r\n tabindex=\"-1\"\r\n type=\"button\"\r\n >\r\n @if (flatNode().loading) {\r\n <fui-icon name=\"spinner\" [spin]=\"true\" size=\"sm\"></fui-icon>\r\n } @else {\r\n <fui-icon [name]=\"flatNode().expanded ? 'caret-down' : 'caret-right'\" size=\"sm\"></fui-icon>\r\n }\r\n </button>\r\n\r\n <!-- Checkbox (only in checkbox mode) -->\r\n @if (selectionMode() === 'checkbox') {\r\n <fui-checkbox\r\n [checked]=\"checkboxState() === 'checked'\"\r\n [indeterminate]=\"checkboxState() === 'indeterminate'\"\r\n [disabled]=\"flatNode().disabled\"\r\n (change)=\"checkboxChange.emit()\"\r\n >\r\n </fui-checkbox>\r\n }\r\n\r\n <!-- Node content -->\r\n <div class=\"fui-tree-node__label\" (click)=\"select.emit()\" (dblclick)=\"toggle.emit()\">\r\n @if (nodeTemplate()) {\r\n <ng-container *ngTemplateOutlet=\"nodeTemplate()!; context: { $implicit: flatNode().origin, node: flatNode() }\">\r\n </ng-container>\r\n } @else {\r\n {{ flatNode().origin.data }}\r\n }\r\n </div>\r\n</div>\r\n", styles: [".fui-tree-node{display:flex;align-items:center;cursor:pointer;transition:background-color var(--fui-duration-base) var(--fui-ease-in-out)}.fui-tree-node:hover{background-color:var(--fui-bg-subtle)}.fui-tree-node--focused{outline:2px solid var(--fui-primary-60);outline-offset:-2px}.fui-tree-node--selected{background-color:var(--fui-primary-10)}.fui-tree-node--disabled{opacity:.5;pointer-events:none}.fui-tree-node__content{display:flex;align-items:center;width:100%;min-height:32px;padding:4px 8px;gap:4px}.fui-tree-node__toggle{all:unset;display:flex;align-items:center;justify-content:center;width:20px;height:20px;flex-shrink:0;border-radius:var(--fui-radius-sm);cursor:pointer}.fui-tree-node__toggle--hidden{visibility:hidden}.fui-tree-node__toggle:hover{background-color:var(--fui-bg-subtle)}.fui-tree-node__label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n"] }]
53
53
  }], ctorParameters: () => [], propDecorators: { flatNode: [{ type: i0.Input, args: [{ isSignal: true, alias: "flatNode", required: true }] }], selectionMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionMode", required: false }] }], nodeTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodeTemplate", required: false }] }], checkboxState: [{ type: i0.Input, args: [{ isSignal: true, alias: "checkboxState", required: false }] }], focused: [{ type: i0.Input, args: [{ isSignal: true, alias: "focused", required: false }] }], toggle: [{ type: i0.Output, args: ["toggle"] }], select: [{ type: i0.Output, args: ["select"] }], checkboxChange: [{ type: i0.Output, args: ["checkboxChange"] }] } });
54
54
 
55
55
  class FuiTreeFlattener {
@@ -123,12 +123,21 @@ class FuiTreeComponent {
123
123
  virtualScroll = input(false, ...(ngDevMode ? [{ debugName: "virtualScroll" }] : /* istanbul ignore next */ []));
124
124
  virtualItemSize = input(32, ...(ngDevMode ? [{ debugName: "virtualItemSize" }] : /* istanbul ignore next */ []));
125
125
  filter = input('', ...(ngDevMode ? [{ debugName: "filter" }] : /* istanbul ignore next */ []));
126
+ /**
127
+ * Optional prefix used to build stable DOM ids for each rendered tree-node element.
128
+ * When provided, each node element receives `id="${nodeIdPrefix}-${flatIndex}"`.
129
+ * Used by parent combobox components (e.g. tree-select) to resolve `aria-activedescendant`.
130
+ */
131
+ nodeIdPrefix = input(null, ...(ngDevMode ? [{ debugName: "nodeIdPrefix" }] : /* istanbul ignore next */ []));
126
132
  nodeSelect = output();
127
133
  nodeUnselect = output();
128
134
  nodeExpand = output();
129
135
  nodeCollapse = output();
130
136
  nodeDrop = output();
131
137
  filterChange = output();
138
+ /** Emits the DOM id of the tree-node element that gains keyboard focus. Used by parent
139
+ * combobox components to update `aria-activedescendant`. */
140
+ focusChange = output();
132
141
  _flattener = new FuiTreeFlattener();
133
142
  _subscriptions = [];
134
143
  /** Refresh counter to trigger re-flatten after mutations */
@@ -151,6 +160,11 @@ class FuiTreeComponent {
151
160
  return this._flattener.calculateCheckboxStates(this.nodes());
152
161
  }, ...(ngDevMode ? [{ debugName: "checkboxStates" }] : /* istanbul ignore next */ []));
153
162
  focusedIndex = signal(0, ...(ngDevMode ? [{ debugName: "focusedIndex" }] : /* istanbul ignore next */ []));
163
+ /** Builds the DOM element id for a flat-node at the given index. Returns null when no prefix is set. */
164
+ nodeElementId(flatIndex) {
165
+ const prefix = this.nodeIdPrefix();
166
+ return prefix != null ? `${prefix}-node-${String(flatIndex)}` : null;
167
+ }
154
168
  ngOnDestroy() {
155
169
  for (const sub of this._subscriptions) {
156
170
  sub.unsubscribe();
@@ -269,6 +283,8 @@ class FuiTreeComponent {
269
283
  return;
270
284
  const currentIndex = this.focusedIndex();
271
285
  const currentNode = visibleNodes.find((n) => n._flatIndex === currentIndex);
286
+ const prevFocusedIndex = currentIndex;
287
+ const prevRefreshCounter = this._refreshCounter();
272
288
  switch (event.key) {
273
289
  case 'ArrowDown': {
274
290
  event.preventDefault();
@@ -359,6 +375,16 @@ class FuiTreeComponent {
359
375
  break;
360
376
  }
361
377
  }
378
+ // Emit focusChange when either the focused index changed OR a structural refresh
379
+ // happened (expand/collapse). The latter is required because flatIndex values shift
380
+ // after a refresh, which changes the DOM ids of nodes — so any cached
381
+ // aria-activedescendant id in a parent component must be re-synced even if the
382
+ // logically-focused node is unchanged.
383
+ const newFocusedIndex = this.focusedIndex();
384
+ const didRefresh = this._refreshCounter() !== prevRefreshCounter;
385
+ if (newFocusedIndex !== prevFocusedIndex || didRefresh) {
386
+ this.focusChange.emit(this.nodeElementId(newFocusedIndex));
387
+ }
362
388
  }
363
389
  // --- Private helpers ---
364
390
  _filterNodes(nodes, filterStr) {
@@ -428,7 +454,7 @@ class FuiTreeComponent {
428
454
  }
429
455
  }
430
456
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiTreeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
431
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: FuiTreeComponent, isStandalone: true, selector: "fui-tree", inputs: { nodes: { classPropertyName: "nodes", publicName: "nodes", isSignal: true, isRequired: true, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, loadChildren: { classPropertyName: "loadChildren", publicName: "loadChildren", isSignal: true, isRequired: false, transformFunction: null }, nodeTemplate: { classPropertyName: "nodeTemplate", publicName: "nodeTemplate", isSignal: true, isRequired: false, transformFunction: null }, draggable: { classPropertyName: "draggable", publicName: "draggable", isSignal: true, isRequired: false, transformFunction: null }, virtualScroll: { classPropertyName: "virtualScroll", publicName: "virtualScroll", isSignal: true, isRequired: false, transformFunction: null }, virtualItemSize: { classPropertyName: "virtualItemSize", publicName: "virtualItemSize", isSignal: true, isRequired: false, transformFunction: null }, filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { nodeSelect: "nodeSelect", nodeUnselect: "nodeUnselect", nodeExpand: "nodeExpand", nodeCollapse: "nodeCollapse", nodeDrop: "nodeDrop", filterChange: "filterChange" }, host: { attributes: { "role": "tree" }, listeners: { "keydown": "_onKeydown($event)" }, properties: { "attr.tabindex": "0" }, classAttribute: "fui-tree" }, ngImport: i0, template: "@if (!virtualScroll()) {\r\n @for (flatNode of flatNodes(); track flatNode._flatIndex) {\r\n <fui-tree-node\r\n [flatNode]=\"flatNode\"\r\n [selectionMode]=\"selectionMode()\"\r\n [nodeTemplate]=\"nodeTemplate()\"\r\n [checkboxState]=\"checkboxStates().get(flatNode.origin) ?? 'unchecked'\"\r\n [focused]=\"focusedIndex() === flatNode._flatIndex\"\r\n (toggle)=\"onNodeToggle(flatNode)\"\r\n (select)=\"onNodeSelect(flatNode)\"\r\n (checkboxChange)=\"onCheckboxChange(flatNode)\"\r\n >\r\n </fui-tree-node>\r\n }\r\n}\r\n\r\n@if (virtualScroll()) {\r\n <fui-virtual-scroll-viewport [itemSize]=\"virtualItemSize()\" style=\"height: 100%\">\r\n <fui-tree-node\r\n *fuiVirtualFor=\"let flatNode of flatNodes()\"\r\n [flatNode]=\"flatNode\"\r\n [selectionMode]=\"selectionMode()\"\r\n [nodeTemplate]=\"nodeTemplate()\"\r\n [checkboxState]=\"checkboxStates().get(flatNode.origin) ?? 'unchecked'\"\r\n [focused]=\"focusedIndex() === flatNode._flatIndex\"\r\n (toggle)=\"onNodeToggle(flatNode)\"\r\n (select)=\"onNodeSelect(flatNode)\"\r\n (checkboxChange)=\"onCheckboxChange(flatNode)\"\r\n >\r\n </fui-tree-node>\r\n </fui-virtual-scroll-viewport>\r\n}\r\n", styles: [".fui-tree{display:block;outline:none;font-family:var(--fui-font-family);font-size:var(--fui-font-size-03);color:var(--fui-text-primary)}\n"], dependencies: [{ kind: "component", type: FuiTreeNodeComponent, selector: "fui-tree-node", inputs: ["flatNode", "selectionMode", "nodeTemplate", "checkboxState", "focused"], outputs: ["toggle", "select", "checkboxChange"] }, { kind: "component", type: FuiVirtualScrollViewportComponent, selector: "fui-virtual-scroll-viewport", inputs: ["itemSize", "minBufferPx", "maxBufferPx", "orientation"], outputs: ["scrolledIndexChange", "renderedRangeChange"] }, { kind: "directive", type: FuiVirtualForDirective, selector: "[fuiVirtualFor][fuiVirtualForOf]", inputs: ["fuiVirtualForOf", "fuiVirtualForTrackBy"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
457
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: FuiTreeComponent, isStandalone: true, selector: "fui-tree", inputs: { nodes: { classPropertyName: "nodes", publicName: "nodes", isSignal: true, isRequired: true, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, loadChildren: { classPropertyName: "loadChildren", publicName: "loadChildren", isSignal: true, isRequired: false, transformFunction: null }, nodeTemplate: { classPropertyName: "nodeTemplate", publicName: "nodeTemplate", isSignal: true, isRequired: false, transformFunction: null }, draggable: { classPropertyName: "draggable", publicName: "draggable", isSignal: true, isRequired: false, transformFunction: null }, virtualScroll: { classPropertyName: "virtualScroll", publicName: "virtualScroll", isSignal: true, isRequired: false, transformFunction: null }, virtualItemSize: { classPropertyName: "virtualItemSize", publicName: "virtualItemSize", isSignal: true, isRequired: false, transformFunction: null }, filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: false, transformFunction: null }, nodeIdPrefix: { classPropertyName: "nodeIdPrefix", publicName: "nodeIdPrefix", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { nodeSelect: "nodeSelect", nodeUnselect: "nodeUnselect", nodeExpand: "nodeExpand", nodeCollapse: "nodeCollapse", nodeDrop: "nodeDrop", filterChange: "filterChange", focusChange: "focusChange" }, host: { attributes: { "role": "tree" }, listeners: { "keydown": "_onKeydown($event)" }, properties: { "attr.tabindex": "0" }, classAttribute: "fui-tree" }, ngImport: i0, template: "@if (!virtualScroll()) {\r\n @for (flatNode of flatNodes(); track flatNode._flatIndex) {\r\n <fui-tree-node\r\n [attr.id]=\"nodeElementId(flatNode._flatIndex)\"\r\n [flatNode]=\"flatNode\"\r\n [selectionMode]=\"selectionMode()\"\r\n [nodeTemplate]=\"nodeTemplate()\"\r\n [checkboxState]=\"checkboxStates().get(flatNode.origin) ?? 'unchecked'\"\r\n [focused]=\"focusedIndex() === flatNode._flatIndex\"\r\n (toggle)=\"onNodeToggle(flatNode)\"\r\n (select)=\"onNodeSelect(flatNode)\"\r\n (checkboxChange)=\"onCheckboxChange(flatNode)\"\r\n >\r\n </fui-tree-node>\r\n }\r\n}\r\n\r\n@if (virtualScroll()) {\r\n <fui-virtual-scroll-viewport [itemSize]=\"virtualItemSize()\" style=\"height: 100%\">\r\n <fui-tree-node\r\n *fuiVirtualFor=\"let flatNode of flatNodes()\"\r\n [attr.id]=\"nodeElementId(flatNode._flatIndex)\"\r\n [flatNode]=\"flatNode\"\r\n [selectionMode]=\"selectionMode()\"\r\n [nodeTemplate]=\"nodeTemplate()\"\r\n [checkboxState]=\"checkboxStates().get(flatNode.origin) ?? 'unchecked'\"\r\n [focused]=\"focusedIndex() === flatNode._flatIndex\"\r\n (toggle)=\"onNodeToggle(flatNode)\"\r\n (select)=\"onNodeSelect(flatNode)\"\r\n (checkboxChange)=\"onCheckboxChange(flatNode)\"\r\n >\r\n </fui-tree-node>\r\n </fui-virtual-scroll-viewport>\r\n}\r\n", styles: [".fui-tree{display:block;outline:none;font-family:var(--fui-font-family);font-size:var(--fui-text-md);color:var(--fui-text-primary)}\n"], dependencies: [{ kind: "component", type: FuiTreeNodeComponent, selector: "fui-tree-node", inputs: ["flatNode", "selectionMode", "nodeTemplate", "checkboxState", "focused"], outputs: ["toggle", "select", "checkboxChange"] }, { kind: "component", type: FuiVirtualScrollViewportComponent, selector: "fui-virtual-scroll-viewport", inputs: ["itemSize", "minBufferPx", "maxBufferPx", "orientation"], outputs: ["scrolledIndexChange", "renderedRangeChange"] }, { kind: "directive", type: FuiVirtualForDirective, selector: "[fuiVirtualFor][fuiVirtualForOf]", inputs: ["fuiVirtualForOf", "fuiVirtualForTrackBy"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
432
458
  }
433
459
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiTreeComponent, decorators: [{
434
460
  type: Component,
@@ -437,8 +463,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImpor
437
463
  role: 'tree',
438
464
  '[attr.tabindex]': '0',
439
465
  '(keydown)': '_onKeydown($event)',
440
- }, template: "@if (!virtualScroll()) {\r\n @for (flatNode of flatNodes(); track flatNode._flatIndex) {\r\n <fui-tree-node\r\n [flatNode]=\"flatNode\"\r\n [selectionMode]=\"selectionMode()\"\r\n [nodeTemplate]=\"nodeTemplate()\"\r\n [checkboxState]=\"checkboxStates().get(flatNode.origin) ?? 'unchecked'\"\r\n [focused]=\"focusedIndex() === flatNode._flatIndex\"\r\n (toggle)=\"onNodeToggle(flatNode)\"\r\n (select)=\"onNodeSelect(flatNode)\"\r\n (checkboxChange)=\"onCheckboxChange(flatNode)\"\r\n >\r\n </fui-tree-node>\r\n }\r\n}\r\n\r\n@if (virtualScroll()) {\r\n <fui-virtual-scroll-viewport [itemSize]=\"virtualItemSize()\" style=\"height: 100%\">\r\n <fui-tree-node\r\n *fuiVirtualFor=\"let flatNode of flatNodes()\"\r\n [flatNode]=\"flatNode\"\r\n [selectionMode]=\"selectionMode()\"\r\n [nodeTemplate]=\"nodeTemplate()\"\r\n [checkboxState]=\"checkboxStates().get(flatNode.origin) ?? 'unchecked'\"\r\n [focused]=\"focusedIndex() === flatNode._flatIndex\"\r\n (toggle)=\"onNodeToggle(flatNode)\"\r\n (select)=\"onNodeSelect(flatNode)\"\r\n (checkboxChange)=\"onCheckboxChange(flatNode)\"\r\n >\r\n </fui-tree-node>\r\n </fui-virtual-scroll-viewport>\r\n}\r\n", styles: [".fui-tree{display:block;outline:none;font-family:var(--fui-font-family);font-size:var(--fui-font-size-03);color:var(--fui-text-primary)}\n"] }]
441
- }], propDecorators: { nodes: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodes", required: true }] }], selectionMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionMode", required: false }] }], loadChildren: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadChildren", required: false }] }], nodeTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodeTemplate", required: false }] }], draggable: [{ type: i0.Input, args: [{ isSignal: true, alias: "draggable", required: false }] }], virtualScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualScroll", required: false }] }], virtualItemSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualItemSize", required: false }] }], filter: [{ type: i0.Input, args: [{ isSignal: true, alias: "filter", required: false }] }], nodeSelect: [{ type: i0.Output, args: ["nodeSelect"] }], nodeUnselect: [{ type: i0.Output, args: ["nodeUnselect"] }], nodeExpand: [{ type: i0.Output, args: ["nodeExpand"] }], nodeCollapse: [{ type: i0.Output, args: ["nodeCollapse"] }], nodeDrop: [{ type: i0.Output, args: ["nodeDrop"] }], filterChange: [{ type: i0.Output, args: ["filterChange"] }] } });
466
+ }, template: "@if (!virtualScroll()) {\r\n @for (flatNode of flatNodes(); track flatNode._flatIndex) {\r\n <fui-tree-node\r\n [attr.id]=\"nodeElementId(flatNode._flatIndex)\"\r\n [flatNode]=\"flatNode\"\r\n [selectionMode]=\"selectionMode()\"\r\n [nodeTemplate]=\"nodeTemplate()\"\r\n [checkboxState]=\"checkboxStates().get(flatNode.origin) ?? 'unchecked'\"\r\n [focused]=\"focusedIndex() === flatNode._flatIndex\"\r\n (toggle)=\"onNodeToggle(flatNode)\"\r\n (select)=\"onNodeSelect(flatNode)\"\r\n (checkboxChange)=\"onCheckboxChange(flatNode)\"\r\n >\r\n </fui-tree-node>\r\n }\r\n}\r\n\r\n@if (virtualScroll()) {\r\n <fui-virtual-scroll-viewport [itemSize]=\"virtualItemSize()\" style=\"height: 100%\">\r\n <fui-tree-node\r\n *fuiVirtualFor=\"let flatNode of flatNodes()\"\r\n [attr.id]=\"nodeElementId(flatNode._flatIndex)\"\r\n [flatNode]=\"flatNode\"\r\n [selectionMode]=\"selectionMode()\"\r\n [nodeTemplate]=\"nodeTemplate()\"\r\n [checkboxState]=\"checkboxStates().get(flatNode.origin) ?? 'unchecked'\"\r\n [focused]=\"focusedIndex() === flatNode._flatIndex\"\r\n (toggle)=\"onNodeToggle(flatNode)\"\r\n (select)=\"onNodeSelect(flatNode)\"\r\n (checkboxChange)=\"onCheckboxChange(flatNode)\"\r\n >\r\n </fui-tree-node>\r\n </fui-virtual-scroll-viewport>\r\n}\r\n", styles: [".fui-tree{display:block;outline:none;font-family:var(--fui-font-family);font-size:var(--fui-text-md);color:var(--fui-text-primary)}\n"] }]
467
+ }], propDecorators: { nodes: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodes", required: true }] }], selectionMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionMode", required: false }] }], loadChildren: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadChildren", required: false }] }], nodeTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodeTemplate", required: false }] }], draggable: [{ type: i0.Input, args: [{ isSignal: true, alias: "draggable", required: false }] }], virtualScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualScroll", required: false }] }], virtualItemSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualItemSize", required: false }] }], filter: [{ type: i0.Input, args: [{ isSignal: true, alias: "filter", required: false }] }], nodeIdPrefix: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodeIdPrefix", required: false }] }], nodeSelect: [{ type: i0.Output, args: ["nodeSelect"] }], nodeUnselect: [{ type: i0.Output, args: ["nodeUnselect"] }], nodeExpand: [{ type: i0.Output, args: ["nodeExpand"] }], nodeCollapse: [{ type: i0.Output, args: ["nodeCollapse"] }], nodeDrop: [{ type: i0.Output, args: ["nodeDrop"] }], filterChange: [{ type: i0.Output, args: ["filterChange"] }], focusChange: [{ type: i0.Output, args: ["focusChange"] }] } });
442
468
 
443
469
  /**
444
470
  * Generated bundle index. Do not edit.