@koobiq/components 20.4.2 → 21.0.1

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 (798) hide show
  1. package/accordion/accordion-trigger.scss +3 -10
  2. package/accordion/accordion.scss +4 -6
  3. package/actions-panel/actions-panel-container.scss +45 -1
  4. package/alert/alert.component.scss +3 -2
  5. package/app-switcher/_app-switcher-theme.scss +0 -4
  6. package/app-switcher/app-switcher-dropdown-app.scss +3 -2
  7. package/app-switcher/app-switcher-dropdown-site.scss +2 -1
  8. package/app-switcher/{kbq-app-switcher-list-item.scss → app-switcher-list-item.scss} +18 -4
  9. package/app-switcher/app-switcher-tokens.scss +15 -0
  10. package/app-switcher/app-switcher.scss +14 -4
  11. package/autocomplete/autocomplete.scss +7 -6
  12. package/badge/badge.component.scss +5 -8
  13. package/breadcrumbs/breadcrumbs.scss +25 -10
  14. package/button/_button-base.scss +30 -7
  15. package/button/_button-theme.scss +16 -0
  16. package/button/button-group.scss +7 -0
  17. package/button/button-tokens.scss +0 -2
  18. package/button/button.scss +34 -2
  19. package/button-toggle/_button-toggle-theme.scss +7 -2
  20. package/button-toggle/button-toggle.scss +65 -15
  21. package/checkbox/_checkbox-theme.scss +4 -3
  22. package/checkbox/checkbox.scss +3 -6
  23. package/clamped-text/clamped-text.scss +6 -2
  24. package/code-block/code-block-tokens.scss +0 -224
  25. package/code-block/code-block.scss +20 -9
  26. package/content-panel/content-panel-aside.scss +3 -2
  27. package/content-panel/content-panel-container.scss +37 -0
  28. package/content-panel/content-panel.scss +4 -3
  29. package/core/highlight/_highlight-theme.scss +3 -1
  30. package/core/option/action-container.scss +2 -2
  31. package/core/option/action.scss +2 -1
  32. package/core/option/option.scss +2 -1
  33. package/core/pop-up/_pop-up.scss +0 -37
  34. package/core/selection/pseudo-checkbox/pseudo-checkbox.scss +5 -10
  35. package/core/styles/_core.scss +3 -0
  36. package/core/styles/_koobiq-theme.scss +5 -6
  37. package/core/styles/common/_animation.scss +44 -16
  38. package/core/styles/common/_groups-mixins.scss +21 -19
  39. package/core/styles/common/_groups.scss +4 -32
  40. package/core/styles/common/_index.scss +0 -2
  41. package/core/styles/common/_link.scss +117 -0
  42. package/core/styles/common/_list.scss +0 -26
  43. package/core/styles/common/_overlay.scss +8 -10
  44. package/core/styles/common/_rtl.scss +0 -14
  45. package/core/styles/common/_select.scss +33 -15
  46. package/core/styles/common/_squircle.scss +63 -0
  47. package/core/styles/common/_tokens.scss +0 -11
  48. package/core/styles/common/_vendor-prefixes.scss +0 -20
  49. package/core/styles/functions/_timing.scss +0 -22
  50. package/core/styles/theming/_scrollbar-theme.scss +6 -1
  51. package/core/styles/theming/_theming.scss +13 -65
  52. package/core/styles/typography/_index.scss +0 -1
  53. package/core/styles/typography/_typography.scss +0 -143
  54. package/core/styles/visual/_body.scss +1 -6
  55. package/core/styles/visual/_layout.scss +0 -12
  56. package/datepicker/calendar-body.scss +3 -1
  57. package/datepicker/calendar-header.scss +0 -1
  58. package/datepicker/datepicker-content.scss +33 -1
  59. package/datepicker/datepicker-toggle.scss +0 -38
  60. package/dl/dl-tokens.scss +10 -0
  61. package/dl/dl.scss +113 -13
  62. package/dropdown/_dropdown-theme.scss +4 -16
  63. package/dropdown/dropdown-item.scss +4 -10
  64. package/dropdown/dropdown.scss +2 -1
  65. package/empty-state/_empty-state-theme.scss +10 -4
  66. package/empty-state/empty-state-tokens.scss +4 -4
  67. package/empty-state/empty-state.scss +4 -0
  68. package/fesm2022/koobiq-components-accordion.mjs +347 -229
  69. package/fesm2022/koobiq-components-accordion.mjs.map +1 -1
  70. package/fesm2022/koobiq-components-actions-panel.mjs +302 -187
  71. package/fesm2022/koobiq-components-actions-panel.mjs.map +1 -1
  72. package/fesm2022/koobiq-components-alert.mjs +39 -39
  73. package/fesm2022/koobiq-components-alert.mjs.map +1 -1
  74. package/fesm2022/koobiq-components-app-switcher.mjs +677 -367
  75. package/fesm2022/koobiq-components-app-switcher.mjs.map +1 -1
  76. package/fesm2022/koobiq-components-autocomplete.mjs +620 -253
  77. package/fesm2022/koobiq-components-autocomplete.mjs.map +1 -1
  78. package/fesm2022/koobiq-components-badge.mjs +46 -48
  79. package/fesm2022/koobiq-components-badge.mjs.map +1 -1
  80. package/fesm2022/koobiq-components-breadcrumbs.mjs +221 -169
  81. package/fesm2022/koobiq-components-breadcrumbs.mjs.map +1 -1
  82. package/fesm2022/koobiq-components-button-toggle.mjs +565 -196
  83. package/fesm2022/koobiq-components-button-toggle.mjs.map +1 -1
  84. package/fesm2022/koobiq-components-button.mjs +332 -116
  85. package/fesm2022/koobiq-components-button.mjs.map +1 -1
  86. package/fesm2022/koobiq-components-checkbox.mjs +172 -132
  87. package/fesm2022/koobiq-components-checkbox.mjs.map +1 -1
  88. package/fesm2022/koobiq-components-clamped-text.mjs +165 -158
  89. package/fesm2022/koobiq-components-clamped-text.mjs.map +1 -1
  90. package/fesm2022/koobiq-components-code-block.mjs +791 -609
  91. package/fesm2022/koobiq-components-code-block.mjs.map +1 -1
  92. package/fesm2022/koobiq-components-content-panel.mjs +260 -143
  93. package/fesm2022/koobiq-components-content-panel.mjs.map +1 -1
  94. package/fesm2022/koobiq-components-core.mjs +4342 -1595
  95. package/fesm2022/koobiq-components-core.mjs.map +1 -1
  96. package/fesm2022/koobiq-components-datepicker.mjs +1713 -1606
  97. package/fesm2022/koobiq-components-datepicker.mjs.map +1 -1
  98. package/fesm2022/koobiq-components-divider.mjs +73 -36
  99. package/fesm2022/koobiq-components-divider.mjs.map +1 -1
  100. package/fesm2022/koobiq-components-dl.mjs +447 -89
  101. package/fesm2022/koobiq-components-dl.mjs.map +1 -1
  102. package/fesm2022/koobiq-components-dropdown.mjs +703 -599
  103. package/fesm2022/koobiq-components-dropdown.mjs.map +1 -1
  104. package/fesm2022/koobiq-components-dynamic-translation.mjs +20 -20
  105. package/fesm2022/koobiq-components-dynamic-translation.mjs.map +1 -1
  106. package/fesm2022/koobiq-components-ellipsis-center.mjs +46 -31
  107. package/fesm2022/koobiq-components-ellipsis-center.mjs.map +1 -1
  108. package/fesm2022/koobiq-components-empty-state.mjs +116 -60
  109. package/fesm2022/koobiq-components-empty-state.mjs.map +1 -1
  110. package/fesm2022/koobiq-components-file-upload.mjs +550 -290
  111. package/fesm2022/koobiq-components-file-upload.mjs.map +1 -1
  112. package/fesm2022/koobiq-components-filter-bar.mjs +2871 -2595
  113. package/fesm2022/koobiq-components-filter-bar.mjs.map +1 -1
  114. package/fesm2022/koobiq-components-flag.mjs +79 -24
  115. package/fesm2022/koobiq-components-flag.mjs.map +1 -1
  116. package/fesm2022/koobiq-components-form-field.mjs +389 -525
  117. package/fesm2022/koobiq-components-form-field.mjs.map +1 -1
  118. package/fesm2022/koobiq-components-icon.mjs +400 -149
  119. package/fesm2022/koobiq-components-icon.mjs.map +1 -1
  120. package/fesm2022/koobiq-components-inline-edit.mjs +429 -212
  121. package/fesm2022/koobiq-components-inline-edit.mjs.map +1 -1
  122. package/fesm2022/koobiq-components-input.mjs +601 -459
  123. package/fesm2022/koobiq-components-input.mjs.map +1 -1
  124. package/fesm2022/koobiq-components-link-deprecated.mjs +196 -0
  125. package/fesm2022/koobiq-components-link-deprecated.mjs.map +1 -0
  126. package/fesm2022/koobiq-components-link.mjs +328 -125
  127. package/fesm2022/koobiq-components-link.mjs.map +1 -1
  128. package/fesm2022/koobiq-components-list.mjs +583 -433
  129. package/fesm2022/koobiq-components-list.mjs.map +1 -1
  130. package/fesm2022/koobiq-components-loader-overlay.mjs +167 -68
  131. package/fesm2022/koobiq-components-loader-overlay.mjs.map +1 -1
  132. package/fesm2022/koobiq-components-markdown.mjs +55 -78
  133. package/fesm2022/koobiq-components-markdown.mjs.map +1 -1
  134. package/fesm2022/koobiq-components-modal.mjs +853 -475
  135. package/fesm2022/koobiq-components-modal.mjs.map +1 -1
  136. package/fesm2022/koobiq-components-navbar.mjs +895 -556
  137. package/fesm2022/koobiq-components-navbar.mjs.map +1 -1
  138. package/fesm2022/koobiq-components-notification-center.mjs +680 -310
  139. package/fesm2022/koobiq-components-notification-center.mjs.map +1 -1
  140. package/fesm2022/koobiq-components-overflow-items.mjs +46 -64
  141. package/fesm2022/koobiq-components-overflow-items.mjs.map +1 -1
  142. package/fesm2022/koobiq-components-popover.mjs +684 -285
  143. package/fesm2022/koobiq-components-popover.mjs.map +1 -1
  144. package/fesm2022/koobiq-components-progress-bar.mjs +87 -33
  145. package/fesm2022/koobiq-components-progress-bar.mjs.map +1 -1
  146. package/fesm2022/koobiq-components-progress-spinner.mjs +52 -43
  147. package/fesm2022/koobiq-components-progress-spinner.mjs.map +1 -1
  148. package/fesm2022/koobiq-components-radio.mjs +450 -231
  149. package/fesm2022/koobiq-components-radio.mjs.map +1 -1
  150. package/fesm2022/koobiq-components-resizer.mjs +127 -21
  151. package/fesm2022/koobiq-components-resizer.mjs.map +1 -1
  152. package/fesm2022/koobiq-components-scrollbar-deprecated.mjs +299 -0
  153. package/fesm2022/koobiq-components-scrollbar-deprecated.mjs.map +1 -0
  154. package/fesm2022/koobiq-components-scrollbar.mjs +745 -222
  155. package/fesm2022/koobiq-components-scrollbar.mjs.map +1 -1
  156. package/fesm2022/koobiq-components-search-expandable.mjs +288 -126
  157. package/fesm2022/koobiq-components-search-expandable.mjs.map +1 -1
  158. package/fesm2022/koobiq-components-select.mjs +883 -693
  159. package/fesm2022/koobiq-components-select.mjs.map +1 -1
  160. package/fesm2022/koobiq-components-sidebar.mjs +207 -88
  161. package/fesm2022/koobiq-components-sidebar.mjs.map +1 -1
  162. package/fesm2022/koobiq-components-sidepanel.mjs +689 -296
  163. package/fesm2022/koobiq-components-sidepanel.mjs.map +1 -1
  164. package/fesm2022/koobiq-components-skeleton.mjs +815 -41
  165. package/fesm2022/koobiq-components-skeleton.mjs.map +1 -1
  166. package/fesm2022/koobiq-components-split-button.mjs +109 -88
  167. package/fesm2022/koobiq-components-split-button.mjs.map +1 -1
  168. package/fesm2022/koobiq-components-splitter-deprecated.mjs +591 -0
  169. package/fesm2022/koobiq-components-splitter-deprecated.mjs.map +1 -0
  170. package/fesm2022/koobiq-components-splitter.mjs +890 -501
  171. package/fesm2022/koobiq-components-splitter.mjs.map +1 -1
  172. package/fesm2022/koobiq-components-table.mjs +63 -49
  173. package/fesm2022/koobiq-components-table.mjs.map +1 -1
  174. package/fesm2022/koobiq-components-tabs.mjs +1062 -603
  175. package/fesm2022/koobiq-components-tabs.mjs.map +1 -1
  176. package/fesm2022/koobiq-components-tags.mjs +886 -733
  177. package/fesm2022/koobiq-components-tags.mjs.map +1 -1
  178. package/fesm2022/koobiq-components-textarea.mjs +213 -185
  179. package/fesm2022/koobiq-components-textarea.mjs.map +1 -1
  180. package/fesm2022/koobiq-components-time-range.mjs +299 -147
  181. package/fesm2022/koobiq-components-time-range.mjs.map +1 -1
  182. package/fesm2022/koobiq-components-timepicker.mjs +233 -245
  183. package/fesm2022/koobiq-components-timepicker.mjs.map +1 -1
  184. package/fesm2022/koobiq-components-timezone.mjs +344 -142
  185. package/fesm2022/koobiq-components-timezone.mjs.map +1 -1
  186. package/fesm2022/koobiq-components-title.mjs +229 -145
  187. package/fesm2022/koobiq-components-title.mjs.map +1 -1
  188. package/fesm2022/koobiq-components-toast.mjs +463 -143
  189. package/fesm2022/koobiq-components-toast.mjs.map +1 -1
  190. package/fesm2022/koobiq-components-toggle.mjs +177 -130
  191. package/fesm2022/koobiq-components-toggle.mjs.map +1 -1
  192. package/fesm2022/koobiq-components-tooltip.mjs +657 -214
  193. package/fesm2022/koobiq-components-tooltip.mjs.map +1 -1
  194. package/fesm2022/koobiq-components-top-bar.mjs +61 -32
  195. package/fesm2022/koobiq-components-top-bar.mjs.map +1 -1
  196. package/fesm2022/koobiq-components-tree-select.mjs +734 -488
  197. package/fesm2022/koobiq-components-tree-select.mjs.map +1 -1
  198. package/fesm2022/koobiq-components-tree.mjs +1700 -617
  199. package/fesm2022/koobiq-components-tree.mjs.map +1 -1
  200. package/fesm2022/koobiq-components-username.mjs +290 -135
  201. package/fesm2022/koobiq-components-username.mjs.map +1 -1
  202. package/file-upload/dropzone.scss +31 -3
  203. package/file-upload/file-upload-tokens.scss +2 -22
  204. package/file-upload/file-upload.scss +6 -0
  205. package/file-upload/multiple-file-upload.component.scss +14 -12
  206. package/file-upload/single-file-upload.component.scss +3 -2
  207. package/filter-bar/filters.scss +7 -0
  208. package/filter-bar/pipes/base-pipe.scss +3 -3
  209. package/filter-bar/pipes/pipe-date.scss +8 -1
  210. package/flag/flag-tokens.scss +22 -0
  211. package/flag/flag.scss +34 -21
  212. package/form-field/{_fiedset-theme.scss → _fieldset-theme.scss} +1 -5
  213. package/form-field/_form-field-theme.scss +4 -9
  214. package/form-field/cleaner.scss +3 -1
  215. package/form-field/fieldset.scss +3 -4
  216. package/form-field/form-field.scss +26 -21
  217. package/form-field/password-toggle.scss +3 -1
  218. package/icon/_icon-button-theme.scss +7 -0
  219. package/icon/_icon-theme.scss +10 -7
  220. package/icon/icon-button.scss +0 -2
  221. package/icon/icon-tokens.scss +12 -9
  222. package/inline-edit/inline-edit.scss +40 -54
  223. package/input/input.scss +4 -0
  224. package/link/{_link-theme.scss → deprecated/_link-theme.scss} +11 -6
  225. package/link/deprecated/link-tokens.scss +27 -0
  226. package/link/link-tokens.scss +6 -25
  227. package/link/link.scss +137 -0
  228. package/list/list.scss +3 -2
  229. package/loader-overlay/_loader-overlay-theme.scss +19 -10
  230. package/loader-overlay/loader-overlay-tokens.scss +0 -2
  231. package/loader-overlay/loader-overlay.scss +7 -1
  232. package/markdown/_markdown-theme.scss +16 -0
  233. package/markdown/markdown-tokens.scss +5 -0
  234. package/markdown/markdown.scss +2 -1
  235. package/modal/_modal-animation.scss +23 -14
  236. package/modal/modal-tokens.scss +2 -1
  237. package/modal/modal.scss +35 -31
  238. package/navbar/_navbar-item_horizontal.scss +8 -6
  239. package/navbar/_navbar-item_vertical.scss +18 -6
  240. package/navbar/_navbar-theme.scss +9 -1
  241. package/navbar/navbar-brand.scss +8 -6
  242. package/navbar/navbar-divider.scss +1 -1
  243. package/navbar/navbar-item.scss +8 -9
  244. package/navbar/navbar-toggle.scss +3 -3
  245. package/navbar/navbar-tokens.scss +14 -0
  246. package/navbar/navbar.scss +1 -2
  247. package/navbar/vertical-navbar.scss +2 -2
  248. package/notification-center/_notification-center-theme.scss +11 -6
  249. package/notification-center/notification-center-tokens.scss +33 -0
  250. package/notification-center/notification-center.scss +58 -20
  251. package/notification-center/notification-item.scss +15 -6
  252. package/package.json +112 -81
  253. package/popover/popover-tokens.scss +0 -2
  254. package/popover/popover.scss +41 -19
  255. package/prebuilt-themes/theme.css +1 -1
  256. package/progress-bar/_progress-bar-theme.scss +20 -3
  257. package/progress-bar/progress-bar-tokens.scss +3 -0
  258. package/progress-bar/progress-bar.scss +36 -8
  259. package/progress-spinner/progress-spinner.scss +4 -3
  260. package/radio/_radio-theme.scss +21 -4
  261. package/radio/radio-tokens.scss +7 -3
  262. package/radio/radio.scss +55 -8
  263. package/schematics/collection.json +415 -18
  264. package/schematics/migrations/accordion-state-saving-default/README.md +60 -0
  265. package/schematics/migrations/accordion-state-saving-default/data.cjs +75 -0
  266. package/schematics/migrations/accordion-state-saving-default/index.cjs +61 -0
  267. package/schematics/migrations/accordion-state-saving-default/schema.json +15 -0
  268. package/schematics/migrations/actions-panel-overlay-container/README.md +35 -0
  269. package/schematics/migrations/actions-panel-overlay-container/data.cjs +47 -0
  270. package/schematics/migrations/actions-panel-overlay-container/index.cjs +55 -0
  271. package/schematics/migrations/actions-panel-overlay-container/schema.json +15 -0
  272. package/schematics/migrations/alert-signals/README.md +13 -7
  273. package/schematics/migrations/alert-signals/{data.js → data.cjs} +3 -0
  274. package/schematics/migrations/alert-signals/index.cjs +221 -0
  275. package/schematics/migrations/angular-animations-removal/README.md +46 -0
  276. package/schematics/migrations/angular-animations-removal/data.cjs +150 -0
  277. package/schematics/migrations/angular-animations-removal/index.cjs +21 -0
  278. package/schematics/migrations/angular-animations-removal/schema.json +15 -0
  279. package/schematics/migrations/app-switcher-signals/README.md +88 -0
  280. package/schematics/migrations/app-switcher-signals/data.cjs +136 -0
  281. package/schematics/migrations/app-switcher-signals/index.cjs +366 -0
  282. package/schematics/migrations/app-switcher-signals/schema.json +20 -0
  283. package/schematics/migrations/autocomplete-panel-width-auto/README.md +2 -2
  284. package/schematics/migrations/autocomplete-panel-width-auto/{index.js → index.cjs} +6 -5
  285. package/schematics/migrations/autocomplete-signals/README.md +92 -0
  286. package/schematics/migrations/autocomplete-signals/data.cjs +149 -0
  287. package/schematics/migrations/autocomplete-signals/index.cjs +707 -0
  288. package/schematics/migrations/autocomplete-signals/schema.json +20 -0
  289. package/schematics/migrations/badge-signals/README.md +77 -0
  290. package/schematics/migrations/badge-signals/data.cjs +109 -0
  291. package/schematics/migrations/badge-signals/index.cjs +694 -0
  292. package/schematics/migrations/badge-signals/schema.json +20 -0
  293. package/schematics/migrations/button-state-and-styles/README.md +129 -0
  294. package/schematics/migrations/button-state-and-styles/data.cjs +136 -0
  295. package/schematics/migrations/button-state-and-styles/index.cjs +221 -0
  296. package/schematics/migrations/button-state-and-styles/schema.json +20 -0
  297. package/schematics/migrations/button-supported-colors/README.md +73 -0
  298. package/schematics/migrations/button-supported-colors/data.cjs +106 -0
  299. package/schematics/migrations/button-supported-colors/index.cjs +261 -0
  300. package/schematics/migrations/button-supported-colors/schema.json +20 -0
  301. package/schematics/migrations/button-toggle-signals-and-aria/README.md +137 -0
  302. package/schematics/migrations/button-toggle-signals-and-aria/data.cjs +200 -0
  303. package/schematics/migrations/button-toggle-signals-and-aria/index.cjs +497 -0
  304. package/schematics/migrations/button-toggle-signals-and-aria/schema.json +20 -0
  305. package/schematics/migrations/button-truncation/README.md +110 -0
  306. package/schematics/migrations/button-truncation/data.cjs +88 -0
  307. package/schematics/migrations/button-truncation/index.cjs +270 -0
  308. package/schematics/migrations/button-truncation/schema.json +20 -0
  309. package/schematics/migrations/checkbox-signals/README.md +76 -0
  310. package/schematics/migrations/checkbox-signals/data.cjs +114 -0
  311. package/schematics/migrations/checkbox-signals/index.cjs +635 -0
  312. package/schematics/migrations/checkbox-signals/schema.json +20 -0
  313. package/schematics/migrations/clamped-text-disclosure/README.md +62 -0
  314. package/schematics/migrations/clamped-text-disclosure/data.cjs +101 -0
  315. package/schematics/migrations/clamped-text-disclosure/index.cjs +60 -0
  316. package/schematics/migrations/clamped-text-disclosure/schema.json +15 -0
  317. package/schematics/migrations/code-block-highlight-js-core/README.md +53 -0
  318. package/schematics/migrations/code-block-highlight-js-core/data.cjs +64 -0
  319. package/schematics/migrations/code-block-highlight-js-core/index.cjs +319 -0
  320. package/schematics/migrations/code-block-highlight-js-core/schema.json +20 -0
  321. package/schematics/migrations/code-block-signals/README.md +84 -0
  322. package/schematics/migrations/code-block-signals/data.cjs +121 -0
  323. package/schematics/migrations/code-block-signals/index.cjs +701 -0
  324. package/schematics/migrations/code-block-signals/schema.json +20 -0
  325. package/schematics/migrations/color-signals/README.md +46 -0
  326. package/schematics/migrations/color-signals/data.cjs +131 -0
  327. package/schematics/migrations/color-signals/index.cjs +20 -0
  328. package/schematics/migrations/color-signals/schema.json +20 -0
  329. package/schematics/migrations/core-mixins-removal/README.md +20 -0
  330. package/schematics/migrations/core-mixins-removal/data.cjs +27 -0
  331. package/schematics/migrations/core-mixins-removal/index.cjs +18 -0
  332. package/schematics/migrations/core-mixins-removal/schema.json +15 -0
  333. package/schematics/migrations/css-selectors/README.md +2 -2
  334. package/schematics/migrations/css-selectors/{index.js → index.cjs} +4 -3
  335. package/schematics/migrations/datepicker-signals/README.md +24 -0
  336. package/schematics/migrations/datepicker-signals/data.cjs +49 -0
  337. package/schematics/migrations/datepicker-signals/index.cjs +18 -0
  338. package/schematics/migrations/datepicker-signals/schema.json +15 -0
  339. package/schematics/migrations/deprecated-icons/README.md +2 -2
  340. package/schematics/migrations/deprecated-icons/{index.js → index.cjs} +8 -7
  341. package/schematics/migrations/design-tokens-v4/README.md +75 -0
  342. package/schematics/migrations/design-tokens-v4/index.cjs +60 -0
  343. package/schematics/migrations/design-tokens-v4/schema.json +15 -0
  344. package/schematics/migrations/divider-signals-and-aria/README.md +47 -0
  345. package/schematics/migrations/divider-signals-and-aria/data.cjs +62 -0
  346. package/schematics/migrations/divider-signals-and-aria/index.cjs +212 -0
  347. package/schematics/migrations/divider-signals-and-aria/schema.json +15 -0
  348. package/schematics/migrations/dl-attribute-coercion/README.md +59 -0
  349. package/schematics/migrations/dl-attribute-coercion/data.cjs +85 -0
  350. package/schematics/migrations/dl-attribute-coercion/index.cjs +162 -0
  351. package/schematics/migrations/dl-attribute-coercion/schema.json +15 -0
  352. package/schematics/migrations/dl-standalone-names/README.md +49 -0
  353. package/schematics/migrations/dl-standalone-names/data.cjs +44 -0
  354. package/schematics/migrations/dl-standalone-names/index.cjs +322 -0
  355. package/schematics/migrations/dl-standalone-names/schema.json +20 -0
  356. package/schematics/migrations/dropdown-demote-overlay/README.md +137 -0
  357. package/schematics/migrations/dropdown-demote-overlay/data.cjs +84 -0
  358. package/schematics/migrations/dropdown-demote-overlay/index.cjs +289 -0
  359. package/schematics/migrations/dropdown-demote-overlay/schema.json +20 -0
  360. package/schematics/migrations/dropdown-signals/README.md +83 -0
  361. package/schematics/migrations/dropdown-signals/data.cjs +152 -0
  362. package/schematics/migrations/dropdown-signals/index.cjs +20 -0
  363. package/schematics/migrations/dropdown-signals/schema.json +20 -0
  364. package/schematics/migrations/empty-state-error-color/README.md +84 -0
  365. package/schematics/migrations/empty-state-error-color/data.cjs +85 -0
  366. package/schematics/migrations/empty-state-error-color/index.cjs +72 -0
  367. package/schematics/migrations/empty-state-error-color/schema.json +15 -0
  368. package/schematics/migrations/empty-state-size-attr/README.md +2 -2
  369. package/schematics/migrations/empty-state-size-attr/{index.js → index.cjs} +6 -5
  370. package/schematics/migrations/file-upload-cva-and-primitives/README.md +70 -0
  371. package/schematics/migrations/file-upload-cva-and-primitives/data.cjs +97 -0
  372. package/schematics/migrations/file-upload-cva-and-primitives/index.cjs +61 -0
  373. package/schematics/migrations/file-upload-cva-and-primitives/schema.json +15 -0
  374. package/schematics/migrations/file-upload-deprecated-outputs/README.md +90 -0
  375. package/schematics/migrations/file-upload-deprecated-outputs/data.cjs +20 -0
  376. package/schematics/migrations/file-upload-deprecated-outputs/index.cjs +71 -0
  377. package/schematics/migrations/file-upload-deprecated-outputs/schema.json +20 -0
  378. package/schematics/migrations/filter-bar-rename-action/README.md +183 -0
  379. package/schematics/migrations/filter-bar-rename-action/data.cjs +151 -0
  380. package/schematics/migrations/filter-bar-rename-action/index.cjs +178 -0
  381. package/schematics/migrations/filter-bar-rename-action/schema.json +20 -0
  382. package/schematics/migrations/filter-bar-signals/README.md +27 -16
  383. package/schematics/migrations/filter-bar-signals/{data.js → data.cjs} +1 -2
  384. package/schematics/migrations/filter-bar-signals/index.cjs +225 -0
  385. package/schematics/migrations/filter-bar-state-saving-default/README.md +53 -0
  386. package/schematics/migrations/filter-bar-state-saving-default/data.cjs +87 -0
  387. package/schematics/migrations/filter-bar-state-saving-default/index.cjs +62 -0
  388. package/schematics/migrations/filter-bar-state-saving-default/schema.json +15 -0
  389. package/schematics/migrations/flag-inner-html/README.md +67 -0
  390. package/schematics/migrations/flag-inner-html/data.cjs +58 -0
  391. package/schematics/migrations/flag-inner-html/index.cjs +62 -0
  392. package/schematics/migrations/flag-inner-html/schema.json +15 -0
  393. package/schematics/migrations/form-field-signals/README.md +125 -0
  394. package/schematics/migrations/form-field-signals/data.cjs +288 -0
  395. package/schematics/migrations/form-field-signals/index.cjs +383 -0
  396. package/schematics/migrations/form-field-signals/schema.json +20 -0
  397. package/schematics/migrations/icon-semantics-and-api/README.md +65 -0
  398. package/schematics/migrations/icon-semantics-and-api/data.cjs +97 -0
  399. package/schematics/migrations/icon-semantics-and-api/index.cjs +65 -0
  400. package/schematics/migrations/icon-semantics-and-api/schema.json +15 -0
  401. package/schematics/migrations/icons-replacement/README.md +5 -5
  402. package/schematics/migrations/icons-replacement/{index.js → index.cjs} +4 -3
  403. package/schematics/migrations/inline-edit-a11y-and-types/README.md +82 -0
  404. package/schematics/migrations/inline-edit-a11y-and-types/data.cjs +117 -0
  405. package/schematics/migrations/inline-edit-a11y-and-types/index.cjs +98 -0
  406. package/schematics/migrations/inline-edit-a11y-and-types/schema.json +20 -0
  407. package/schematics/migrations/input-number-surface/README.md +140 -0
  408. package/schematics/migrations/input-number-surface/data.cjs +135 -0
  409. package/schematics/migrations/input-number-surface/index.cjs +293 -0
  410. package/schematics/migrations/input-number-surface/schema.json +20 -0
  411. package/schematics/migrations/input-signals/README.md +20 -0
  412. package/schematics/migrations/input-signals/data.cjs +30 -0
  413. package/schematics/migrations/input-signals/index.cjs +18 -0
  414. package/schematics/migrations/input-signals/schema.json +15 -0
  415. package/schematics/migrations/link-deprecated-path/README.md +144 -0
  416. package/schematics/migrations/link-deprecated-path/index.cjs +20 -0
  417. package/schematics/migrations/link-deprecated-path/schema.json +20 -0
  418. package/schematics/migrations/link-signals/README.md +71 -0
  419. package/schematics/migrations/link-signals/data.cjs +116 -0
  420. package/schematics/migrations/link-signals/index.cjs +416 -0
  421. package/schematics/migrations/link-signals/schema.json +20 -0
  422. package/schematics/migrations/list-signals/README.md +22 -0
  423. package/schematics/migrations/list-signals/data.cjs +35 -0
  424. package/schematics/migrations/list-signals/index.cjs +18 -0
  425. package/schematics/migrations/list-signals/schema.json +15 -0
  426. package/schematics/migrations/list-tree-multiple-input/README.md +105 -0
  427. package/schematics/migrations/list-tree-multiple-input/data.cjs +74 -0
  428. package/schematics/migrations/list-tree-multiple-input/index.cjs +222 -0
  429. package/schematics/migrations/list-tree-multiple-input/schema.json +20 -0
  430. package/schematics/migrations/loader-overlay-signals/README.md +62 -0
  431. package/schematics/migrations/loader-overlay-signals/data.cjs +101 -0
  432. package/schematics/migrations/loader-overlay-signals/index.cjs +698 -0
  433. package/schematics/migrations/loader-overlay-signals/schema.json +20 -0
  434. package/schematics/migrations/loader-overlay-size-attr/README.md +2 -2
  435. package/schematics/migrations/loader-overlay-size-attr/{index.js → index.cjs} +6 -5
  436. package/schematics/migrations/locale-configuration-providers/README.md +163 -0
  437. package/schematics/migrations/locale-configuration-providers/data.cjs +257 -0
  438. package/schematics/migrations/locale-configuration-providers/index.cjs +295 -0
  439. package/schematics/migrations/locale-configuration-providers/schema.json +20 -0
  440. package/schematics/migrations/mandatory-peer-dependencies/README.md +70 -0
  441. package/schematics/migrations/mandatory-peer-dependencies/index.cjs +43 -0
  442. package/schematics/migrations/mandatory-peer-dependencies/schema.json +15 -0
  443. package/schematics/migrations/markdown-signals/README.md +58 -0
  444. package/schematics/migrations/markdown-signals/data.cjs +79 -0
  445. package/schematics/migrations/markdown-signals/index.cjs +640 -0
  446. package/schematics/migrations/markdown-signals/schema.json +20 -0
  447. package/schematics/migrations/modal-dialog-semantics/README.md +106 -0
  448. package/schematics/migrations/modal-dialog-semantics/data.cjs +110 -0
  449. package/schematics/migrations/modal-dialog-semantics/index.cjs +59 -0
  450. package/schematics/migrations/modal-dialog-semantics/schema.json +15 -0
  451. package/schematics/migrations/modal-signals/README.md +88 -0
  452. package/schematics/migrations/modal-signals/data.cjs +132 -0
  453. package/schematics/migrations/modal-signals/index.cjs +20 -0
  454. package/schematics/migrations/modal-signals/schema.json +20 -0
  455. package/schematics/migrations/navbar-signals-and-aria/README.md +111 -0
  456. package/schematics/migrations/navbar-signals-and-aria/data.cjs +198 -0
  457. package/schematics/migrations/navbar-signals-and-aria/index.cjs +569 -0
  458. package/schematics/migrations/navbar-signals-and-aria/schema.json +20 -0
  459. package/schematics/migrations/new-icons-pack/README.md +10 -10
  460. package/schematics/migrations/new-icons-pack/{index.js → index.cjs} +8 -7
  461. package/schematics/migrations/notification-center-signals/README.md +67 -0
  462. package/schematics/migrations/notification-center-signals/data.cjs +66 -0
  463. package/schematics/migrations/notification-center-signals/index.cjs +62 -0
  464. package/schematics/migrations/notification-center-signals/schema.json +15 -0
  465. package/schematics/migrations/option-signals/README.md +37 -0
  466. package/schematics/migrations/option-signals/data.cjs +86 -0
  467. package/schematics/migrations/option-signals/index.cjs +20 -0
  468. package/schematics/migrations/option-signals/schema.json +20 -0
  469. package/schematics/migrations/popover-leave-delay/README.md +51 -0
  470. package/schematics/migrations/popover-leave-delay/data.cjs +61 -0
  471. package/schematics/migrations/popover-leave-delay/index.cjs +55 -0
  472. package/schematics/migrations/popover-leave-delay/schema.json +15 -0
  473. package/schematics/migrations/progress-bar-percentage-and-aria/README.md +54 -0
  474. package/schematics/migrations/progress-bar-percentage-and-aria/data.cjs +76 -0
  475. package/schematics/migrations/progress-bar-percentage-and-aria/index.cjs +59 -0
  476. package/schematics/migrations/progress-bar-percentage-and-aria/schema.json +15 -0
  477. package/schematics/migrations/progress-spinner-signals/README.md +72 -0
  478. package/schematics/migrations/progress-spinner-signals/data.cjs +83 -0
  479. package/schematics/migrations/progress-spinner-signals/index.cjs +695 -0
  480. package/schematics/migrations/progress-spinner-signals/schema.json +20 -0
  481. package/schematics/migrations/query-list-signals/README.md +32 -0
  482. package/schematics/migrations/query-list-signals/data.cjs +70 -0
  483. package/schematics/migrations/query-list-signals/index.cjs +18 -0
  484. package/schematics/migrations/query-list-signals/schema.json +15 -0
  485. package/schematics/migrations/radio-signals-and-aria/README.md +82 -0
  486. package/schematics/migrations/radio-signals-and-aria/data.cjs +163 -0
  487. package/schematics/migrations/radio-signals-and-aria/index.cjs +40 -0
  488. package/schematics/migrations/radio-signals-and-aria/schema.json +20 -0
  489. package/schematics/migrations/read-state-dwell-handlers/README.md +125 -0
  490. package/schematics/migrations/read-state-dwell-handlers/data.cjs +45 -0
  491. package/schematics/migrations/read-state-dwell-handlers/index.cjs +216 -0
  492. package/schematics/migrations/read-state-dwell-handlers/schema.json +20 -0
  493. package/schematics/migrations/scrollbar-deprecated-path/README.md +128 -0
  494. package/schematics/migrations/scrollbar-deprecated-path/index.cjs +21 -0
  495. package/schematics/migrations/scrollbar-deprecated-path/schema.json +20 -0
  496. package/schematics/migrations/select-signal-inputs/README.md +61 -0
  497. package/schematics/migrations/select-signal-inputs/data.cjs +99 -0
  498. package/schematics/migrations/select-signal-inputs/index.cjs +58 -0
  499. package/schematics/migrations/select-signal-inputs/schema.json +15 -0
  500. package/schematics/migrations/sidepanel-non-modal-behavior/README.md +57 -0
  501. package/schematics/migrations/sidepanel-non-modal-behavior/data.cjs +111 -0
  502. package/schematics/migrations/sidepanel-non-modal-behavior/index.cjs +58 -0
  503. package/schematics/migrations/sidepanel-non-modal-behavior/schema.json +15 -0
  504. package/schematics/migrations/signal-inputs-subclasses/README.md +28 -0
  505. package/schematics/migrations/signal-inputs-subclasses/data.cjs +69 -0
  506. package/schematics/migrations/signal-inputs-subclasses/index.cjs +18 -0
  507. package/schematics/migrations/signal-inputs-subclasses/schema.json +15 -0
  508. package/schematics/migrations/split-button-optional-disabled/README.md +47 -0
  509. package/schematics/migrations/split-button-optional-disabled/data.cjs +53 -0
  510. package/schematics/migrations/split-button-optional-disabled/index.cjs +58 -0
  511. package/schematics/migrations/split-button-optional-disabled/schema.json +15 -0
  512. package/schematics/migrations/splitter-deprecated-path/README.md +136 -0
  513. package/schematics/migrations/splitter-deprecated-path/index.cjs +21 -0
  514. package/schematics/migrations/splitter-deprecated-path/schema.json +20 -0
  515. package/schematics/migrations/state-saving-default/README.md +67 -0
  516. package/schematics/migrations/state-saving-default/data.cjs +88 -0
  517. package/schematics/migrations/state-saving-default/index.cjs +63 -0
  518. package/schematics/migrations/state-saving-default/schema.json +15 -0
  519. package/schematics/migrations/table-cell-content/README.md +55 -0
  520. package/schematics/migrations/table-cell-content/data.cjs +66 -0
  521. package/schematics/migrations/table-cell-content/index.cjs +67 -0
  522. package/schematics/migrations/table-cell-content/schema.json +15 -0
  523. package/schematics/migrations/tabs-signals-and-aria/README.md +93 -0
  524. package/schematics/migrations/tabs-signals-and-aria/data.cjs +139 -0
  525. package/schematics/migrations/tabs-signals-and-aria/index.cjs +66 -0
  526. package/schematics/migrations/tabs-signals-and-aria/schema.json +15 -0
  527. package/schematics/migrations/tag-list-cleaner/README.md +58 -0
  528. package/schematics/migrations/tag-list-cleaner/data.cjs +42 -0
  529. package/schematics/migrations/tag-list-cleaner/index.cjs +197 -0
  530. package/schematics/migrations/tag-list-cleaner/schema.json +20 -0
  531. package/schematics/migrations/tag-slots/README.md +41 -0
  532. package/schematics/migrations/tag-slots/index.cjs +191 -0
  533. package/schematics/migrations/tag-slots/schema.json +20 -0
  534. package/schematics/migrations/tags-signals/README.md +85 -0
  535. package/schematics/migrations/tags-signals/data.cjs +103 -0
  536. package/schematics/migrations/tags-signals/index.cjs +674 -0
  537. package/schematics/migrations/tags-signals/schema.json +20 -0
  538. package/schematics/migrations/textarea-signals/README.md +72 -0
  539. package/schematics/migrations/textarea-signals/data.cjs +121 -0
  540. package/schematics/migrations/textarea-signals/index.cjs +380 -0
  541. package/schematics/migrations/textarea-signals/schema.json +20 -0
  542. package/schematics/migrations/time-range-title-for/README.md +164 -0
  543. package/schematics/migrations/time-range-title-for/data.cjs +139 -0
  544. package/schematics/migrations/time-range-title-for/index.cjs +164 -0
  545. package/schematics/migrations/time-range-title-for/schema.json +20 -0
  546. package/schematics/migrations/timepicker-signals/README.md +78 -0
  547. package/schematics/migrations/timepicker-signals/data.cjs +82 -0
  548. package/schematics/migrations/timepicker-signals/index.cjs +710 -0
  549. package/schematics/migrations/timepicker-signals/schema.json +20 -0
  550. package/schematics/migrations/timezone-grouping-utils/README.md +73 -0
  551. package/schematics/migrations/timezone-grouping-utils/data.cjs +101 -0
  552. package/schematics/migrations/timezone-grouping-utils/index.cjs +65 -0
  553. package/schematics/migrations/timezone-grouping-utils/schema.json +15 -0
  554. package/schematics/migrations/title-encapsulation/README.md +49 -0
  555. package/schematics/migrations/title-encapsulation/data.cjs +69 -0
  556. package/schematics/migrations/title-encapsulation/index.cjs +58 -0
  557. package/schematics/migrations/title-encapsulation/schema.json +15 -0
  558. package/schematics/migrations/toast-stack-and-defaults/README.md +102 -0
  559. package/schematics/migrations/toast-stack-and-defaults/data.cjs +79 -0
  560. package/schematics/migrations/toast-stack-and-defaults/index.cjs +54 -0
  561. package/schematics/migrations/toast-stack-and-defaults/schema.json +15 -0
  562. package/schematics/migrations/tooltip-pointer-events-and-types/README.md +53 -0
  563. package/schematics/migrations/tooltip-pointer-events-and-types/data.cjs +89 -0
  564. package/schematics/migrations/tooltip-pointer-events-and-types/index.cjs +61 -0
  565. package/schematics/migrations/tooltip-pointer-events-and-types/schema.json +15 -0
  566. package/schematics/migrations/top-bar-container-selectors/README.md +111 -0
  567. package/schematics/migrations/top-bar-container-selectors/data.cjs +56 -0
  568. package/schematics/migrations/top-bar-container-selectors/index.cjs +85 -0
  569. package/schematics/migrations/top-bar-container-selectors/schema.json +20 -0
  570. package/schematics/migrations/tree-select-signals/README.md +61 -0
  571. package/schematics/migrations/tree-select-signals/data.cjs +106 -0
  572. package/schematics/migrations/tree-select-signals/index.cjs +59 -0
  573. package/schematics/migrations/tree-select-signals/schema.json +15 -0
  574. package/schematics/migrations/tree-signals/README.md +82 -0
  575. package/schematics/migrations/tree-signals/data.cjs +123 -0
  576. package/schematics/migrations/tree-signals/index.cjs +55 -0
  577. package/schematics/migrations/tree-signals/schema.json +15 -0
  578. package/schematics/migrations/tree-state-saving-default/README.md +66 -0
  579. package/schematics/migrations/tree-state-saving-default/data.cjs +78 -0
  580. package/schematics/migrations/tree-state-saving-default/index.cjs +61 -0
  581. package/schematics/migrations/tree-state-saving-default/schema.json +15 -0
  582. package/schematics/migrations/username-pipe-injection/README.md +59 -0
  583. package/schematics/migrations/username-pipe-injection/data.cjs +78 -0
  584. package/schematics/migrations/username-pipe-injection/index.cjs +59 -0
  585. package/schematics/migrations/username-pipe-injection/schema.json +15 -0
  586. package/schematics/migrations/v20-upgrade/README.md +36 -16
  587. package/schematics/migrations/v20-upgrade/{data.js → data.cjs} +124 -77
  588. package/schematics/migrations/v20-upgrade/index.cjs +19 -0
  589. package/schematics/migrations/v21-upgrade/README.md +271 -0
  590. package/schematics/migrations/v21-upgrade/data.cjs +1371 -0
  591. package/schematics/migrations/v21-upgrade/index.cjs +95 -0
  592. package/schematics/migrations/v21-upgrade/schema.json +20 -0
  593. package/schematics/migrations/zoneless-change-detection/README.md +30 -0
  594. package/schematics/migrations/zoneless-change-detection/data.cjs +29 -0
  595. package/schematics/migrations/zoneless-change-detection/index.cjs +21 -0
  596. package/schematics/migrations/zoneless-change-detection/schema.json +15 -0
  597. package/schematics/migrations.json +401 -6
  598. package/schematics/ng-add/index.cjs +266 -0
  599. package/schematics/ng-add/schema.json +15 -0
  600. package/schematics/utils/{angular-parsing.js → angular-parsing.cjs} +2 -2
  601. package/schematics/utils/deprecated-path-migration.cjs +62 -0
  602. package/schematics/utils/html-config.cjs +148 -0
  603. package/schematics/utils/{icon-migration.js → icon-migration.cjs} +2 -2
  604. package/schematics/utils/list-item-pattern.cjs +16 -0
  605. package/schematics/utils/{package-config.js → package-config.cjs} +3 -32
  606. package/schematics/utils/project-files.cjs +25 -0
  607. package/schematics/utils/replacement-driver.cjs +337 -0
  608. package/schematics/utils/safe-rule.cjs +23 -0
  609. package/schematics/utils/signal-members-migration.cjs +779 -0
  610. package/schematics/utils/tag-patterns.cjs +21 -0
  611. package/schematics/utils/template-ref-access.cjs +155 -0
  612. package/schematics/utils/{typescript.js → typescript.cjs} +1 -1
  613. package/schematics/utils/warn-only-migration.cjs +52 -0
  614. package/schematics/utils/workspace-styles.cjs +123 -0
  615. package/scrollbar/{_scrollbar-component-theme.scss → deprecated/_scrollbar-component-theme.scss} +1 -1
  616. package/scrollbar/{scrollbar.component.scss → deprecated/scrollbar.component.scss} +1 -1
  617. package/scrollbar/native-scrollbar.scss +68 -0
  618. package/scrollbar/scrollbar-tokens.scss +13 -22
  619. package/scrollbar/scrollbar-track.scss +94 -0
  620. package/scrollbar/scrollbar-viewport.scss +33 -0
  621. package/scrollbar/scrollbar.scss +24 -0
  622. package/search-expandable/search-expandable-tokens.scss +4 -0
  623. package/search-expandable/search-expandable.scss +4 -2
  624. package/select/_select-theme.scss +3 -16
  625. package/select/select.scss +0 -6
  626. package/sidebar/sidebar.scss +20 -0
  627. package/sidepanel/_sidepanel-theme.scss +1 -1
  628. package/sidepanel/sidepanel-tokens.scss +7 -1
  629. package/sidepanel/sidepanel.scss +41 -5
  630. package/skeleton/skeleton-presets.scss +350 -0
  631. package/skeleton/skeleton-tokens.scss +127 -0
  632. package/skeleton/skeleton.scss +53 -45
  633. package/split-button/_split-button-theme.scss +4 -4
  634. package/split-button/split-button.scss +2 -6
  635. package/splitter/{_splitter-theme.scss → deprecated/_splitter-theme.scss} +1 -1
  636. package/splitter/deprecated/splitter.scss +51 -0
  637. package/splitter/splitter-tokens.scss +19 -0
  638. package/splitter/splitter.scss +148 -28
  639. package/table/_table-theme.scss +13 -12
  640. package/table/table-tokens.scss +8 -0
  641. package/table/table.scss +47 -22
  642. package/tabs/_tabs-common.scss +14 -14
  643. package/tabs/_tabs-theme.scss +4 -5
  644. package/tabs/tab-body.scss +49 -1
  645. package/tabs/tab-header.scss +2 -1
  646. package/tags/tag-list.scss +4 -0
  647. package/tags/tag.scss +19 -1
  648. package/time-range/time-range.scss +9 -0
  649. package/timezone/timezone-option.component.scss +4 -7
  650. package/timezone/timezone-select.component.scss +3 -0
  651. package/toast/_toast-theme.scss +1 -4
  652. package/toast/toast-container.component.scss +19 -13
  653. package/toast/toast-tokens.scss +12 -6
  654. package/toast/toast.component.scss +42 -19
  655. package/toggle/_toggle-theme.scss +4 -10
  656. package/toggle/toggle.scss +67 -26
  657. package/tooltip/_tooltip-theme.scss +7 -1
  658. package/tooltip/tooltip-tokens.scss +1 -2
  659. package/tooltip/tooltip.scss +55 -9
  660. package/top-bar/top-bar-tokens.scss +13 -2
  661. package/top-bar/top-bar.scss +24 -19
  662. package/tree/_tree-theme.scss +0 -1
  663. package/tree/toggle.scss +5 -9
  664. package/tree/tree-option.scss +2 -4
  665. package/tree/tree-tokens.scss +2 -1
  666. package/tree/tree.scss +3 -5
  667. package/tree-select/_tree-select-theme.scss +4 -15
  668. package/tree-select/tree-select-tokens.scss +16 -0
  669. package/tree-select/tree-select.scss +0 -6
  670. package/{accordion/index.d.ts → types/koobiq-components-accordion.d.ts} +102 -84
  671. package/{actions-panel/index.d.ts → types/koobiq-components-actions-panel.d.ts} +44 -59
  672. package/{alert/index.d.ts → types/koobiq-components-alert.d.ts} +8 -3
  673. package/types/koobiq-components-app-switcher.d.ts +406 -0
  674. package/types/koobiq-components-autocomplete.d.ts +443 -0
  675. package/{badge/index.d.ts → types/koobiq-components-badge.d.ts} +25 -20
  676. package/{breadcrumbs/index.d.ts → types/koobiq-components-breadcrumbs.d.ts} +97 -46
  677. package/types/koobiq-components-button-toggle.d.ts +340 -0
  678. package/types/koobiq-components-button.d.ts +296 -0
  679. package/types/koobiq-components-checkbox.d.ts +172 -0
  680. package/types/koobiq-components-clamped-text.d.ts +184 -0
  681. package/{code-block/index.d.ts → types/koobiq-components-code-block.d.ts} +150 -88
  682. package/{content-panel/index.d.ts → types/koobiq-components-content-panel.d.ts} +81 -25
  683. package/{core/index.d.ts → types/koobiq-components-core.d.ts} +2827 -865
  684. package/{datepicker/index.d.ts → types/koobiq-components-datepicker.d.ts} +161 -116
  685. package/types/koobiq-components-divider.d.ts +43 -0
  686. package/types/koobiq-components-dl.d.ts +235 -0
  687. package/{dropdown/index.d.ts → types/koobiq-components-dropdown.d.ts} +245 -239
  688. package/types/koobiq-components-ellipsis-center.d.ts +85 -0
  689. package/types/koobiq-components-empty-state.d.ts +106 -0
  690. package/{file-upload/index.d.ts → types/koobiq-components-file-upload.d.ts} +214 -107
  691. package/{filter-bar/index.d.ts → types/koobiq-components-filter-bar.d.ts} +410 -495
  692. package/types/koobiq-components-flag.d.ts +68 -0
  693. package/{form-field/index.d.ts → types/koobiq-components-form-field.d.ts} +167 -191
  694. package/types/koobiq-components-icon.d.ts +333 -0
  695. package/{inline-edit/index.d.ts → types/koobiq-components-inline-edit.d.ts} +109 -46
  696. package/types/koobiq-components-input.d.ts +477 -0
  697. package/types/koobiq-components-link-deprecated.d.ts +101 -0
  698. package/types/koobiq-components-link.d.ts +176 -0
  699. package/{list/index.d.ts → types/koobiq-components-list.d.ts} +162 -99
  700. package/types/koobiq-components-loader-overlay.d.ts +101 -0
  701. package/{markdown/index.d.ts → types/koobiq-components-markdown.d.ts} +16 -24
  702. package/types/koobiq-components-modal.d.ts +666 -0
  703. package/types/koobiq-components-navbar.d.ts +569 -0
  704. package/types/koobiq-components-notification-center.d.ts +500 -0
  705. package/{overflow-items/index.d.ts → types/koobiq-components-overflow-items.d.ts} +8 -22
  706. package/types/koobiq-components-popover.d.ts +468 -0
  707. package/types/koobiq-components-progress-bar.d.ts +67 -0
  708. package/{progress-spinner/index.d.ts → types/koobiq-components-progress-spinner.d.ts} +33 -10
  709. package/types/koobiq-components-radio.d.ts +294 -0
  710. package/{resizer/index.d.ts → types/koobiq-components-resizer.d.ts} +37 -2
  711. package/{scrollbar/index.d.ts → types/koobiq-components-scrollbar-deprecated.d.ts} +18 -1
  712. package/types/koobiq-components-scrollbar.d.ts +154 -0
  713. package/types/koobiq-components-search-expandable.d.ts +164 -0
  714. package/{select/index.d.ts → types/koobiq-components-select.d.ts} +360 -167
  715. package/types/koobiq-components-sidebar.d.ts +152 -0
  716. package/types/koobiq-components-sidepanel.d.ts +436 -0
  717. package/types/koobiq-components-skeleton.d.ts +234 -0
  718. package/types/koobiq-components-split-button.d.ts +65 -0
  719. package/{splitter/index.d.ts → types/koobiq-components-splitter-deprecated.d.ts} +44 -1
  720. package/types/koobiq-components-splitter.d.ts +406 -0
  721. package/types/koobiq-components-table.d.ts +44 -0
  722. package/types/koobiq-components-tabs.d.ts +888 -0
  723. package/{tags/index.d.ts → types/koobiq-components-tags.d.ts} +249 -133
  724. package/types/koobiq-components-textarea.d.ts +178 -0
  725. package/{time-range/index.d.ts → types/koobiq-components-time-range.d.ts} +135 -62
  726. package/types/koobiq-components-timepicker.d.ts +223 -0
  727. package/types/koobiq-components-timezone.d.ts +266 -0
  728. package/types/koobiq-components-title.d.ts +184 -0
  729. package/types/koobiq-components-toast.d.ts +289 -0
  730. package/types/koobiq-components-toggle.d.ts +121 -0
  731. package/types/koobiq-components-tooltip.d.ts +610 -0
  732. package/types/koobiq-components-top-bar.d.ts +61 -0
  733. package/types/koobiq-components-tree-select.d.ts +670 -0
  734. package/types/koobiq-components-tree.d.ts +1339 -0
  735. package/types/koobiq-components-username.d.ts +340 -0
  736. package/username/_username-theme.scss +35 -0
  737. package/username/username.scss +10 -34
  738. package/app-switcher/index.d.ts +0 -276
  739. package/autocomplete/index.d.ts +0 -286
  740. package/button/index.d.ts +0 -153
  741. package/button-toggle/index.d.ts +0 -162
  742. package/checkbox/index.d.ts +0 -163
  743. package/clamped-text/index.d.ts +0 -146
  744. package/core/styles/_tokens.scss +0 -7
  745. package/core/styles/common/_clearfix.scss +0 -13
  746. package/core/styles/common/_popup.scss +0 -6
  747. package/core/styles/functions/_index.scss +0 -3
  748. package/core/styles/functions/_number.scss +0 -60
  749. package/core/styles/functions/_string.scss +0 -18
  750. package/core/styles/theming/scrollbar-tokens.scss +0 -25
  751. package/core/styles/typography/_typography-utils.scss +0 -84
  752. package/divider/index.d.ts +0 -20
  753. package/dl/index.d.ts +0 -45
  754. package/ellipsis-center/index.d.ts +0 -71
  755. package/empty-state/index.d.ts +0 -45
  756. package/flag/index.d.ts +0 -44
  757. package/icon/index.d.ts +0 -200
  758. package/input/index.d.ts +0 -354
  759. package/link/index.d.ts +0 -56
  760. package/loader-overlay/index.d.ts +0 -57
  761. package/modal/index.d.ts +0 -339
  762. package/navbar/index.d.ts +0 -372
  763. package/notification-center/index.d.ts +0 -323
  764. package/popover/index.d.ts +0 -182
  765. package/prebuilt-themes/dark-theme.css +0 -1
  766. package/prebuilt-themes/light-theme.css +0 -1
  767. package/progress-bar/index.d.ts +0 -31
  768. package/radio/index.d.ts +0 -203
  769. package/schematics/migrations/alert-signals/index.js +0 -353
  770. package/schematics/migrations/filter-bar-signals/index.js +0 -319
  771. package/schematics/migrations/v20-upgrade/index.js +0 -225
  772. package/schematics/ng-add/index.js +0 -39
  773. package/search-expandable/index.d.ts +0 -101
  774. package/sidebar/index.d.ts +0 -94
  775. package/sidepanel/index.d.ts +0 -272
  776. package/skeleton/index.d.ts +0 -26
  777. package/split-button/index.d.ts +0 -46
  778. package/table/index.d.ts +0 -25
  779. package/tabs/index.d.ts +0 -677
  780. package/textarea/index.d.ts +0 -138
  781. package/timepicker/index.d.ts +0 -197
  782. package/timezone/index.d.ts +0 -125
  783. package/title/index.d.ts +0 -139
  784. package/toast/index.d.ts +0 -178
  785. package/toggle/index.d.ts +0 -104
  786. package/tooltip/index.d.ts +0 -335
  787. package/top-bar/index.d.ts +0 -33
  788. package/tree/index.d.ts +0 -802
  789. package/tree-select/index.d.ts +0 -475
  790. package/username/index.d.ts +0 -194
  791. /package/schematics/migrations/css-selectors/{data.js → data.cjs} +0 -0
  792. /package/schematics/migrations/deprecated-icons/{data.js → data.cjs} +0 -0
  793. /package/schematics/migrations/icons-replacement/{data.js → data.cjs} +0 -0
  794. /package/schematics/migrations/new-icons-pack/{data.js → data.cjs} +0 -0
  795. /package/schematics/utils/{ast.js → ast.cjs} +0 -0
  796. /package/schematics/utils/{messages.js → messages.cjs} +0 -0
  797. /package/{dynamic-translation/index.d.ts → types/koobiq-components-dynamic-translation.d.ts} +0 -0
  798. /package/{index.d.ts → types/koobiq-components.d.ts} +0 -0
@@ -1,18 +1,19 @@
1
1
  import { SelectionModel, DataSource } from '@angular/cdk/collections';
2
2
  import { BehaviorSubject, merge, Observable, of, Subject, asyncScheduler } from 'rxjs';
3
- import { escapeRegExp, KbqPseudoCheckbox, KbqOptionActionComponent, kbqFocusAndReveal, kbqGetElementHeight, kbqFocusOptionActionOnTab, hasModifierKey, KbqActionContainer, KBQ_TITLE_TEXT_REF, KBQ_OPTION_ACTION_PARENT, getSelectAllState, MultipleMode, ruRULocaleData, KBQ_LOCALE_SERVICE, FocusKeyManager, SPACE, LEFT_ARROW, RIGHT_ARROW, isVerticalMovement, isSelectAll, isCopy, TAB, DOWN_ARROW, UP_ARROW, ENTER, HOME, END, PAGE_UP, PAGE_DOWN, toggleSelectAll, getKbqSelectNonArrayValueError, KbqPseudoCheckboxModule } from '@koobiq/components/core';
4
- import { take, map, delay } from 'rxjs/operators';
3
+ import * as i1 from '@koobiq/components/core';
4
+ import { escapeRegExp, KbqStateSaving, KbqPseudoCheckbox, KbqOptionActionComponent, kbqFocusAndReveal, kbqGetElementHeight, kbqFocusOptionActionOnTab, hasModifierKey, KbqActionContainer, KBQ_TITLE_TEXT_REF, KBQ_OPTION_ACTION_PARENT, MultipleMode, getSelectAllState, kbqQueryListFrom, KbqLocaleOverridesDirective, KBQ_SELECT_LOCALE_CONFIGURATION, kbqOptionalNumberAttribute, kbqSelectAllHandlerTransform, resolveMultipleMode, FocusKeyManager, kbqLeaveTabOrderOnTabOut, SPACE, LEFT_ARROW, RIGHT_ARROW, isVerticalMovement, isSelectAll, isCopy, TAB, DOWN_ARROW, UP_ARROW, ENTER, HOME, END, PAGE_UP, PAGE_DOWN, toggleSelectAll, getKbqSelectNonArrayValueError, KbqPseudoCheckboxModule } from '@koobiq/components/core';
5
+ import { take, map, delay, filter } from 'rxjs/operators';
5
6
  import * as i0 from '@angular/core';
6
- import { inject, TemplateRef, input, Directive, ViewContainerRef, ChangeDetectorRef, IterableDiffers, DestroyRef, Input, ContentChildren, ViewChild, ElementRef, booleanAttribute, ViewEncapsulation, ChangeDetectionStrategy, Component, InjectionToken, NgZone, contentChild, output, EventEmitter, ContentChild, Renderer2, forwardRef, HostAttributeToken, QueryList, viewChild, signal, effect, Output, NgModule } from '@angular/core';
7
+ import { signal, inject, TemplateRef, input, Directive, ViewContainerRef, IterableDiffers, ChangeDetectorRef, viewChild, contentChildren, DestroyRef, effect, untracked, isDevMode, ElementRef, booleanAttribute, computed, ViewEncapsulation, ChangeDetectionStrategy, Component, InjectionToken, EnvironmentInjector, NgZone, Renderer2, contentChild, linkedSignal, output, EventEmitter, afterNextRender, forwardRef, Injector, QueryList, NgModule } from '@angular/core';
7
8
  import { Directionality } from '@angular/cdk/bidi';
8
9
  import { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';
9
- import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
10
+ import { takeUntilDestroyed, toSignal, outputFromObservable } from '@angular/core/rxjs-interop';
11
+ import { _getFocusedElementPierceShadowDom, Platform } from '@angular/cdk/platform';
10
12
  import { KbqDropdownTrigger } from '@koobiq/components/dropdown';
11
13
  import { KbqTooltipTrigger } from '@koobiq/components/tooltip';
12
14
  import { KbqIcon, KbqIconModule } from '@koobiq/components/icon';
13
15
  import { FocusMonitor } from '@angular/cdk/a11y';
14
16
  import { Clipboard } from '@angular/cdk/clipboard';
15
- import { Platform } from '@angular/cdk/platform';
16
17
  import { NG_VALUE_ACCESSOR } from '@angular/forms';
17
18
  import { KBQ_FORM_FIELD } from '@koobiq/components/form-field';
18
19
  import { AsyncScheduler } from 'rxjs/internal/scheduler/AsyncScheduler';
@@ -20,7 +21,7 @@ import { AsyncScheduler } from 'rxjs/internal/scheduler/AsyncScheduler';
20
21
  /** Base tree control. It has basic toggle/expand/collapse operations on a single data node. */
21
22
  class BaseTreeControl {
22
23
  constructor() {
23
- /** A selection model with multi-selection to track expansion status. */
24
+ /** A selection model with multi-selection to track expansion status: it holds the key of every expanded node. */
24
25
  this.expansionModel = new SelectionModel(true);
25
26
  this.filterModel = new SelectionModel(true);
26
27
  this.filterValue = new BehaviorSubject('');
@@ -30,29 +31,29 @@ class BaseTreeControl {
30
31
  if (this.filterValue.value?.length) {
31
32
  return;
32
33
  }
33
- this.expansionModel.toggle(dataNode);
34
+ this.expansionModel.toggle(this.expansionKey(dataNode));
34
35
  }
35
36
  /** Expands one single data node. */
36
37
  expand(dataNode) {
37
38
  if (this.filterValue.value?.length) {
38
39
  return;
39
40
  }
40
- this.expansionModel.select(dataNode);
41
+ this.expansionModel.select(this.expansionKey(dataNode));
41
42
  }
42
43
  /** Collapses one single data node. */
43
44
  collapse(dataNode) {
44
45
  if (this.filterValue.value?.length) {
45
46
  return;
46
47
  }
47
- this.expansionModel.deselect(dataNode);
48
+ this.expansionModel.deselect(this.expansionKey(dataNode));
48
49
  }
49
50
  /** Whether a given data node is expanded or not. Returns true if the data node is expanded. */
50
51
  isExpanded(dataNode) {
51
- return this.expansionModel.isSelected(dataNode);
52
+ return this.expansionModel.isSelected(this.expansionKey(dataNode));
52
53
  }
53
54
  /** Toggles a subtree rooted at `node` recursively. */
54
55
  toggleDescendants(dataNode) {
55
- if (this.expansionModel.isSelected(dataNode)) {
56
+ if (this.isExpanded(dataNode)) {
56
57
  this.collapseDescendants(dataNode);
57
58
  }
58
59
  else {
@@ -67,17 +68,26 @@ class BaseTreeControl {
67
68
  expandDescendants(dataNode) {
68
69
  const toBeProcessed = [dataNode];
69
70
  toBeProcessed.push(...this.getDescendants(dataNode));
70
- this.expansionModel.select(...toBeProcessed);
71
+ this.expansionModel.select(...toBeProcessed.map((node) => this.expansionKey(node)));
71
72
  }
72
73
  /** Collapses a subtree rooted at given data node recursively. */
73
74
  collapseDescendants(dataNode) {
74
75
  const toBeProcessed = [dataNode];
75
76
  toBeProcessed.push(...this.getDescendants(dataNode));
76
- this.expansionModel.deselect(...toBeProcessed);
77
+ this.expansionModel.deselect(...toBeProcessed.map((node) => this.expansionKey(node)));
78
+ }
79
+ /** The key `expansionModel` holds for a data node. */
80
+ expansionKey(dataNode) {
81
+ return this.trackBy ? this.trackBy(dataNode) : dataNode;
77
82
  }
78
83
  }
79
84
 
80
85
  const kbqTreeSelectAllValue = 'selectAll';
86
+ /**
87
+ * Default first stage of the filter pipeline: keeps the nodes whose view value matches the query.
88
+ *
89
+ * @docs-private
90
+ */
81
91
  class FilterByViewValue {
82
92
  constructor(control) {
83
93
  this.control = control;
@@ -95,6 +105,12 @@ class FilterByViewValue {
95
105
  return this.result;
96
106
  }
97
107
  }
108
+ /**
109
+ * Default last stage of the filter pipeline: re-adds the ancestors of every matched node so the
110
+ * matches stay reachable in the rendered hierarchy.
111
+ *
112
+ * @docs-private
113
+ */
98
114
  class FilterParentsForNodes {
99
115
  constructor(control) {
100
116
  this.control = control;
@@ -124,6 +140,7 @@ class FilterByValues {
124
140
  this.result = Array.from(new Set([...(prevFilter?.result || []), ...found]));
125
141
  return this.result;
126
142
  }
143
+ // TODO: nothing in the library uses it; kept as public API at the DS-2196 review. Document or deprecate it.
127
144
  getValues() {
128
145
  return this.values;
129
146
  }
@@ -148,7 +165,9 @@ class FlatTreeControl extends BaseTreeControl {
148
165
  /** compareValues will be used to comparing values. */
149
166
  compareViewValues = defaultCompareViewValues,
150
167
  /** isDisabled will be used to determine if the node is disabled. */
151
- isDisabled = () => false) {
168
+ isDisabled = () => false,
169
+ /** Further options: the `trackBy` the nodes are expanded by. */
170
+ options) {
152
171
  super();
153
172
  this.getLevel = getLevel;
154
173
  this.isExpandable = isExpandable;
@@ -157,8 +176,13 @@ class FlatTreeControl extends BaseTreeControl {
157
176
  this.compareValues = compareValues;
158
177
  this.compareViewValues = compareViewValues;
159
178
  this.isDisabled = isDisabled;
179
+ // Positions in each `dataNodes` array: a tree looks up every rendered row, and `indexOf` would make that
180
+ // rows × nodes. Keyed weakly by the array, so replacing `dataNodes` releases the old nodes.
181
+ this.nodeIndexes = new WeakMap();
182
+ this.trackBy = options?.trackBy;
160
183
  this.setFilters(new FilterByViewValue(this), new FilterParentsForNodes(this));
161
184
  }
185
+ // TODO: nothing in the library uses it; kept as public API at the DS-2196 review. Document or deprecate it.
162
186
  getFilters() {
163
187
  return this.filters;
164
188
  }
@@ -172,7 +196,7 @@ class FlatTreeControl extends BaseTreeControl {
172
196
  * with correct levels.
173
197
  */
174
198
  getDescendants(dataNode) {
175
- const startIndex = this.dataNodes.indexOf(dataNode);
199
+ const startIndex = this.indexOfNode(dataNode);
176
200
  const results = [];
177
201
  // Goes through flattened tree nodes in the `dataNodes` array, and get all descendants.
178
202
  // The level of descendants of a tree node must be greater than the level of the given
@@ -192,16 +216,34 @@ class FlatTreeControl extends BaseTreeControl {
192
216
  * data nodes of the tree.
193
217
  */
194
218
  expandAll() {
195
- this.expansionModel.select(...this.dataNodes);
219
+ this.expansionModel.select(...this.dataNodes.map((node) => this.expansionKey(node)));
196
220
  }
197
- getParents(node, result) {
198
- if (node.parent) {
199
- result.unshift(node.parent);
200
- return this.getParents(node.parent, result);
201
- }
202
- else {
221
+ /**
222
+ * Ancestors of a data node, outermost first.
223
+ *
224
+ * Derived from `dataNodes` rather than from a `parent` back-reference: the flattened nodes are in
225
+ * depth-first order, so scanning backwards from the node, the first node of a smaller level is its
226
+ * parent, and repeating with that level yields the whole chain. A data node whose shape carries no
227
+ * `parent` therefore resolves just as well as one that does.
228
+ *
229
+ * @param result Collector the ancestors are prepended to. Provided so callers can accumulate into
230
+ * an existing array; a fresh one is used when omitted.
231
+ */
232
+ getParents(node, result = []) {
233
+ const startIndex = this.indexOfNode(node);
234
+ if (startIndex === -1) {
203
235
  return result;
204
236
  }
237
+ let level = this.getLevel(node);
238
+ for (let i = startIndex - 1; i >= 0 && level > 0; i--) {
239
+ const candidate = this.dataNodes[i];
240
+ const candidateLevel = this.getLevel(candidate);
241
+ if (candidateLevel < level) {
242
+ result.unshift(candidate);
243
+ level = candidateLevel;
244
+ }
245
+ }
246
+ return result;
205
247
  }
206
248
  hasValue(value) {
207
249
  return this.dataNodes?.find((node) => this.compareValues(this.getValue(node), value));
@@ -216,7 +258,7 @@ class FlatTreeControl extends BaseTreeControl {
216
258
  this.filterModel.clear();
217
259
  this.filterModel.select(...result);
218
260
  // set current expansion state according to filtered tree
219
- this.expansionModel.setSelection(...result.filter((node) => this.isExpandable(node)));
261
+ this.expansionModel.setSelection(...result.filter((node) => this.isExpandable(node)).map((node) => this.expansionKey(node)));
220
262
  this.updateFilterValue(value || result);
221
263
  Promise.resolve().then(() => this.restoreExpansionState());
222
264
  }
@@ -233,14 +275,49 @@ class FlatTreeControl extends BaseTreeControl {
233
275
  this.expansionModel.setSelection(...this.expandedItemsBeforeFiltration);
234
276
  }
235
277
  }
278
+ /**
279
+ * Position of the node in `dataNodes`, constant-time while the index matches the array. With `trackBy` a node
280
+ * rebuilt as a new object since is found by its key, as the expansion methods accept it too.
281
+ */
282
+ indexOfNode(node) {
283
+ const { dataNodes, trackBy } = this;
284
+ if (!dataNodes)
285
+ return -1;
286
+ const cached = this.nodeIndexes.get(dataNodes)?.get(node);
287
+ // Checked against the array: `dataNodes` can be mutated in place.
288
+ if (cached !== undefined && dataNodes[cached] === node)
289
+ return cached;
290
+ const index = dataNodes.indexOf(node);
291
+ // A node that is not there leaves the index as it is.
292
+ if (index === -1) {
293
+ if (!trackBy)
294
+ return index;
295
+ const key = trackBy(node);
296
+ return dataNodes.findIndex((candidate) => trackBy(candidate) === key);
297
+ }
298
+ const positions = new Map();
299
+ dataNodes.forEach((dataNode, position) => {
300
+ if (!positions.has(dataNode))
301
+ positions.set(dataNode, position);
302
+ });
303
+ this.nodeIndexes.set(dataNodes, positions);
304
+ return index;
305
+ }
236
306
  }
237
307
 
238
308
  /** Nested tree control. Able to expand/collapse a subtree recursively for NestedNode type. */
239
309
  class NestedTreeControl extends BaseTreeControl {
240
- /** Construct with nested tree function getChildren. */
241
- constructor(getChildren) {
310
+ /**
311
+ * Construct with nested tree function getChildren.
312
+ *
313
+ * @param getChildren Must emit **synchronously** (e.g. `of(children)` or a `BehaviorSubject`).
314
+ * `getDescendants` walks the tree with `take(1)` and returns as soon as the recursion unwinds, so
315
+ * an asynchronous source yields an incomplete — usually empty — descendant list.
316
+ */
317
+ constructor(getChildren, options) {
242
318
  super();
243
319
  this.getChildren = getChildren;
320
+ this.trackBy = options?.trackBy;
244
321
  }
245
322
  /**
246
323
  * Expands all dataNodes in the tree.
@@ -251,7 +328,7 @@ class NestedTreeControl extends BaseTreeControl {
251
328
  expandAll() {
252
329
  this.expansionModel.clear();
253
330
  const allNodes = this.dataNodes.reduce((accumulator, dataNode) => [...accumulator, ...this.getDescendants(dataNode), dataNode], []);
254
- this.expansionModel.select(...allNodes);
331
+ this.expansionModel.select(...allNodes.map((node) => this.expansionKey(node)));
255
332
  }
256
333
  /** Gets a list of descendant dataNodes of a subtree rooted at given data node recursively. */
257
334
  getDescendants(dataNode) {
@@ -278,33 +355,41 @@ class NestedTreeControl extends BaseTreeControl {
278
355
  * Transform nested nodes of type `T` to flattened nodes of type `F`.
279
356
  *
280
357
  * For example, the input data of type `T` is nested, and contains its children data:
281
- * SomeNode: {
358
+ *
359
+ * ```ts
360
+ * SomeNode: {
282
361
  * key: 'Fruits',
283
362
  * children: [
284
- * NodeOne: {
285
- * key: 'Apple',
286
- * },
287
- * NodeTwo: {
288
- * key: 'Pear',
289
- * }
290
- * ]
291
- * }
292
- * After flattener flatten the tree, the structure will become
293
- * SomeNode: {
294
- * key: 'Fruits',
295
- * expandable: true,
296
- * level: 1
297
- * },
298
- * NodeOne: {
299
- * key: 'Apple',
300
- * expandable: false,
301
- * level: 2
302
- * },
303
- * NodeTwo: {
304
- * key: 'Pear',
305
- * expandable: false,
306
- * level: 2
363
+ * NodeOne: {
364
+ * key: 'Apple'
365
+ * },
366
+ * NodeTwo: {
367
+ * key: 'Pear'
368
+ * }
369
+ * ]
370
+ * }
371
+ * ```
372
+ *
373
+ * After flattener flatten the tree, the structure will become
374
+ *
375
+ * ```ts
376
+ * SomeNode: {
377
+ * key: 'Fruits',
378
+ * expandable: true,
379
+ * level: 1
380
+ * },
381
+ * NodeOne: {
382
+ * key: 'Apple',
383
+ * expandable: false,
384
+ * level: 2
385
+ * },
386
+ * NodeTwo: {
387
+ * key: 'Pear',
388
+ * expandable: false,
389
+ * level: 2
307
390
  * }
391
+ * ```
392
+ *
308
393
  * and the output flattened type is `F` with additional information.
309
394
  */
310
395
  class KbqTreeFlattener {
@@ -314,6 +399,7 @@ class KbqTreeFlattener {
314
399
  this.isExpandable = isExpandable;
315
400
  this.getChildren = getChildren;
316
401
  }
402
+ /** @docs-private */
317
403
  flattenNode(node, level, resultNodes, parent) {
318
404
  const flatNode = this.transformFunction(node, level, parent);
319
405
  resultNodes.push(flatNode);
@@ -332,6 +418,7 @@ class KbqTreeFlattener {
332
418
  }
333
419
  return resultNodes;
334
420
  }
421
+ /** @docs-private */
335
422
  flattenChildren(children, level, resultNodes, parent) {
336
423
  children.forEach((child) => {
337
424
  this.flattenNode(child, level + 1, resultNodes, parent);
@@ -350,6 +437,8 @@ class KbqTreeFlattener {
350
437
  /**
351
438
  * Expand flattened node with current expansion status.
352
439
  * The returned list may have different length.
440
+ *
441
+ * Reads only `isExpanded` of the tree control, so it takes a control of any key type.
353
442
  */
354
443
  expandFlattenedNodes(nodes, treeControl) {
355
444
  const results = [];
@@ -379,17 +468,19 @@ var KbqTreeDataSourceChangeTypes;
379
468
  * Data source for flat tree.
380
469
  * The data source need to handle expansion/collapsion of the tree node and change the data feed
381
470
  * to `KbqTree`.
382
- * The nested tree nodes of type `T` are flattened through `MсTreeFlattener`, and converted
471
+ * The nested tree nodes of type `T` are flattened through `KbqTreeFlattener`, and converted
383
472
  * to type `F` for `KbqTree` to consume.
384
473
  */
385
474
  class KbqTreeFlatDataSource extends DataSource {
386
475
  get data() {
387
- return this._data.value;
476
+ return this._data();
388
477
  }
389
478
  set data(value) {
390
- this._data.next(value);
391
- this.flattenedData.next(this.treeFlattener.flattenNodes(this.data));
392
- this.treeControl.dataNodes = this.flattenedData.value;
479
+ this._data.set(value);
480
+ const flattened = this.treeFlattener.flattenNodes(this.data);
481
+ // Assigned before emitting: the tree renders inside `next`, and its rows look themselves up in `dataNodes`.
482
+ this.treeControl.dataNodes = flattened;
483
+ this.flattenedData.next(flattened);
393
484
  }
394
485
  constructor(treeControl, treeFlattener, initialData = []) {
395
486
  super();
@@ -398,7 +489,12 @@ class KbqTreeFlatDataSource extends DataSource {
398
489
  this.flattenedData = new BehaviorSubject([]);
399
490
  this.expandedData = new BehaviorSubject([]);
400
491
  this.filteredData = new BehaviorSubject([]);
401
- this._data = new BehaviorSubject(initialData);
492
+ this._data = signal([], ...(ngDevMode ? [{ debugName: "_data" }] : /* istanbul ignore next */ []));
493
+ this._data.set(initialData);
494
+ // The setter flattens the data for the tree.
495
+ if (initialData.length) {
496
+ this.data = initialData;
497
+ }
402
498
  }
403
499
  connect(collectionViewer) {
404
500
  return merge(collectionViewer.viewChange, this.treeControl.expansionModel.changed.pipe(map((value) => ({ type: KbqTreeDataSourceChangeTypes.Expansion, value }))), this.treeControl.filterValue.pipe(map((value) => ({ type: KbqTreeDataSourceChangeTypes.Filter, value }))), this.flattenedData).pipe(map((changeObj) => {
@@ -465,12 +561,12 @@ class KbqTreeNodeOutletContext {
465
561
  class KbqTreeNodeDef {
466
562
  constructor() {
467
563
  this.template = inject(TemplateRef);
468
- this.data = input(undefined, ...(ngDevMode ? [{ debugName: "data", alias: 'kbqTreeNode' }] : [{ alias: 'kbqTreeNode' }]));
564
+ this.data = input(undefined, { ...(ngDevMode ? { debugName: "data" } : /* istanbul ignore next */ {}), alias: 'kbqTreeNode' });
469
565
  }
470
- /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqTreeNodeDef, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
471
- /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.30", type: KbqTreeNodeDef, isStandalone: true, selector: "[kbqTreeNodeDef]", inputs: { when: { classPropertyName: "when", publicName: "kbqTreeNodeDefWhen", isSignal: false, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "kbqTreeNode", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 }); }
566
+ /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqTreeNodeDef, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
567
+ /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.25", type: KbqTreeNodeDef, isStandalone: true, selector: "[kbqTreeNodeDef]", inputs: { when: { classPropertyName: "when", publicName: "kbqTreeNodeDefWhen", isSignal: false, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "kbqTreeNode", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 }); }
472
568
  }
473
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqTreeNodeDef, decorators: [{
569
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqTreeNodeDef, decorators: [{
474
570
  type: Directive,
475
571
  args: [{
476
572
  selector: '[kbqTreeNodeDef]',
@@ -481,12 +577,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImpo
481
577
  class KbqTreeNodeOutlet {
482
578
  constructor() {
483
579
  this.viewContainer = inject(ViewContainerRef);
484
- this.changeDetectorRef = inject(ChangeDetectorRef);
485
580
  }
486
- /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqTreeNodeOutlet, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
487
- /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.30", type: KbqTreeNodeOutlet, isStandalone: true, selector: "[kbqTreeNodeOutlet]", ngImport: i0 }); }
581
+ /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqTreeNodeOutlet, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
582
+ /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.25", type: KbqTreeNodeOutlet, isStandalone: true, selector: "[kbqTreeNodeOutlet]", ngImport: i0 }); }
488
583
  }
489
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqTreeNodeOutlet, decorators: [{
584
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqTreeNodeOutlet, decorators: [{
490
585
  type: Directive,
491
586
  args: [{
492
587
  selector: '[kbqTreeNodeOutlet]'
@@ -495,6 +590,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImpo
495
590
 
496
591
  /**
497
592
  * Returns an error to be thrown when there is no usable data.
593
+ *
498
594
  * @docs-private
499
595
  */
500
596
  function getTreeNoValidDataSourceError() {
@@ -502,6 +598,7 @@ function getTreeNoValidDataSourceError() {
502
598
  }
503
599
  /**
504
600
  * Returns an error to be thrown when there are multiple nodes that are missing a when function.
601
+ *
505
602
  * @docs-private
506
603
  */
507
604
  function getTreeMultipleDefaultNodeDefsError() {
@@ -509,6 +606,7 @@ function getTreeMultipleDefaultNodeDefsError() {
509
606
  }
510
607
  /**
511
608
  * Returns an error to be thrown when there are no matching node defs for a particular set of data.
609
+ *
512
610
  * @docs-private
513
611
  */
514
612
  function getTreeMissingMatchingNodeDefError() {
@@ -516,62 +614,169 @@ function getTreeMissingMatchingNodeDefError() {
516
614
  }
517
615
  /**
518
616
  * Returns an error to be thrown when there are tree control.
617
+ *
519
618
  * @docs-private
520
619
  */
521
620
  function getTreeControlMissingError() {
522
621
  return Error(`Could not find a tree control for the tree.`);
523
622
  }
524
623
  /**
525
- * Returns an error to be thrown when tree control did not implement functions for flat/nested node.
624
+ * Returns an error to be thrown when the selection mode of a tree is changed while its `SelectionModel`
625
+ * belongs to a host `KbqTreeSelect`.
626
+ *
526
627
  * @docs-private
527
628
  */
528
- function getTreeControlFunctionsMissingError() {
529
- return Error(`Could not find functions for nested/flat tree in tree control.`);
629
+ function getKbqTreeSelectionOwnedMultipleError() {
630
+ return Error('Cannot change the multiplicity of `multiple` on a `kbq-tree-selection` rendered inside a ' +
631
+ '`kbq-tree-select`: the select owns the selection model. Set `multiple` on the select instead.');
530
632
  }
531
633
 
634
+ /**
635
+ * Coerces a raw persisted payload into a `KbqTreeState`, returning `null` for anything unrecognizable.
636
+ *
637
+ * Web storage is origin-wide and user-writable, so a payload is never trusted — without this, an entry
638
+ * such as `{"a": null}` would reach `hasValue()` while restoring.
639
+ */
640
+ const normalizeTreeState = (parsed) => {
641
+ if (!Array.isArray(parsed))
642
+ return null;
643
+ const values = parsed.filter((value) => typeof value === 'string');
644
+ // An array that held nothing usable is somebody else's payload, not "nothing was expanded" — the
645
+ // difference matters, because only the second one is a state worth keeping.
646
+ return values.length || !parsed.length ? values : null;
647
+ };
648
+ /**
649
+ * Rendering core of the tree.
650
+ *
651
+ * Originally forked from `@angular/cdk/tree` and maintained independently since: the node/outlet
652
+ * contract, the option-based selection model and the filtering pipeline have all diverged, so
653
+ * `@angular/cdk/tree` is deliberately not a dependency of this package and upstream fixes have to be
654
+ * ported by hand.
655
+ *
656
+ * `C` narrows the tree control a concrete tree accepts, and so the type its `treeControl` binding is checked against.
657
+ * The bound leaves out `expansionModel` and `trackBy`, the members typed by the control's key, so that it admits
658
+ * a control of any key type: the model makes a control invariant in that type.
659
+ */
532
660
  class KbqTreeBase {
661
+ /** Controls the expanded state and holds the data nodes of the tree. */
662
+ get treeControl() {
663
+ return this.treeControlInput();
664
+ }
665
+ /** {@link treeControl} as state saving reads it: by node value, which only a `FlatTreeControl` has. */
666
+ get flatTreeControl() {
667
+ const treeControl = this.treeControl;
668
+ return treeControl;
669
+ }
670
+ /** Outlet within the tree's template where the data nodes are inserted. */
671
+ get nodeOutlet() {
672
+ return this.nodeOutletQuery();
673
+ }
674
+ /**
675
+ * Provides a stream containing the latest data array to render. Influenced by the tree's
676
+ * stream of view window (what dataNodes are currently on screen).
677
+ * Data source can be an observable of data array, or a data array to render.
678
+ */
679
+ get dataSource() {
680
+ return this._dataSource;
681
+ }
533
682
  constructor() {
534
683
  this.differs = inject(IterableDiffers);
535
684
  this.changeDetectorRef = inject(ChangeDetectorRef);
685
+ /**
686
+ * Persistence of the expanded state, applied as a host directive by the concrete tree components.
687
+ * Optional because `KbqTreeBase` is exported: a tree without the directive persists nothing.
688
+ */
689
+ this.stateSaving = inject(KbqStateSaving, { optional: true });
690
+ /** @docs-private */
691
+ this.treeControlInput = input(undefined, { ...(ngDevMode ? { debugName: "treeControlInput" } : /* istanbul ignore next */ {}), alias: 'treeControl' });
536
692
  /**
537
693
  * Tracking function that will be used to check the differences in data changes. Used similarly
538
694
  * to `ngFor` `trackBy` function. Optimize node operations by identifying a node based on its data
539
695
  * relative to the function to know if a node should be added/removed/moved.
540
696
  * Accepts a function that takes two parameters, `index` and `item`.
697
+ *
698
+ * Views are reused for nodes the function reports as unchanged, which a data source that rebuilds
699
+ * its node objects on every emission — a flattener among them — otherwise cannot get.
700
+ *
701
+ * Defaults to the `trackBy` of the tree control, read when the tree initializes and when the data source changes.
541
702
  */
542
- this.trackBy = input(undefined, ...(ngDevMode ? [{ debugName: "trackBy" }] : []));
543
- // TODO(tinayuangao): Setup a listener for scrolling, emit the calculated view to viewChange.
544
- // Remove the MAX_VALUE in viewChange
703
+ this.trackBy = input(undefined, ...(ngDevMode ? [{ debugName: "trackBy" }] : /* istanbul ignore next */ []));
704
+ this.nodeOutletQuery = viewChild(KbqTreeNodeOutlet, ...(ngDevMode ? [{ debugName: "nodeOutletQuery" }] : /* istanbul ignore next */ []));
705
+ /** The tree node template for the tree */
706
+ this.nodeDefs = contentChildren(KbqTreeNodeDef, ...(ngDevMode ? [{ debugName: "nodeDefs" }] : /* istanbul ignore next */ []));
545
707
  /**
546
708
  * Stream containing the latest information on what rows are being displayed on screen.
547
709
  * Can be used by the data source to as a heuristic of what data should be provided.
710
+ *
711
+ * The tree renders every expanded node eagerly, so the window is the whole data set; a data source
712
+ * cannot use it to page or virtualize. Windowing would have to emit a real range from a scroll
713
+ * listener here first.
548
714
  */
549
715
  this.viewChange = new BehaviorSubject({ start: 0, end: Number.MAX_VALUE });
550
716
  /** Level of nodes */
551
717
  this.levels = new Map();
718
+ /** Most recently constructed node of this tree, see `registerNode`. */
719
+ this.recentNode = null;
720
+ /** Node rendered for a given outlet context, so a reused view can be handed its new data. */
721
+ this.nodesByContext = new WeakMap();
722
+ /**
723
+ * Values from the persisted state whose node has not appeared in `treeControl.dataNodes` yet —
724
+ * applied as the nodes show up, and dropped the first time each node is seen.
725
+ */
726
+ this.pendingValues = new Set();
727
+ /** The `dataNodes` the last restore ran against, so an unchanged list is not walked again. */
728
+ this.lastRestoredDataNodes = null;
729
+ /**
730
+ * Whether the persisted state has been read. `KbqTreeSelect` calls `ngAfterContentInit()` by hand on
731
+ * the tree it projects into its panel, and a second read would resurrect values the user dismissed.
732
+ */
733
+ this.hasRead = false;
734
+ /** Whether the dev-mode warnings below have already been logged, so each is logged once. */
735
+ this.warnedAboutTreeControl = false;
736
+ this.warnedAboutValues = false;
737
+ /** @docs-private */
738
+ this.dataSourceInput = input(undefined, { ...(ngDevMode ? { debugName: "dataSourceInput" } : /* istanbul ignore next */ {}), alias: 'dataSource' });
739
+ this._dataSource = null;
552
740
  this.destroyRef = inject(DestroyRef);
553
- }
554
- /**
555
- * Provides a stream containing the latest data array to render. Influenced by the tree's
556
- * stream of view window (what dataNodes are currently on screen).
557
- * Data source can be an observable of data array, or a data array to render.
558
- */
559
- // TODO: Skipped for migration because:
560
- // Accessor inputs cannot be migrated as they are too complex.
561
- get dataSource() {
562
- return this._dataSource;
563
- }
564
- set dataSource(dataSource) {
565
- if (this._dataSource !== dataSource) {
566
- this.switchDataSource(dataSource);
567
- }
741
+ /** Whether `ngAfterContentChecked` has run, i.e. the node definitions the first render needs are resolved. */
742
+ this.contentChecked = false;
743
+ // Switching the source drops the rendered nodes and resubscribes, which a bound value alone does not do. A
744
+ // binding back to `undefined` clears the tree as `null` does; an unbound input equals the initial `null`.
745
+ effect(() => {
746
+ const dataSource = this.dataSourceInput() ?? null;
747
+ untracked(() => {
748
+ if (dataSource !== this._dataSource)
749
+ this.switchDataSource(dataSource);
750
+ });
751
+ });
568
752
  }
569
753
  ngOnInit() {
570
- this.dataDiffer = this.differs.find([]).create(this.trackBy());
754
+ this.dataDiffer = this.createDataDiffer();
571
755
  if (!this.treeControl) {
572
756
  throw getTreeControlMissingError();
573
757
  }
574
758
  }
759
+ ngAfterContentInit() {
760
+ // Before `ngAfterContentChecked` connects the data source, so the restored nodes are expanded
761
+ // ahead of the first render rather than causing a second one.
762
+ if (this.hasRead || !this.persists)
763
+ return;
764
+ this.hasRead = true;
765
+ // The state lives under the new key now, so restore from it.
766
+ this.stateSaving.keyChanges.subscribe(() => this.restoreState());
767
+ this.restoreState();
768
+ }
769
+ /** Reads the persisted expansion and applies it. Runs while initializing, and again on a key change. */
770
+ restoreState() {
771
+ if (!this.persists)
772
+ return;
773
+ const savedState = this.stateSaving.read(normalizeTreeState);
774
+ this.pendingValues = new Set(savedState ?? []);
775
+ // The memo that keeps one batch of nodes from being examined twice. A restore from another key
776
+ // has new values to match against the same nodes, so it has to be allowed to look again.
777
+ this.lastRestoredDataNodes = null;
778
+ this.restorePending();
779
+ }
575
780
  ngOnDestroy() {
576
781
  this.nodeOutlet.viewContainer.clear();
577
782
  if (this._dataSource && typeof this.dataSource.disconnect === 'function') {
@@ -583,20 +788,65 @@ class KbqTreeBase {
583
788
  }
584
789
  }
585
790
  ngAfterContentChecked() {
586
- const defaultNodeDefs = this.nodeDefs.filter((def) => !def.when);
791
+ const defaultNodeDefs = this.nodeDefs().filter((def) => !def.when);
587
792
  if (defaultNodeDefs.length > 1) {
588
793
  throw getTreeMultipleDefaultNodeDefsError();
589
794
  }
590
795
  this.defaultNodeDef = defaultNodeDefs[0];
591
- if (this.dataSource && this.nodeDefs && !this.dataSubscription) {
796
+ this.contentChecked = true;
797
+ if (this.dataSource && this.nodeDefs().length && !this.dataSubscription) {
592
798
  this.observeRenderChanges();
593
799
  }
594
800
  }
801
+ /**
802
+ * Persists the values of the currently expanded nodes.
803
+ *
804
+ * Called for every expansion and collapse a user performs. Expansion driven by the application —
805
+ * `treeControl.expandAll()`, or writing to `expansionModel` — is not persisted; call this to record it.
806
+ *
807
+ * A no-op while a filter is active: what is expanded then is the result set, not a chosen state.
808
+ */
809
+ saveState() {
810
+ // Untracked, as in `clearSavedState()`: called from a consumer's `effect()`, the inputs read on the way would
811
+ // make the effect run again whenever they change.
812
+ untracked(() => {
813
+ if (!this.persists || this.treeControl.filterValue.value?.length)
814
+ return;
815
+ this.stateSaving.write(this.expandedValues());
816
+ });
817
+ }
818
+ /**
819
+ * Removes the state persisted for this tree.
820
+ *
821
+ * Persistence itself stays on — the next expansion is written again.
822
+ */
823
+ clearSavedState() {
824
+ untracked(() => this.stateSaving?.clear());
825
+ }
826
+ /**
827
+ * Whether state is currently persisted for this tree — restored on init, or written since.
828
+ * Always `false` while `useStateSaving` is unset, and `false` again after `clearSavedState()`.
829
+ */
830
+ get hasSavedState() {
831
+ return this.stateSaving?.state != null;
832
+ }
595
833
  /** Check for changes made in the data and render each change (node added/removed/moved). */
596
834
  renderNodeChanges(data, dataDiffer = this.dataDiffer, viewContainer = this.nodeOutlet.viewContainer, parentData) {
835
+ if (this.applyNodeChanges(data, dataDiffer, viewContainer, parentData)) {
836
+ this.changeDetectorRef.detectChanges();
837
+ }
838
+ }
839
+ /**
840
+ * Applies the data changes to the view container without running change detection, and reports
841
+ * whether anything moved. Split out of `renderNodeChanges` so a subclass can update the state its
842
+ * own template reads before the single change-detection pass, instead of running a second one.
843
+ *
844
+ * @docs-private
845
+ */
846
+ applyNodeChanges(data, dataDiffer, viewContainer, parentData) {
597
847
  const changes = dataDiffer.diff(data);
598
848
  if (!changes) {
599
- return;
849
+ return false;
600
850
  }
601
851
  changes.forEachOperation((item, adjustedPreviousIndex, currentIndex) => {
602
852
  if (item.previousIndex == null) {
@@ -611,7 +861,30 @@ class KbqTreeBase {
611
861
  viewContainer.move(view, currentIndex);
612
862
  }
613
863
  });
614
- this.changeDetectorRef.detectChanges();
864
+ // A node kept its identity but is a different object — what a data source that rebuilds its
865
+ // nodes on every emission produces, a flattener among them. The view is reused, so the object
866
+ // it and its `KbqTreeNode` still hold is gone from `dataNodes`, and every lookup keyed on the
867
+ // node reference (`getDescendants`, `isExpanded`, the selection) would miss it.
868
+ changes.forEachIdentityChange((record) => {
869
+ this.refreshNodeData(viewContainer, record.currentIndex, record.item);
870
+ });
871
+ return true;
872
+ }
873
+ refreshNodeData(viewContainer, index, nodeData) {
874
+ const view = viewContainer.get(index);
875
+ if (!view) {
876
+ return;
877
+ }
878
+ const { context } = view;
879
+ const previousData = context.$implicit;
880
+ context.$implicit = nodeData;
881
+ this.levels.delete(previousData);
882
+ this.levels.set(nodeData, context.level);
883
+ const node = this.nodesByContext.get(context);
884
+ if (node) {
885
+ node.data = nodeData;
886
+ node.refresh();
887
+ }
615
888
  }
616
889
  /**
617
890
  * Finds the matching node definition that should be used for this node data. If there is only
@@ -620,10 +893,11 @@ class KbqTreeBase {
620
893
  * definition.
621
894
  */
622
895
  getNodeDef(data, i) {
623
- if (this.nodeDefs.length === 1) {
624
- return this.nodeDefs.first;
896
+ const nodeDefs = this.nodeDefs();
897
+ if (nodeDefs.length === 1) {
898
+ return nodeDefs[0];
625
899
  }
626
- const nodeDef = this.nodeDefs.find((def) => def.when && def.when(i, data)) || this.defaultNodeDef;
900
+ const nodeDef = nodeDefs.find((def) => def.when && def.when(i, data)) || this.defaultNodeDef;
627
901
  if (!nodeDef) {
628
902
  throw getTreeMissingMatchingNodeDefError();
629
903
  }
@@ -637,6 +911,7 @@ class KbqTreeBase {
637
911
  const node = this.getNodeDef(nodeData, index);
638
912
  // Node context that will be provided to created embedded view
639
913
  const context = new KbqTreeNodeOutletContext(nodeData);
914
+ context.index = index;
640
915
  // If the tree is flat tree, then use the `getLevel` function in flat tree control
641
916
  // Otherwise, use the level of parent node.
642
917
  const treeControl = this.treeControl;
@@ -653,12 +928,106 @@ class KbqTreeBase {
653
928
  // Use default tree nodeOutlet, or nested node's nodeOutlet
654
929
  const container = viewContainer ? viewContainer : this.nodeOutlet.viewContainer;
655
930
  container.createEmbeddedView(node.template, context, index);
656
- // Set the data to just created `KbqTreeNode`.
657
- // The `KbqTreeNode` created from `createEmbeddedView` will be saved in static variable
658
- // `mostRecentTreeNode`. We get it from static variable and pass the node data to it.
659
- if (KbqTreeNode.mostRecentTreeNode) {
660
- KbqTreeNode.mostRecentTreeNode.data = nodeData;
931
+ // The `KbqTreeNode` instantiated by `createEmbeddedView` registers itself here on construction,
932
+ // which is the only handle onto it — the embedded view exposes its context, not its directives.
933
+ // It is remembered against that context so a later re-render can reach it again.
934
+ if (this.recentNode) {
935
+ this.recentNode.data = nodeData;
936
+ this.nodesByContext.set(context, this.recentNode);
937
+ this.recentNode = null;
938
+ }
939
+ }
940
+ /**
941
+ * Called by a `KbqTreeNode` while it is being constructed, so `insertNode` can hand it its data.
942
+ *
943
+ * @docs-private
944
+ */
945
+ registerNode(node) {
946
+ this.recentNode = node;
947
+ }
948
+ /** Whether this tree reads and writes its expanded state at all. */
949
+ get persists() {
950
+ if (!this.stateSaving?.useStateSaving())
951
+ return false;
952
+ // A tree that is not in the document has no stable key — the default resolver derives one from
953
+ // the path to `<body>`. That is the ordinary state of a tree projected into an overlay, such as
954
+ // the one `kbq-tree-select` renders into its panel, whose expansion is transient UI rather than
955
+ // a setting worth carrying to the next visit.
956
+ if (!this.stateSaving.host?.isConnected)
957
+ return false;
958
+ if (typeof this.flatTreeControl.getValue !== 'function') {
959
+ if (isDevMode() && !this.warnedAboutTreeControl) {
960
+ this.warnedAboutTreeControl = true;
961
+ // eslint-disable-next-line no-console
962
+ console.warn('kbq-tree: state saving is enabled, but the tree control has no `getValue`. ' +
963
+ 'Expansion is persisted by node value, and a node object does not survive a ' +
964
+ 'reload, so nothing is persisted. Use `FlatTreeControl`, or unset ' +
965
+ '`useStateSaving`.');
966
+ }
967
+ return false;
661
968
  }
969
+ return true;
970
+ }
971
+ /**
972
+ * Expands every pending value whose node is present, and stops tracking it.
973
+ *
974
+ * Idempotent, and safe to call on every render: the pending set only shrinks, so a tree that has
975
+ * restored everything does no work at all.
976
+ */
977
+ restorePending() {
978
+ if (!this.pendingValues.size)
979
+ return;
980
+ const currentNodes = this.treeControl.dataNodes;
981
+ // Nothing new to match against. Deliberately does not record an empty list, so the first real
982
+ // batch of an asynchronously loaded tree is still examined.
983
+ if (currentNodes === this.lastRestoredDataNodes || !currentNodes?.length)
984
+ return;
985
+ this.lastRestoredDataNodes = currentNodes;
986
+ const treeControl = this.flatTreeControl;
987
+ const found = [];
988
+ for (const value of this.pendingValues) {
989
+ const node = treeControl.hasValue(value);
990
+ if (node) {
991
+ found.push(node);
992
+ this.pendingValues.delete(value);
993
+ }
994
+ }
995
+ // Straight at the model rather than through `expand()`, which is a no-op while a filter is
996
+ // active — restoring must not depend on what the user happens to be searching for.
997
+ if (found.length) {
998
+ const { trackBy } = treeControl;
999
+ const keys = trackBy ? found.map((node) => trackBy(node)) : found;
1000
+ this.stateSaving.applying(() => treeControl.expansionModel.select(...keys));
1001
+ }
1002
+ }
1003
+ /** The values of the nodes that are currently expanded, plus the ones still waiting to appear. */
1004
+ expandedValues() {
1005
+ const treeControl = this.flatTreeControl;
1006
+ const expanded = [];
1007
+ let skipped = false;
1008
+ // With `trackBy` the model holds keys, which have no value: only the current nodes map back to them.
1009
+ const expandedNodes = treeControl.trackBy
1010
+ ? (treeControl.dataNodes ?? []).filter((node) => treeControl.isExpanded(node))
1011
+ : treeControl.expansionModel.selected;
1012
+ for (const node of expandedNodes) {
1013
+ const value = treeControl.getValue(node);
1014
+ if (typeof value === 'string') {
1015
+ expanded.push(value);
1016
+ }
1017
+ else {
1018
+ skipped = true;
1019
+ }
1020
+ }
1021
+ if (skipped && isDevMode() && !this.warnedAboutValues) {
1022
+ this.warnedAboutValues = true;
1023
+ // eslint-disable-next-line no-console
1024
+ console.warn('kbq-tree: `getValue` returned a value that is not a string for at least one node. ' +
1025
+ 'Expansion is persisted as JSON keyed by that value, so those nodes are left out.');
1026
+ }
1027
+ // Union with what is still pending: on a tree whose data arrives in batches the expanded nodes
1028
+ // are only part of what was saved, and writing the snapshot alone would drop every branch that
1029
+ // has not been loaded yet.
1030
+ return [...new Set([...expanded, ...this.pendingValues])];
662
1031
  }
663
1032
  /** Set up a subscription for the data provided by the data source. */
664
1033
  observeRenderChanges() {
@@ -675,9 +1044,15 @@ class KbqTreeBase {
675
1044
  dataStream = of(this._dataSource);
676
1045
  }
677
1046
  if (dataStream) {
678
- this.dataSubscription = dataStream
679
- .pipe(takeUntilDestroyed(this.destroyRef))
680
- .subscribe((data) => this.renderNodeChanges(data));
1047
+ this.dataSubscription = dataStream.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((data) => {
1048
+ this.renderNodeChanges(data);
1049
+ // On a microtask, and only while something is still pending: expanding re-enters this
1050
+ // very subscription — the flat data source merges `expansionModel.changed` — and
1051
+ // `renderNodeChanges` has just run `detectChanges()`.
1052
+ if (this.pendingValues.size) {
1053
+ Promise.resolve().then(() => this.restorePending());
1054
+ }
1055
+ });
681
1056
  }
682
1057
  else {
683
1058
  throw getTreeNoValidDataSourceError();
@@ -696,35 +1071,48 @@ class KbqTreeBase {
696
1071
  this.dataSubscription.unsubscribe();
697
1072
  this.dataSubscription = null;
698
1073
  }
699
- // Remove the all dataNodes if there is now no data source
700
- if (!dataSource) {
701
- this.nodeOutlet.viewContainer.clear();
702
- }
1074
+ // Every rendered node belongs to the previous source, so none of them survives the switch. The
1075
+ // differ is reset below and no longer reports them as removals, which makes these two the only
1076
+ // things that drop the old nodes — for a null source and for a replacement source alike. Left
1077
+ // to the differ, `levels` would keep an entry, and with it a strong reference, for every node
1078
+ // of every source the tree has ever been given.
1079
+ this.nodeOutlet.viewContainer.clear();
1080
+ this.levels.clear();
703
1081
  this._dataSource = dataSource;
704
- if (this.nodeDefs) {
1082
+ // The differ remembers the nodes of the previous source. Left in place, the first diff against
1083
+ // the new source is computed as a delta from data that is no longer rendered, so views are
1084
+ // reused for unrelated nodes or dropped entirely.
1085
+ this.dataDiffer = this.createDataDiffer();
1086
+ // Not before the first `ngAfterContentChecked`: that is where the default node definition is resolved,
1087
+ // and a render ahead of it finds no definition for the nodes and throws, taking the subscription down
1088
+ // with it and leaving the tree permanently empty. The initial render is picked up there; a later
1089
+ // source swap is observed here right away.
1090
+ if (dataSource && this.contentChecked && this.nodeDefs().length) {
705
1091
  this.observeRenderChanges();
706
1092
  }
707
1093
  }
708
- /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqTreeBase, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
709
- /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.30", type: KbqTreeBase, isStandalone: true, inputs: { treeControl: { classPropertyName: "treeControl", publicName: "treeControl", isSignal: false, isRequired: false, transformFunction: null }, trackBy: { classPropertyName: "trackBy", publicName: "trackBy", isSignal: true, isRequired: false, transformFunction: null }, dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: false, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "nodeDefs", predicate: KbqTreeNodeDef }], viewQueries: [{ propertyName: "nodeOutlet", first: true, predicate: KbqTreeNodeOutlet, descendants: true, static: true }], ngImport: i0 }); }
1094
+ createDataDiffer() {
1095
+ // The bound of `C` leaves `trackBy` out; the key type is the control's own, so it is read as `unknown` here.
1096
+ const controlTrackBy = this.treeControl?.trackBy;
1097
+ const trackBy = this.trackBy() ?? (controlTrackBy && ((_, node) => controlTrackBy(node)));
1098
+ return this.differs.find([]).create(trackBy);
1099
+ }
1100
+ /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqTreeBase, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1101
+ /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "21.2.25", type: KbqTreeBase, isStandalone: true, inputs: { treeControlInput: { classPropertyName: "treeControlInput", publicName: "treeControl", isSignal: true, isRequired: false, transformFunction: null }, trackBy: { classPropertyName: "trackBy", publicName: "trackBy", isSignal: true, isRequired: false, transformFunction: null }, dataSourceInput: { classPropertyName: "dataSourceInput", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "nodeDefs", predicate: KbqTreeNodeDef, isSignal: true }], viewQueries: [{ propertyName: "nodeOutletQuery", first: true, predicate: KbqTreeNodeOutlet, descendants: true, isSignal: true }], ngImport: i0 }); }
710
1102
  }
711
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqTreeBase, decorators: [{
1103
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqTreeBase, decorators: [{
712
1104
  type: Directive
713
- }], propDecorators: { treeControl: [{
714
- type: Input
715
- }], trackBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "trackBy", required: false }] }], nodeOutlet: [{
716
- type: ViewChild,
717
- args: [KbqTreeNodeOutlet, { static: true }]
718
- }], nodeDefs: [{
719
- type: ContentChildren,
720
- args: [KbqTreeNodeDef]
721
- }], dataSource: [{
722
- type: Input
723
- }] } });
1105
+ }], ctorParameters: () => [], propDecorators: { treeControlInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "treeControl", required: false }] }], trackBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "trackBy", required: false }] }], nodeOutletQuery: [{ type: i0.ViewChild, args: [i0.forwardRef(() => KbqTreeNodeOutlet), { isSignal: true }] }], nodeDefs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => KbqTreeNodeDef), { isSignal: true }] }], dataSourceInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataSource", required: false }] }] } });
1106
+ // `KbqTree` declares `role="tree"`, whose owned elements have to be `treeitem`s — and a bare
1107
+ // `kbq-tree-node` is the only kind of row it can render, since `KbqTreeOption` needs a parent only
1108
+ // `KbqTreeSelection` provides. The nodes are rendered flat into a single outlet, so the depth an AT
1109
+ // reports comes from `aria-level` rather than from the DOM.
724
1110
  class KbqTreeNode {
725
1111
  /**
726
- * The most recently created `KbqTreeNode`. We save it in static variable so we can retrieve it
727
- * in `KbqTree` and set the data to it.
1112
+ * The most recently created `KbqTreeNode`, across every tree on the page.
1113
+ *
1114
+ * @deprecated Kept for backwards compatibility only — the tree hands a node its data through
1115
+ * `KbqTreeBase.registerNode`, which is scoped to the tree that owns the node. Will be removed in 22.0.0.
728
1116
  */
729
1117
  static { this.mostRecentTreeNode = null; }
730
1118
  get data() {
@@ -744,89 +1132,102 @@ class KbqTreeNode {
744
1132
  this.elementRef = inject(ElementRef);
745
1133
  this.tree = inject(KbqTreeBase);
746
1134
  this.destroyed = new Subject();
1135
+ /**
1136
+ * Emits after the tree reused this node's view for a different data object, so a directive on the
1137
+ * same element can re-derive what it computed from the previous one.
1138
+ *
1139
+ * @docs-private
1140
+ */
1141
+ this.refreshed = new Subject();
747
1142
  KbqTreeNode.mostRecentTreeNode = this;
1143
+ this.tree.registerNode(this);
748
1144
  }
749
1145
  ngOnDestroy() {
750
1146
  this.destroyed.next();
751
1147
  this.destroyed.complete();
1148
+ this.refreshed.complete();
1149
+ }
1150
+ /**
1151
+ * Called by the tree once `data` has been replaced on a reused view. State a subclass derived from
1152
+ * the previous node — its value, its level — is stale at this point and has to be recomputed.
1153
+ *
1154
+ * @docs-private
1155
+ */
1156
+ refresh() {
1157
+ this.refreshed.next();
752
1158
  }
753
1159
  focus() {
754
1160
  this.elementRef.nativeElement.focus();
755
1161
  }
756
- /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqTreeNode, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
757
- /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.30", type: KbqTreeNode, isStandalone: true, selector: "kbq-tree-node", exportAs: ["kbqTreeNode"], ngImport: i0 }); }
1162
+ /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqTreeNode, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1163
+ /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.25", type: KbqTreeNode, isStandalone: true, selector: "kbq-tree-node", host: { attributes: { "role": "treeitem" }, properties: { "attr.aria-level": "level + 1" } }, exportAs: ["kbqTreeNode"], ngImport: i0 }); }
758
1164
  }
759
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqTreeNode, decorators: [{
1165
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqTreeNode, decorators: [{
760
1166
  type: Directive,
761
1167
  args: [{
762
1168
  selector: 'kbq-tree-node',
1169
+ host: {
1170
+ role: 'treeitem',
1171
+ '[attr.aria-level]': 'level + 1'
1172
+ },
763
1173
  exportAs: 'kbqTreeNode'
764
1174
  }]
765
1175
  }], ctorParameters: () => [] });
766
1176
 
767
1177
  /** @docs-private */
768
1178
  class KbqTreeNodeToggleBaseDirective {
769
- // TODO: Skipped for migration because:
770
- // Accessor inputs cannot be migrated as they are too complex.
771
- get recursive() {
772
- return this._recursive;
773
- }
774
- set recursive(value) {
775
- this._recursive = coerceBooleanProperty(value);
1179
+ constructor() {
1180
+ this.tree = inject(KbqTreeBase);
1181
+ this.treeNode = inject(KbqTreeNode);
1182
+ this.node = input(undefined, ...(ngDevMode ? [{ debugName: "node" }] : /* istanbul ignore next */ []));
1183
+ /** Whether toggling expands or collapses the whole subtree instead of the node alone. */
1184
+ this.recursive = input(false, { ...(ngDevMode ? { debugName: "recursive" } : /* istanbul ignore next */ {}), alias: 'kbqTreeNodeToggleRecursive', transform: booleanAttribute });
1185
+ /**
1186
+ * Backing input of `disabled`. Bind through the `disabled` attribute; read the `disabled` getter,
1187
+ * which also reports the toggle disabled while a filter is active.
1188
+ *
1189
+ * @docs-private
1190
+ */
1191
+ this.disabledInput = input(false, { ...(ngDevMode ? { debugName: "disabledInput" } : /* istanbul ignore next */ {}), alias: 'disabled', transform: booleanAttribute });
1192
+ /** Set while a filter is active: filtering already decides what is expanded. */
1193
+ this.filterDisabled = toSignal(this.tree.treeControl.filterValue.pipe(map((value) => !!value?.length)), { initialValue: false });
1194
+ this.disabledState = computed(() => this.disabledInput() || this.filterDisabled(), ...(ngDevMode ? [{ debugName: "disabledState" }] : /* istanbul ignore next */ []));
776
1195
  }
777
- // TODO: Skipped for migration because:
778
- // Accessor inputs cannot be migrated as they are too complex.
779
1196
  get disabled() {
780
- return this._disabled;
781
- }
782
- set disabled(value) {
783
- if (value !== this.disabled) {
784
- this._disabled = value;
785
- }
1197
+ return this.disabledState();
786
1198
  }
787
1199
  get iconState() {
788
- return this.tree.treeControl.isExpanded(this.node());
789
- }
790
- constructor() {
791
- this.tree = inject(KbqTreeBase);
792
- this.treeNode = inject(KbqTreeNode);
793
- this.node = input(undefined, ...(ngDevMode ? [{ debugName: "node" }] : []));
794
- this._recursive = false;
795
- this._disabled = false;
796
- this.tree.treeControl.filterValue.subscribe((value) => (this.disabled = !!value?.length));
1200
+ // The node `toggle()` acts on when `node` is not bound: an unbound `node` would reach the control's
1201
+ // `trackBy` as `undefined`.
1202
+ return this.tree.treeControl.isExpanded(this.node() ?? this.treeNode.data);
797
1203
  }
798
1204
  toggle(event) {
799
1205
  if (this.disabled)
800
1206
  return;
801
- if (this.recursive) {
1207
+ if (this.recursive()) {
802
1208
  this.tree.treeControl.toggleDescendants(this.treeNode.data);
803
1209
  }
804
1210
  else {
805
1211
  this.tree.treeControl.toggle(this.treeNode.data);
806
1212
  }
1213
+ this.tree.saveState();
807
1214
  event.stopPropagation();
808
1215
  }
809
- /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqTreeNodeToggleBaseDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
810
- /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.30", type: KbqTreeNodeToggleBaseDirective, isStandalone: true, inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: false, transformFunction: null }, recursive: { classPropertyName: "recursive", publicName: "kbqTreeNodeToggleRecursive", isSignal: false, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: false, isRequired: false, transformFunction: booleanAttribute } }, ngImport: i0 }); }
1216
+ /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqTreeNodeToggleBaseDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1217
+ /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.25", type: KbqTreeNodeToggleBaseDirective, isStandalone: true, inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: false, transformFunction: null }, recursive: { classPropertyName: "recursive", publicName: "kbqTreeNodeToggleRecursive", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 }); }
811
1218
  }
812
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqTreeNodeToggleBaseDirective, decorators: [{
1219
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqTreeNodeToggleBaseDirective, decorators: [{
813
1220
  type: Directive
814
- }], ctorParameters: () => [], propDecorators: { node: [{ type: i0.Input, args: [{ isSignal: true, alias: "node", required: false }] }], recursive: [{
815
- type: Input,
816
- args: ['kbqTreeNodeToggleRecursive']
817
- }], disabled: [{
818
- type: Input,
819
- args: [{ transform: booleanAttribute }]
820
- }] } });
1221
+ }], propDecorators: { node: [{ type: i0.Input, args: [{ isSignal: true, alias: "node", required: false }] }], recursive: [{ type: i0.Input, args: [{ isSignal: true, alias: "kbqTreeNodeToggleRecursive", required: false }] }], disabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
821
1222
  class KbqTreeNodeToggleComponent extends KbqTreeNodeToggleBaseDirective {
822
- /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqTreeNodeToggleComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
823
- /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.30", type: KbqTreeNodeToggleComponent, isStandalone: true, selector: "kbq-tree-node-toggle", host: { listeners: { "click": "toggle($event)" }, properties: { "class.kbq-expanded": "iconState", "attr.disabled": "disabled || null" }, classAttribute: "kbq-tree-node-toggle" }, exportAs: ["kbqTreeNodeToggle"], usesInheritance: true, ngImport: i0, template: `
1223
+ /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqTreeNodeToggleComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
1224
+ /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.25", type: KbqTreeNodeToggleComponent, isStandalone: true, selector: "kbq-tree-node-toggle", host: { attributes: { "aria-hidden": "true" }, listeners: { "click": "toggle($event)" }, properties: { "class.kbq-expanded": "iconState", "attr.disabled": "disabled || null", "attr.aria-disabled": "disabled || null" }, classAttribute: "kbq-tree-node-toggle" }, exportAs: ["kbqTreeNodeToggle"], usesInheritance: true, ngImport: i0, template: `
824
1225
  <ng-content>
825
1226
  <i kbq-icon="kbq-chevron-down-s_16" [color]="'contrast-fade'"></i>
826
1227
  </ng-content>
827
- `, isInline: true, styles: [".kbq-tree-node-toggle{display:flex;align-items:center;justify-content:center;flex-shrink:0;height:100%;padding-left:var(--kbq-tree-size-toggle-padding);padding-right:var(--kbq-tree-size-toggle-padding);cursor:pointer}.kbq-tree-node-toggle .kbq-icon{transform:rotate(-90deg)}.kbq-tree-node-toggle.kbq-expanded .kbq-icon{transform:rotate(0)}.kbq-tree-node-toggle[disabled]{cursor:default}.kbq-tree-node-toggle[disabled] .kbq-icon{color:var(--kbq-tree-states-disabled-tree-toggle-color)}.kbq-tree-selection:focus{outline:none}.kbq-tree-option{--kbq-option-background: var(--kbq-tree-default-container-background);background:var(--kbq-tree-default-container-background)}.kbq-tree-option .kbq-option-text{color:var(--kbq-tree-default-text-color)}.kbq-tree-option .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-default-action-button-color)}.kbq-tree-option .kbq-option-caption{color:var(--kbq-tree-default-caption-color)}.kbq-tree-option:not(.kbq-disabled):hover,.kbq-tree-option:not(.kbq-disabled).kbq-hovered,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused{--kbq-option-background: var(--kbq-tree-states-hover-container-background);background:var(--kbq-tree-states-hover-container-background)}.kbq-tree-option:not(.kbq-disabled):hover .kbq-option-text,.kbq-tree-option:not(.kbq-disabled).kbq-hovered .kbq-option-text,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused .kbq-option-text{color:var(--kbq-tree-states-hover-text-color)}.kbq-tree-option:not(.kbq-disabled):hover .kbq-option-action .kbq-icon.kbq-empty,.kbq-tree-option:not(.kbq-disabled).kbq-hovered .kbq-option-action .kbq-icon.kbq-empty,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-hover-action-button-color)}.kbq-tree-option:not(.kbq-disabled):hover .kbq-option-caption,.kbq-tree-option:not(.kbq-disabled).kbq-hovered .kbq-option-caption,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused .kbq-option-caption{color:var(--kbq-tree-states-hover-caption-color)}.kbq-tree-option:not(.kbq-disabled):active,.kbq-tree-option:not(.kbq-disabled).kbq-active{--kbq-option-background: var(--kbq-tree-states-active-container-background);background:var(--kbq-tree-states-active-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-selected{--kbq-option-background: var(--kbq-tree-states-selected-container-background);background:var(--kbq-tree-states-selected-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-selected .kbq-option-text{color:var(--kbq-tree-states-selected-text-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-selected-action-button-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected .kbq-option-caption{color:var(--kbq-tree-states-selected-caption-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered{--kbq-option-background: var(--kbq-tree-states-selected-hover-container-background);background:var(--kbq-tree-states-selected-hover-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover .kbq-option-text,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered .kbq-option-text{color:var(--kbq-tree-states-selected-hover-text-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover .kbq-option-action .kbq-icon.kbq-empty,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-selected-hover-action-button-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover .kbq-option-caption,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered .kbq-option-caption{color:var(--kbq-tree-states-selected-hover-caption-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:active,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-active{--kbq-option-background: var(--kbq-tree-states-selected-active-container-background);background:var(--kbq-tree-states-selected-active-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected),.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected{--kbq-option-background: var(--kbq-tree-multiple-states-selected-container-background);background:var(--kbq-tree-multiple-states-selected-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected):hover,.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected).kbq-hovered,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected:hover,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected.kbq-hovered{--kbq-option-background: var(--kbq-tree-multiple-states-selected-hover-container-background);background:var(--kbq-tree-multiple-states-selected-hover-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected):active,.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected).kbq-active,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected:active,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected.kbq-active{--kbq-option-background: var(--kbq-tree-multiple-states-selected-active-container-background);background:var(--kbq-tree-multiple-states-selected-active-container-background)}.kbq-tree-option.kbq-disabled{--kbq-option-background: var(--kbq-tree-states-disabled-container-background);background:var(--kbq-tree-states-disabled-container-background)}.kbq-tree-option.kbq-disabled .kbq-option-text{color:var(--kbq-tree-states-disabled-text-color)}.kbq-tree-option.kbq-disabled .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-disabled-action-button-color)}.kbq-tree-option.kbq-disabled .kbq-option-caption{color:var(--kbq-tree-states-disabled-caption-color)}.kbq-tree-option.kbq-disabled .kbq-icon.kbq-empty:not(.kbq-tree-node-toggle .kbq-icon){color:var(--kbq-states-icon-disabled)}.kbq-tree-selection.cdk-keyboard-focused .kbq-tree-option.kbq-focused:not(.kbq-action-button-focused){border-color:var(--kbq-tree-states-focused-focus-outline-color)}.kbq-tree-option{font-size:var(--kbq-typography-text-normal-font-size);font-style:var(--kbq-typography-text-normal-font-style);font-weight:var(--kbq-typography-text-normal-font-weight);line-height:var(--kbq-typography-text-normal-line-height);font-family:var(--kbq-typography-text-normal-font-family);text-transform:var(--kbq-typography-text-normal-text-transform);font-feature-settings:var(--kbq-typography-text-normal-font-feature-settings);letter-spacing:var(--kbq-typography-text-normal-letter-spacing)}.kbq-option-caption{font-size:var(--kbq-typography-text-compact-font-size);font-style:var(--kbq-typography-text-compact-font-style);font-weight:var(--kbq-typography-text-compact-font-weight);line-height:var(--kbq-typography-text-compact-line-height);font-family:var(--kbq-typography-text-compact-font-family);text-transform:var(--kbq-typography-text-compact-text-transform);font-feature-settings:var(--kbq-typography-text-compact-font-feature-settings);letter-spacing:var(--kbq-typography-text-compact-letter-spacing)}\n", ".kbq-tree,.kbq-tree-selection{--kbq-tree-size-indent-level: var(--kbq-size-xxl);--kbq-tree-size-container-padding-right: var(--kbq-size-s);--kbq-tree-size-container-padding-vertical: var(--kbq-size-xxs);--kbq-tree-size-container-content-gap-horizontal: var(--kbq-size-s);--kbq-tree-size-container-content-gap-vertical: 0px;--kbq-tree-size-container-focus-outline-width: var(--kbq-size-3xs);--kbq-tree-size-text-padding-vertical: var(--kbq-size-3xs);--kbq-tree-option-border-radius: var(--kbq-size-border-radius);--kbq-tree-default-container-background: transparent;--kbq-tree-default-text-color: var(--kbq-foreground-contrast);--kbq-tree-default-icon-color: var(--kbq-icon-contrast);--kbq-tree-default-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-hover-container-background: var(--kbq-states-background-transparent-hover);--kbq-tree-states-active-container-background: var(--kbq-states-background-transparent-active);--kbq-tree-states-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-focused-focus-outline-color: var(--kbq-states-line-focus-theme);--kbq-tree-states-selected-container-background: var(--kbq-background-theme-less);--kbq-tree-multiple-states-selected-container-background: var(--kbq-background-contrast-less);--kbq-tree-states-selected-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-selected-hover-container-background: var(--kbq-states-background-theme-less-hover);--kbq-tree-states-selected-active-container-background: var(--kbq-states-background-theme-less-active);--kbq-tree-multiple-states-selected-hover-container-background: var(--kbq-states-background-contrast-less-hover);--kbq-tree-multiple-states-selected-active-container-background: var(--kbq-states-background-contrast-less-active);--kbq-tree-states-selected-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-disabled-container-background: transparent;--kbq-tree-states-disabled-text-color: var(--kbq-states-foreground-disabled);--kbq-tree-states-disabled-icon-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-tree-toggle-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-action-button-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-caption-color: var(--kbq-states-foreground-disabled)}\n"], dependencies: [{ kind: "component", type: KbqIcon, selector: "[kbq-icon]", inputs: ["small", "autoColor", "kbq-icon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
1228
+ `, isInline: true, styles: [".kbq-tree-node-toggle{display:flex;align-items:center;justify-content:center;flex-shrink:0;height:100%;cursor:pointer}.kbq-tree-node-toggle .kbq-icon{transform:rotate(-90deg)}.kbq-tree-node-toggle.kbq-expanded .kbq-icon{transform:rotate(0)}.kbq-tree-node-toggle[disabled]{cursor:default}.kbq-tree-node-toggle[disabled] .kbq-icon{color:var(--kbq-tree-states-disabled-tree-toggle-color)}\n", ".kbq-tree,.kbq-tree-selection{--kbq-tree-size-indent-level: var(--kbq-size-xxl);--kbq-tree-size-container-padding-right: var(--kbq-size-s);--kbq-tree-size-container-padding-vertical: var(--kbq-size-xxs);--kbq-tree-size-container-content-gap-horizontal: var(--kbq-size-s);--kbq-tree-size-container-focus-outline-width: var(--kbq-size-3xs);--kbq-tree-size-text-padding-vertical: var(--kbq-size-3xs);--kbq-tree-option-border-radius: var(--kbq-size-border-radius);--kbq-tree-default-container-background: transparent;--kbq-tree-default-text-color: var(--kbq-foreground-contrast);--kbq-tree-default-icon-color: var(--kbq-icon-contrast);--kbq-tree-default-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-hover-container-background: var(--kbq-states-background-transparent-hover);--kbq-tree-states-active-container-background: var(--kbq-states-background-transparent-active);--kbq-tree-states-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-focused-focus-outline-color: var(--kbq-states-line-focus-theme);--kbq-tree-states-selected-container-background: var(--kbq-background-theme-less);--kbq-tree-multiple-states-selected-container-background: var(--kbq-background-contrast-less);--kbq-tree-states-selected-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-selected-hover-container-background: var(--kbq-states-background-theme-less-hover);--kbq-tree-states-selected-active-container-background: var(--kbq-states-background-theme-less-active);--kbq-tree-multiple-states-selected-hover-container-background: var(--kbq-states-background-contrast-less-hover);--kbq-tree-multiple-states-selected-active-container-background: var(--kbq-states-background-contrast-less-active);--kbq-tree-states-selected-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-disabled-container-background: transparent;--kbq-tree-states-disabled-text-color: var(--kbq-states-foreground-disabled);--kbq-tree-states-disabled-icon-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-tree-toggle-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-action-button-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-caption-color: var(--kbq-states-foreground-disabled)}\n"], dependencies: [{ kind: "component", type: KbqIcon, selector: "[kbq-icon]", inputs: ["aria-hidden", "iconSize", "autoColor", "kbq-icon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
828
1229
  }
829
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqTreeNodeToggleComponent, decorators: [{
1230
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqTreeNodeToggleComponent, decorators: [{
830
1231
  type: Component,
831
1232
  args: [{ selector: 'kbq-tree-node-toggle', imports: [KbqIcon], template: `
832
1233
  <ng-content>
@@ -834,16 +1235,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImpo
834
1235
  </ng-content>
835
1236
  `, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
836
1237
  class: 'kbq-tree-node-toggle',
1238
+ // The expanded state is announced on the owning `treeitem` through `aria-expanded`, and the
1239
+ // Left/Right arrow keys drive it, so exposing the chevron as a second control would only add
1240
+ // a duplicate stop for assistive tech.
1241
+ 'aria-hidden': 'true',
837
1242
  '[class.kbq-expanded]': 'iconState',
838
1243
  '[attr.disabled]': 'disabled || null',
1244
+ '[attr.aria-disabled]': 'disabled || null',
839
1245
  '(click)': 'toggle($event)'
840
- }, exportAs: 'kbqTreeNodeToggle', styles: [".kbq-tree-node-toggle{display:flex;align-items:center;justify-content:center;flex-shrink:0;height:100%;padding-left:var(--kbq-tree-size-toggle-padding);padding-right:var(--kbq-tree-size-toggle-padding);cursor:pointer}.kbq-tree-node-toggle .kbq-icon{transform:rotate(-90deg)}.kbq-tree-node-toggle.kbq-expanded .kbq-icon{transform:rotate(0)}.kbq-tree-node-toggle[disabled]{cursor:default}.kbq-tree-node-toggle[disabled] .kbq-icon{color:var(--kbq-tree-states-disabled-tree-toggle-color)}.kbq-tree-selection:focus{outline:none}.kbq-tree-option{--kbq-option-background: var(--kbq-tree-default-container-background);background:var(--kbq-tree-default-container-background)}.kbq-tree-option .kbq-option-text{color:var(--kbq-tree-default-text-color)}.kbq-tree-option .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-default-action-button-color)}.kbq-tree-option .kbq-option-caption{color:var(--kbq-tree-default-caption-color)}.kbq-tree-option:not(.kbq-disabled):hover,.kbq-tree-option:not(.kbq-disabled).kbq-hovered,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused{--kbq-option-background: var(--kbq-tree-states-hover-container-background);background:var(--kbq-tree-states-hover-container-background)}.kbq-tree-option:not(.kbq-disabled):hover .kbq-option-text,.kbq-tree-option:not(.kbq-disabled).kbq-hovered .kbq-option-text,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused .kbq-option-text{color:var(--kbq-tree-states-hover-text-color)}.kbq-tree-option:not(.kbq-disabled):hover .kbq-option-action .kbq-icon.kbq-empty,.kbq-tree-option:not(.kbq-disabled).kbq-hovered .kbq-option-action .kbq-icon.kbq-empty,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-hover-action-button-color)}.kbq-tree-option:not(.kbq-disabled):hover .kbq-option-caption,.kbq-tree-option:not(.kbq-disabled).kbq-hovered .kbq-option-caption,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused .kbq-option-caption{color:var(--kbq-tree-states-hover-caption-color)}.kbq-tree-option:not(.kbq-disabled):active,.kbq-tree-option:not(.kbq-disabled).kbq-active{--kbq-option-background: var(--kbq-tree-states-active-container-background);background:var(--kbq-tree-states-active-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-selected{--kbq-option-background: var(--kbq-tree-states-selected-container-background);background:var(--kbq-tree-states-selected-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-selected .kbq-option-text{color:var(--kbq-tree-states-selected-text-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-selected-action-button-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected .kbq-option-caption{color:var(--kbq-tree-states-selected-caption-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered{--kbq-option-background: var(--kbq-tree-states-selected-hover-container-background);background:var(--kbq-tree-states-selected-hover-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover .kbq-option-text,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered .kbq-option-text{color:var(--kbq-tree-states-selected-hover-text-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover .kbq-option-action .kbq-icon.kbq-empty,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-selected-hover-action-button-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover .kbq-option-caption,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered .kbq-option-caption{color:var(--kbq-tree-states-selected-hover-caption-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:active,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-active{--kbq-option-background: var(--kbq-tree-states-selected-active-container-background);background:var(--kbq-tree-states-selected-active-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected),.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected{--kbq-option-background: var(--kbq-tree-multiple-states-selected-container-background);background:var(--kbq-tree-multiple-states-selected-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected):hover,.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected).kbq-hovered,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected:hover,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected.kbq-hovered{--kbq-option-background: var(--kbq-tree-multiple-states-selected-hover-container-background);background:var(--kbq-tree-multiple-states-selected-hover-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected):active,.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected).kbq-active,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected:active,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected.kbq-active{--kbq-option-background: var(--kbq-tree-multiple-states-selected-active-container-background);background:var(--kbq-tree-multiple-states-selected-active-container-background)}.kbq-tree-option.kbq-disabled{--kbq-option-background: var(--kbq-tree-states-disabled-container-background);background:var(--kbq-tree-states-disabled-container-background)}.kbq-tree-option.kbq-disabled .kbq-option-text{color:var(--kbq-tree-states-disabled-text-color)}.kbq-tree-option.kbq-disabled .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-disabled-action-button-color)}.kbq-tree-option.kbq-disabled .kbq-option-caption{color:var(--kbq-tree-states-disabled-caption-color)}.kbq-tree-option.kbq-disabled .kbq-icon.kbq-empty:not(.kbq-tree-node-toggle .kbq-icon){color:var(--kbq-states-icon-disabled)}.kbq-tree-selection.cdk-keyboard-focused .kbq-tree-option.kbq-focused:not(.kbq-action-button-focused){border-color:var(--kbq-tree-states-focused-focus-outline-color)}.kbq-tree-option{font-size:var(--kbq-typography-text-normal-font-size);font-style:var(--kbq-typography-text-normal-font-style);font-weight:var(--kbq-typography-text-normal-font-weight);line-height:var(--kbq-typography-text-normal-line-height);font-family:var(--kbq-typography-text-normal-font-family);text-transform:var(--kbq-typography-text-normal-text-transform);font-feature-settings:var(--kbq-typography-text-normal-font-feature-settings);letter-spacing:var(--kbq-typography-text-normal-letter-spacing)}.kbq-option-caption{font-size:var(--kbq-typography-text-compact-font-size);font-style:var(--kbq-typography-text-compact-font-style);font-weight:var(--kbq-typography-text-compact-font-weight);line-height:var(--kbq-typography-text-compact-line-height);font-family:var(--kbq-typography-text-compact-font-family);text-transform:var(--kbq-typography-text-compact-text-transform);font-feature-settings:var(--kbq-typography-text-compact-font-feature-settings);letter-spacing:var(--kbq-typography-text-compact-letter-spacing)}\n", ".kbq-tree,.kbq-tree-selection{--kbq-tree-size-indent-level: var(--kbq-size-xxl);--kbq-tree-size-container-padding-right: var(--kbq-size-s);--kbq-tree-size-container-padding-vertical: var(--kbq-size-xxs);--kbq-tree-size-container-content-gap-horizontal: var(--kbq-size-s);--kbq-tree-size-container-content-gap-vertical: 0px;--kbq-tree-size-container-focus-outline-width: var(--kbq-size-3xs);--kbq-tree-size-text-padding-vertical: var(--kbq-size-3xs);--kbq-tree-option-border-radius: var(--kbq-size-border-radius);--kbq-tree-default-container-background: transparent;--kbq-tree-default-text-color: var(--kbq-foreground-contrast);--kbq-tree-default-icon-color: var(--kbq-icon-contrast);--kbq-tree-default-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-hover-container-background: var(--kbq-states-background-transparent-hover);--kbq-tree-states-active-container-background: var(--kbq-states-background-transparent-active);--kbq-tree-states-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-focused-focus-outline-color: var(--kbq-states-line-focus-theme);--kbq-tree-states-selected-container-background: var(--kbq-background-theme-less);--kbq-tree-multiple-states-selected-container-background: var(--kbq-background-contrast-less);--kbq-tree-states-selected-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-selected-hover-container-background: var(--kbq-states-background-theme-less-hover);--kbq-tree-states-selected-active-container-background: var(--kbq-states-background-theme-less-active);--kbq-tree-multiple-states-selected-hover-container-background: var(--kbq-states-background-contrast-less-hover);--kbq-tree-multiple-states-selected-active-container-background: var(--kbq-states-background-contrast-less-active);--kbq-tree-states-selected-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-disabled-container-background: transparent;--kbq-tree-states-disabled-text-color: var(--kbq-states-foreground-disabled);--kbq-tree-states-disabled-icon-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-tree-toggle-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-action-button-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-caption-color: var(--kbq-states-foreground-disabled)}\n"] }]
1246
+ }, exportAs: 'kbqTreeNodeToggle', styles: [".kbq-tree-node-toggle{display:flex;align-items:center;justify-content:center;flex-shrink:0;height:100%;cursor:pointer}.kbq-tree-node-toggle .kbq-icon{transform:rotate(-90deg)}.kbq-tree-node-toggle.kbq-expanded .kbq-icon{transform:rotate(0)}.kbq-tree-node-toggle[disabled]{cursor:default}.kbq-tree-node-toggle[disabled] .kbq-icon{color:var(--kbq-tree-states-disabled-tree-toggle-color)}\n", ".kbq-tree,.kbq-tree-selection{--kbq-tree-size-indent-level: var(--kbq-size-xxl);--kbq-tree-size-container-padding-right: var(--kbq-size-s);--kbq-tree-size-container-padding-vertical: var(--kbq-size-xxs);--kbq-tree-size-container-content-gap-horizontal: var(--kbq-size-s);--kbq-tree-size-container-focus-outline-width: var(--kbq-size-3xs);--kbq-tree-size-text-padding-vertical: var(--kbq-size-3xs);--kbq-tree-option-border-radius: var(--kbq-size-border-radius);--kbq-tree-default-container-background: transparent;--kbq-tree-default-text-color: var(--kbq-foreground-contrast);--kbq-tree-default-icon-color: var(--kbq-icon-contrast);--kbq-tree-default-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-hover-container-background: var(--kbq-states-background-transparent-hover);--kbq-tree-states-active-container-background: var(--kbq-states-background-transparent-active);--kbq-tree-states-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-focused-focus-outline-color: var(--kbq-states-line-focus-theme);--kbq-tree-states-selected-container-background: var(--kbq-background-theme-less);--kbq-tree-multiple-states-selected-container-background: var(--kbq-background-contrast-less);--kbq-tree-states-selected-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-selected-hover-container-background: var(--kbq-states-background-theme-less-hover);--kbq-tree-states-selected-active-container-background: var(--kbq-states-background-theme-less-active);--kbq-tree-multiple-states-selected-hover-container-background: var(--kbq-states-background-contrast-less-hover);--kbq-tree-multiple-states-selected-active-container-background: var(--kbq-states-background-contrast-less-active);--kbq-tree-states-selected-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-disabled-container-background: transparent;--kbq-tree-states-disabled-text-color: var(--kbq-states-foreground-disabled);--kbq-tree-states-disabled-icon-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-tree-toggle-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-action-button-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-caption-color: var(--kbq-states-foreground-disabled)}\n"] }]
841
1247
  }] });
1248
+ // No ARIA on this host: the directive is routinely applied to the `kbq-tree-option` element itself,
1249
+ // where the option already owns `role`, `aria-disabled` and the rest of the treeitem semantics.
842
1250
  class KbqTreeNodeToggleDirective extends KbqTreeNodeToggleBaseDirective {
843
- /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqTreeNodeToggleDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
844
- /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.30", type: KbqTreeNodeToggleDirective, isStandalone: true, selector: "[kbq-tree-node-toggle], [kbqTreeNodeToggle]", host: { listeners: { "click": "toggle($event)" }, properties: { "attr.disabled": "disabled || null" } }, exportAs: ["kbqTreeNodeToggle"], usesInheritance: true, ngImport: i0 }); }
1251
+ /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqTreeNodeToggleDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
1252
+ /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.25", type: KbqTreeNodeToggleDirective, isStandalone: true, selector: "[kbq-tree-node-toggle], [kbqTreeNodeToggle]", host: { listeners: { "click": "toggle($event)" }, properties: { "attr.disabled": "disabled || null" } }, exportAs: ["kbqTreeNodeToggle"], usesInheritance: true, ngImport: i0 }); }
845
1253
  }
846
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqTreeNodeToggleDirective, decorators: [{
1254
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqTreeNodeToggleDirective, decorators: [{
847
1255
  type: Directive,
848
1256
  args: [{
849
1257
  selector: '[kbq-tree-node-toggle], [kbqTreeNodeToggle]',
@@ -857,24 +1265,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImpo
857
1265
 
858
1266
  /** Injection token used to provide the parent component to options. */
859
1267
  const KBQ_TREE_OPTION_PARENT_COMPONENT = new InjectionToken('KBQ_TREE_OPTION_PARENT_COMPONENT');
860
- /**
861
- * Represents a change event for a tree option.
862
- *
863
- * @param source - The tree option that has been modified or selected.
864
- * @param isUserInput - DEPRECATED Will be removed in version 20.
865
- */
1268
+ /** Represents a change event for a tree option. */
866
1269
  class KbqTreeOptionChange {
867
- constructor(source, isUserInput = false) {
1270
+ constructor(
1271
+ /** The tree option that has been modified or selected. */
1272
+ source) {
868
1273
  this.source = source;
869
- this.isUserInput = isUserInput;
870
1274
  }
871
1275
  }
872
1276
  let uniqueIdCounter = 0;
1277
+ const samePredicates = (a, b) => a.disabled === b.disabled && a.expanded === b.expanded;
873
1278
  class KbqTreeOption extends KbqTreeNode {
1279
+ /** Container of the option text, measured by `kbq-title`. */
1280
+ get parentTextElement() {
1281
+ return this.titleContainer();
1282
+ }
874
1283
  // Same element as `parentTextElement` — `.kbq-option-text` clips the text, so it is measured against itself.
875
1284
  get textElement() {
876
1285
  return this.parentTextElement;
877
1286
  }
1287
+ // Getters rather than the signal queries themselves: `KbqOptionActionComponent` reads the triggers as
1288
+ // directive instances through KBQ_OPTION_ACTION_PARENT — see #DS-5079.
1289
+ /** Tooltip trigger projected into the option. */
1290
+ get tooltipTrigger() {
1291
+ return this.tooltipTriggerQuery();
1292
+ }
1293
+ /** Dropdown trigger projected into the option. */
1294
+ get dropdownTrigger() {
1295
+ return this.dropdownTriggerQuery();
1296
+ }
878
1297
  get externalPseudoCheckbox() {
879
1298
  return !!this.pseudoCheckbox();
880
1299
  }
@@ -884,34 +1303,23 @@ class KbqTreeOption extends KbqTreeNode {
884
1303
  set value(value) {
885
1304
  this._value = value;
886
1305
  }
887
- // TODO: Skipped for migration because:
888
- // Accessor inputs cannot be migrated as they are too complex.
1306
+ /** Whether the option is disabled: through its own input, the tree, or the tree control's `isDisabled`. */
889
1307
  get disabled() {
890
1308
  if (this.selectAllRow()) {
891
- return this._disabled || this.tree.disabled;
1309
+ return this.disabledInput() || this.tree.disabled;
892
1310
  }
893
- return this._disabled || this.tree.disabled || this.tree.treeControl.isDisabled(this.data);
1311
+ return this.disabledInput() || this.tree.disabled || this.tree.treeControl.isDisabled(this.data);
894
1312
  }
895
- set disabled(value) {
896
- const newValue = coerceBooleanProperty(value);
897
- if (newValue !== this._disabled) {
898
- this._disabled = newValue;
899
- }
900
- }
901
- // TODO: Skipped for migration because:
902
- // Accessor inputs cannot be migrated as they are too complex.
1313
+ /** Whether the option renders a pseudo-checkbox. Falls back to the tree's own mode until bound. */
903
1314
  get showCheckbox() {
904
- return this._showCheckbox !== undefined ? this._showCheckbox : this.tree.showCheckbox;
905
- }
906
- set showCheckbox(value) {
907
- this._showCheckbox = coerceBooleanProperty(value);
1315
+ return this.showCheckboxInput() ?? this.tree.showCheckbox;
908
1316
  }
909
1317
  get selected() {
910
- return this._selected;
1318
+ return this.selectedState();
911
1319
  }
912
1320
  set selected(value) {
913
1321
  const isSelected = coerceBooleanProperty(value);
914
- if (isSelected !== this._selected) {
1322
+ if (isSelected !== this.selectedState()) {
915
1323
  this.setSelected(isSelected);
916
1324
  }
917
1325
  }
@@ -922,6 +1330,12 @@ class KbqTreeOption extends KbqTreeNode {
922
1330
  // TODO: Add input property alternative for node envs.
923
1331
  return (this.getHostElement().textContent || '').trim();
924
1332
  }
1333
+ get hasFocus() {
1334
+ return this.focused();
1335
+ }
1336
+ set hasFocus(value) {
1337
+ this.focused.set(value);
1338
+ }
925
1339
  get isExpandable() {
926
1340
  if (this.selectAllRow()) {
927
1341
  return false;
@@ -938,28 +1352,86 @@ class KbqTreeOption extends KbqTreeNode {
938
1352
  get isToggleInDefaultPlace() {
939
1353
  return !!(this.toggleElementDirective() || this.toggleElementComponent());
940
1354
  }
1355
+ get checkboxState() {
1356
+ return this.checkbox();
1357
+ }
1358
+ set checkboxState(value) {
1359
+ this.checkbox.set(value);
1360
+ }
1361
+ /**
1362
+ * `aria-expanded` of the row as of the last check, reported for every branch and omitted on a leaf.
1363
+ *
1364
+ * Deliberately not `isExpandable`, which also asks whether the toggle is operable: filtering
1365
+ * disables every toggle while leaving the matched branches expanded, and a branch that stops
1366
+ * reporting `aria-expanded` is announced as a leaf while its children are on screen.
1367
+ */
1368
+ get ariaExpanded() {
1369
+ // The one tracked read of `predicates`, which subscribes the row to the signals the predicates read: the
1370
+ // other bindings read the snapshot `ngDoCheck` takes along with it, as a second read of this row's own signal
1371
+ // would walk the producers of every row checked before it.
1372
+ return this.predicates().expanded;
1373
+ }
1374
+ /**
1375
+ * `aria-checked` of the row: tri-state for a checkbox option, and the "select all" state for the
1376
+ * row that drives it. `null` for a plain option, which reports `aria-selected` instead.
1377
+ */
1378
+ get ariaChecked() {
1379
+ // The checkbox state is read here rather than in `ngDoCheck`: this read is what brings the row back once the
1380
+ // state changes.
1381
+ return this.checkedCheckboxRow ? this.toAriaChecked(this.checkboxState) : this.checkedSelectAllState;
1382
+ }
1383
+ /** `aria-selected` of the row as of the last check. Options with a checkbox report `aria-checked` instead. */
1384
+ get ariaSelected() {
1385
+ return this.checkedAriaSelected;
1386
+ }
941
1387
  constructor() {
942
1388
  const tree = inject(KBQ_TREE_OPTION_PARENT_COMPONENT);
943
1389
  super();
944
1390
  this.changeDetectorRef = inject(ChangeDetectorRef);
945
- this.ngZone = inject(NgZone);
1391
+ this.environmentInjector = inject(EnvironmentInjector);
946
1392
  this.destroyRef = inject(DestroyRef);
947
- this.onFocus = new Subject();
948
- this.onBlur = new Subject();
1393
+ this.ngZone = inject(NgZone);
1394
+ this.renderer = inject(Renderer2);
1395
+ this.focusEvents = new Subject();
1396
+ this.blurEvents = new Subject();
1397
+ /** Emits when the option takes focus. */
1398
+ this.onFocus = this.focusEvents.asObservable();
1399
+ /** Emits when the option loses focus. */
1400
+ this.onBlur = this.blurEvents.asObservable();
949
1401
  this.preventBlur = false;
950
- this.toggleElementDirective = contentChild(KbqTreeNodeToggleDirective, ...(ngDevMode ? [{ debugName: "toggleElementDirective" }] : []));
951
- this.toggleElementComponent = contentChild(KbqTreeNodeToggleComponent, ...(ngDevMode ? [{ debugName: "toggleElementComponent" }] : []));
952
- this.pseudoCheckbox = contentChild(KbqPseudoCheckbox, ...(ngDevMode ? [{ debugName: "pseudoCheckbox" }] : []));
953
- this.actionButton = contentChild(KbqOptionActionComponent, ...(ngDevMode ? [{ debugName: "actionButton" }] : []));
954
- this.checkboxThirdState = input(false, ...(ngDevMode ? [{ debugName: "checkboxThirdState" }] : []));
955
- this._disabled = false;
1402
+ this.titleContainer = viewChild('kbqTitleContainer', ...(ngDevMode ? [{ debugName: "titleContainer" }] : /* istanbul ignore next */ []));
1403
+ this.toggleElementDirective = contentChild(KbqTreeNodeToggleDirective, ...(ngDevMode ? [{ debugName: "toggleElementDirective" }] : /* istanbul ignore next */ []));
1404
+ this.toggleElementComponent = contentChild(KbqTreeNodeToggleComponent, ...(ngDevMode ? [{ debugName: "toggleElementComponent" }] : /* istanbul ignore next */ []));
1405
+ this.pseudoCheckbox = contentChild(KbqPseudoCheckbox, ...(ngDevMode ? [{ debugName: "pseudoCheckbox" }] : /* istanbul ignore next */ []));
1406
+ this.actionButton = contentChild(KbqOptionActionComponent, ...(ngDevMode ? [{ debugName: "actionButton" }] : /* istanbul ignore next */ []));
1407
+ this.tooltipTriggerQuery = contentChild(KbqTooltipTrigger, ...(ngDevMode ? [{ debugName: "tooltipTriggerQuery" }] : /* istanbul ignore next */ []));
1408
+ this.dropdownTriggerQuery = contentChild(KbqDropdownTrigger, ...(ngDevMode ? [{ debugName: "dropdownTriggerQuery" }] : /* istanbul ignore next */ []));
1409
+ this.checkboxThirdState = input(false, ...(ngDevMode ? [{ debugName: "checkboxThirdState" }] : /* istanbul ignore next */ []));
1410
+ /** @docs-private */
1411
+ this.disabledInput = input(false, { ...(ngDevMode ? { debugName: "disabledInput" } : /* istanbul ignore next */ {}), alias: 'disabled',
1412
+ transform: booleanAttribute });
1413
+ /**
1414
+ * `disabled` as of the last check, which the host bindings read: the tree control's `isDisabled` predicate gives
1415
+ * no notice of a change and may be costly, so a check asks it once.
1416
+ */
1417
+ this.checkedDisabled = false;
1418
+ /**
1419
+ * What the tree control's `isDisabled` and `isExpandable` say about the row. Derived, so a predicate reading a
1420
+ * signal brings the row back once that signal changes; `ngDoCheck` sets it on every check for one reading plain
1421
+ * state. Read by a single host binding, see `ariaExpanded`.
1422
+ */
1423
+ this.predicates = linkedSignal(() => this.resolvePredicates(), { ...(ngDevMode ? { debugName: "predicates" } : /* istanbul ignore next */ {}), equal: samePredicates });
1424
+ // Values of the ARIA host bindings as of the last check, resolved by `ngDoCheck`.
1425
+ this.checkedAriaSelected = null;
1426
+ this.checkedSelectAllState = null;
1427
+ this.checkedCheckboxRow = false;
956
1428
  /**
957
1429
  * Whether the option can be selected by user interaction (click, keyboard, select all).
958
1430
  * A non-selectable option remains focusable, navigable and expandable.
959
1431
  * Programmatic selection (`setSelected`, `select`, value accessor) is not affected.
960
1432
  * Options that are not rendered (e.g. collapsed) are not checked by "select all".
961
1433
  */
962
- this.selectable = input(true, ...(ngDevMode ? [{ debugName: "selectable", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
1434
+ this.selectable = input(true, { ...(ngDevMode ? { debugName: "selectable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
963
1435
  /**
964
1436
  * Whether this option is the tree's "select all" row rather than a rendered data node.
965
1437
  *
@@ -967,40 +1439,90 @@ class KbqTreeOption extends KbqTreeNode {
967
1439
  * (`getValue`, `isDisabled`, `isExpandable`, descendants) is skipped — those accessors belong to the
968
1440
  * consumer and must never be handed a node their data source has never seen. Its checkbox state and
969
1441
  * selection are driven from the outside instead.
1442
+ *
970
1443
  * @docs-private
971
1444
  */
972
- this.selectAllRow = input(false, ...(ngDevMode ? [{ debugName: "selectAllRow", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
973
- this.onSelectionChange = output();
1445
+ this.selectAllRow = input(false, { ...(ngDevMode ? { debugName: "selectAllRow" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1446
+ /** @docs-private */
1447
+ this.showCheckboxInput = input(undefined, { ...(ngDevMode ? { debugName: "showCheckboxInput" } : /* istanbul ignore next */ {}), alias: 'showCheckbox',
1448
+ transform: booleanAttribute });
1449
+ /** Emits whenever the selected state of the option changes. */
1450
+ this.selectionChange = output();
1451
+ /** @deprecated Use `selectionChange` instead. Will be removed in 22.0.0. */
1452
+ this.onSelectionChange = output({ alias: 'onSelectionChange' });
1453
+ // Not an `output()`: `KbqTreeSelect` merges this stream with rxjs, which an `OutputEmitterRef`
1454
+ // cannot feed without wrapping every call site in `outputToObservable`.
974
1455
  this.userInteraction = new EventEmitter();
975
- this._selected = false;
1456
+ this.selectedState = signal(false, ...(ngDevMode ? [{ debugName: "selectedState" }] : /* istanbul ignore next */ []));
976
1457
  this._id = `kbq-tree-option-${uniqueIdCounter++}`;
977
- this.hasFocus = false;
1458
+ this.focused = signal(false, ...(ngDevMode ? [{ debugName: "focused" }] : /* istanbul ignore next */ []));
1459
+ // Raised from reporting a focus until `hasFocus` is: `kbqFocusAndReveal` fires `focusin` synchronously, and its
1460
+ // listener calls back into `focus()` while `hasFocus` is still false.
1461
+ this.focusReported = false;
1462
+ this.checkbox = signal('unchecked', ...(ngDevMode ? [{ debugName: "checkbox" }] : /* istanbul ignore next */ []));
978
1463
  this.updateCheckboxState = () => {
979
1464
  if (this.selectAllRow())
980
1465
  return;
981
- if (this.checkboxThirdState() && this.isExpandable) {
982
- if (this.descendantsAllSelected()) {
983
- this.checkboxState = 'checked';
984
- }
985
- else if (this.descendantsPartiallySelected()) {
986
- this.checkboxState = 'indeterminate';
987
- }
988
- else {
989
- this.checkboxState = this.selected ? 'checked' : 'unchecked';
990
- }
991
- }
992
- else {
993
- this.checkboxState = this.selected ? 'checked' : 'unchecked';
994
- }
1466
+ this.syncCheckboxState();
995
1467
  this.updateParentsCheckboxState(this.data);
996
1468
  };
997
1469
  this.tree = tree;
1470
+ // Not a host listener: one would check the views on every row the pointer crosses, and only a tree in a select
1471
+ // reacts to it.
1472
+ const unlisten = this.ngZone.runOutsideAngular(() => this.renderer.listen(this.elementRef.nativeElement, 'mouseenter', () => this.onMouseenter()));
1473
+ this.destroyRef.onDestroy(unlisten);
1474
+ }
1475
+ ngOnInit() {
1476
+ // Selected from its first check: the tree's sweep reaches a new row a macrotask later, and a row it marked
1477
+ // would render unselected first and then report a selection nobody made.
1478
+ if (!this.selectAllRow())
1479
+ this.selectedState.set(!!this.tree.selectionModel?.isSelected(this.data));
1480
+ }
1481
+ ngDoCheck() {
1482
+ // Asked once per check, for a predicate reading plain state; a set to an equal value does nothing.
1483
+ const predicates = this.resolvePredicates();
1484
+ this.predicates.set(predicates);
1485
+ if (predicates.disabled !== this.checkedDisabled) {
1486
+ this.checkedDisabled = predicates.disabled;
1487
+ this.changeDetectorRef.markForCheck();
1488
+ }
1489
+ // Resolved here, untracked: a tree checks its rows under the one reactive consumer of its view, where a signal
1490
+ // read again costs a walk over every signal read before it. The host bindings read each signal of the row once
1491
+ // (`selected`, `checkboxState`, `predicates`, the mode through `tree.multiple`), which brings the row back here
1492
+ // on a change.
1493
+ if (this.selectAllRow()) {
1494
+ this.checkedAriaSelected = null;
1495
+ this.checkedCheckboxRow = false;
1496
+ this.checkedSelectAllState = this.toAriaChecked(this.tree.selectAllState);
1497
+ }
1498
+ else {
1499
+ const showCheckbox = this.showCheckbox;
1500
+ this.checkedAriaSelected = showCheckbox ? null : this.selected;
1501
+ this.checkedCheckboxRow = showCheckbox;
1502
+ this.checkedSelectAllState = null;
1503
+ }
998
1504
  }
999
1505
  ngAfterContentInit() {
1000
1506
  if (this.selectAllRow())
1001
1507
  return;
1002
- Promise.resolve().then(this.updateCheckboxState);
1508
+ // Its own state only: rendering a row changes no ancestor's, and the tree recomputes every row once the data
1509
+ // nodes change.
1510
+ Promise.resolve().then(() => this.syncCheckboxState());
1511
+ this.value = this.tree.treeControl.getValue(this.data);
1512
+ }
1513
+ /**
1514
+ * The value and the checkbox state were derived from the node this view held before it was reused,
1515
+ * and `ngAfterContentInit` does not run again. A stale `value` drops the row out of the tree's
1516
+ * `renderedOptions`, so it renders but can no longer be focused, selected or copied.
1517
+ *
1518
+ * @docs-private
1519
+ */
1520
+ refresh() {
1521
+ super.refresh();
1522
+ if (this.selectAllRow())
1523
+ return;
1003
1524
  this.value = this.tree.treeControl.getValue(this.data);
1525
+ this.markForCheck();
1004
1526
  }
1005
1527
  descendantsAllSelected() {
1006
1528
  const descendants = this.tree.treeControl.getDescendants(this.data);
@@ -1011,132 +1533,202 @@ class KbqTreeOption extends KbqTreeNode {
1011
1533
  return descendants.some((child) => this.tree?.selectionModel.isSelected(child));
1012
1534
  }
1013
1535
  updateParentsCheckboxState(node) {
1014
- this.tree.treeControl.getParents(node, []).forEach((parent) => {
1015
- const parentOption = this.tree.unorderedOptions.find((option) => option.data === parent);
1016
- parentOption?.updateCheckboxState();
1536
+ const parents = new Set(this.tree.treeControl.getParents(node, []));
1537
+ if (!parents.size)
1538
+ return;
1539
+ // Each ancestor reads its state off the selection rather than off its children, so recomputing it is enough.
1540
+ this.tree.unorderedOptions.forEach((option) => {
1541
+ if (parents.has(option.data))
1542
+ option.syncCheckboxState();
1017
1543
  });
1018
1544
  }
1019
1545
  toggle() {
1020
- this.selected = !this.selected;
1546
+ // Untracked, like the other imperative methods: called from a consumer's `effect()`, the state read on the
1547
+ // way — `selected`, focus, `disabled`, the inputs — would make the effect run again whenever it changes.
1548
+ untracked(() => (this.selected = !this.selected));
1021
1549
  }
1022
1550
  setSelected(selected) {
1023
- if (this.selectAllRow() || this._selected === selected || !this.tree.selectionModel) {
1024
- return;
1025
- }
1026
- this._selected = selected;
1027
- if (selected) {
1028
- this.tree.selectionModel.select(this.data);
1029
- }
1030
- else {
1031
- this.tree.selectionModel.deselect(this.data);
1032
- }
1033
- if (this.showCheckbox) {
1034
- this.updateCheckboxState();
1035
- }
1036
- this.markForCheck();
1551
+ untracked(() => {
1552
+ if (this.selectAllRow() || this.selectedState() === selected || !this.tree.selectionModel) {
1553
+ return;
1554
+ }
1555
+ this.selectedState.set(selected);
1556
+ if (selected) {
1557
+ this.tree.selectionModel.select(this.data);
1558
+ }
1559
+ else {
1560
+ this.tree.selectionModel.deselect(this.data);
1561
+ }
1562
+ if (this.showCheckbox) {
1563
+ this.updateCheckboxState();
1564
+ }
1565
+ });
1037
1566
  }
1038
1567
  focus(focusOrigin) {
1039
- if (focusOrigin === 'program' || this.disabled || this.actionButton()?.hasFocus)
1040
- return;
1041
- // With the pointer already on this node, revealing it would shift the tree out from under it.
1042
- kbqFocusAndReveal(this.elementRef.nativeElement, focusOrigin === 'mouse');
1043
- if (!this.hasFocus) {
1044
- this.onFocus.next({ option: this });
1045
- Promise.resolve().then(() => {
1046
- this.hasFocus = true;
1047
- this.markForCheck();
1048
- });
1049
- }
1568
+ untracked(() => {
1569
+ if (focusOrigin === 'program' || this.disabled || this.actionButton()?.hasFocus)
1570
+ return;
1571
+ // With the pointer already on this node, revealing it would shift the tree out from under it.
1572
+ kbqFocusAndReveal(this.elementRef.nativeElement, focusOrigin === 'mouse');
1573
+ if (!this.hasFocus && !this.focusReported) {
1574
+ const event = { option: this };
1575
+ this.focusReported = true;
1576
+ this.focusEvents.next(event);
1577
+ this.tree.reportOptionFocus?.(event);
1578
+ Promise.resolve().then(() => {
1579
+ this.focusReported = false;
1580
+ this.hasFocus = true;
1581
+ // The view only: focus changes no checkbox state.
1582
+ this.changeDetectorRef.markForCheck();
1583
+ });
1584
+ }
1585
+ });
1050
1586
  }
1051
1587
  blur() {
1052
1588
  if (this.preventBlur) {
1053
1589
  return;
1054
1590
  }
1055
- // When animations are enabled, Angular may end up removing the option from the DOM a little
1056
- // earlier than usual, causing it to be blurred and throwing off the logic in the tree
1057
- // that moves focus not the next item. To work around the issue, we defer marking the option
1058
- // as not focused until the next time the zone stabilizes.
1059
- this.ngZone.onStable
1060
- .asObservable()
1061
- .pipe(take(1))
1062
- .subscribe(() => {
1063
- this.ngZone.run(() => {
1064
- if (this.actionButton()?.hasFocus || this.tree.optionShouldHoldFocusOnBlur) {
1065
- return;
1066
- }
1067
- this.hasFocus = false;
1068
- this.onBlur.next({ option: this });
1069
- });
1070
- });
1071
- }
1072
- /** @docs-private */
1591
+ // Deferred until the focus has settled: whatever takes it — this option's action button, or another option,
1592
+ // which marks itself focused on a microtask — records it only after this blur. Reported before that, the move
1593
+ // reads as the focus leaving the options: the option would drop its focused state while its own action button
1594
+ // holds the focus, and the tree its active option.
1595
+ afterNextRender(() => {
1596
+ // Focus can be back by the time this runs (a blur and a focus in the same task): then nothing was lost.
1597
+ if (_getFocusedElementPierceShadowDom() === this.elementRef.nativeElement)
1598
+ return;
1599
+ if (this.actionButton()?.hasFocus || this.tree.optionShouldHoldFocusOnBlur) {
1600
+ return;
1601
+ }
1602
+ this.hasFocus = false;
1603
+ const event = { option: this };
1604
+ this.blurEvents.next(event);
1605
+ this.tree.reportOptionBlur?.(event);
1606
+ },
1607
+ // The environment injector, not the option's: an option removed while focused is blurred as its view is
1608
+ // destroyed, and the tree still has to hear about it to move focus.
1609
+ { injector: this.environmentInjector });
1610
+ }
1611
+ /** @docs-private */
1073
1612
  getHeight() {
1074
1613
  return kbqGetElementHeight(this.elementRef.nativeElement);
1075
1614
  }
1615
+ /**
1616
+ * Label the key manager's type-ahead matches against.
1617
+ *
1618
+ * The "select all" row is navigable but is not a data node, and its label is a localized phrase —
1619
+ * answering type-ahead with it would hijack every query starting with that letter.
1620
+ *
1621
+ * @docs-private
1622
+ */
1623
+ getLabel() {
1624
+ return this.selectAllRow() ? '' : this.viewValue;
1625
+ }
1076
1626
  select(setFocus = true) {
1077
- if (this.selectAllRow() || this._selected) {
1078
- return;
1079
- }
1080
- this._selected = true;
1081
- if (setFocus && !this.hasFocus) {
1082
- this.focus();
1083
- }
1084
- this.updateCheckboxState();
1085
- this.markForCheck();
1086
- this.emitSelectionChangeEvent();
1627
+ untracked(() => {
1628
+ if (this.selectAllRow() || this.selectedState()) {
1629
+ return;
1630
+ }
1631
+ this.selectedState.set(true);
1632
+ if (setFocus && !this.hasFocus) {
1633
+ this.focus();
1634
+ }
1635
+ // Its own state only: an ancestor's reads the selection model, which this leaves as it is.
1636
+ this.syncCheckboxState();
1637
+ this.emitSelectionChangeEvent();
1638
+ });
1087
1639
  }
1088
1640
  deselect() {
1089
- if (this.selectAllRow() || !this._selected) {
1090
- return;
1091
- }
1092
- this._selected = false;
1093
- this.updateCheckboxState();
1094
- this.markForCheck();
1095
- this.emitSelectionChangeEvent();
1641
+ untracked(() => {
1642
+ if (this.selectAllRow() || !this.selectedState()) {
1643
+ return;
1644
+ }
1645
+ this.selectedState.set(false);
1646
+ // Its own state only, as in `select`.
1647
+ this.syncCheckboxState();
1648
+ this.emitSelectionChangeEvent();
1649
+ });
1096
1650
  }
1097
1651
  onKeydown($event) {
1098
1652
  kbqFocusOptionActionOnTab($event, this.actionButton());
1099
1653
  }
1100
1654
  selectViaInteraction($event) {
1101
- if (this.disabled || !this.selectable()) {
1102
- return;
1103
- }
1104
- this.markForCheck();
1105
- this.userInteraction.emit();
1106
- const shiftKey = $event ? hasModifierKey($event, 'shiftKey') : false;
1107
- // ctrlKey is for Windows, metaKey is for MacOS
1108
- const ctrlKey = $event ? hasModifierKey($event, 'ctrlKey', 'metaKey') : false;
1109
- this.tree.setSelectedOptionsByClick(this, shiftKey, ctrlKey);
1655
+ untracked(() => {
1656
+ if (this.disabled || !this.selectable()) {
1657
+ return;
1658
+ }
1659
+ this.userInteraction.emit();
1660
+ const shiftKey = $event ? hasModifierKey($event, 'shiftKey') : false;
1661
+ // ctrlKey is for Windows, metaKey is for MacOS
1662
+ const ctrlKey = $event ? hasModifierKey($event, 'ctrlKey', 'metaKey') : false;
1663
+ this.tree.setSelectedOptionsByClick(this, shiftKey, ctrlKey);
1664
+ });
1110
1665
  }
1111
1666
  emitSelectionChangeEvent() {
1112
1667
  // The tree can still hold an option whose node was re-rendered away until it rebuilds its list.
1113
1668
  if (this.destroyRef.destroyed)
1114
1669
  return;
1115
- this.onSelectionChange.emit(new KbqTreeOptionChange(this));
1670
+ const event = new KbqTreeOptionChange(this);
1671
+ this.selectionChange.emit(event);
1672
+ this.onSelectionChange.emit(event);
1116
1673
  }
1117
1674
  getHostElement() {
1118
1675
  return this.elementRef.nativeElement;
1119
1676
  }
1120
1677
  markForCheck() {
1121
1678
  this.changeDetectorRef.markForCheck();
1122
- if (this.showCheckbox) {
1123
- this.updateCheckboxState();
1679
+ // Its own state only: after a selection, data or mode change the tree calls this on every option. A projected
1680
+ // checkbox shows the state while the tree's own is hidden.
1681
+ if (this.showCheckbox || this.externalPseudoCheckbox) {
1682
+ this.syncCheckboxState();
1124
1683
  }
1125
1684
  }
1126
1685
  /** @docs-private */
1127
1686
  onMouseenter() {
1128
1687
  if (this.disabled || !this.tree.inSelect)
1129
1688
  return;
1130
- this.focus('mouse');
1689
+ // Focusing the option it already holds would only run change detection.
1690
+ if (this.hasFocus && _getFocusedElementPierceShadowDom() === this.elementRef.nativeElement)
1691
+ return;
1692
+ this.ngZone.run(() => this.focus('mouse'));
1693
+ }
1694
+ /** Recomputes the option's own checkbox state, leaving its ancestors as they are. */
1695
+ syncCheckboxState() {
1696
+ if (this.selectAllRow())
1697
+ return;
1698
+ if (this.checkboxThirdState() && this.isExpandable) {
1699
+ // One descendant walk, not two: each walk covers the whole subtree, and the roll-up runs this method for
1700
+ // every ancestor.
1701
+ const descendants = this.tree.treeControl.getDescendants(this.data);
1702
+ const selectedCount = descendants.filter((child) => this.tree.selectionModel.isSelected(child)).length;
1703
+ if (selectedCount === descendants.length) {
1704
+ this.checkboxState = 'checked';
1705
+ }
1706
+ else if (selectedCount > 0) {
1707
+ this.checkboxState = 'indeterminate';
1708
+ }
1709
+ else {
1710
+ this.checkboxState = this.selected ? 'checked' : 'unchecked';
1711
+ }
1712
+ }
1713
+ else {
1714
+ this.checkboxState = this.selected ? 'checked' : 'unchecked';
1715
+ }
1716
+ }
1717
+ toAriaChecked(state) {
1718
+ return state === 'indeterminate' ? 'mixed' : `${state === 'checked'}`;
1131
1719
  }
1132
- /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqTreeOption, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1133
- /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.30", type: KbqTreeOption, isStandalone: true, selector: "kbq-tree-option", inputs: { checkboxThirdState: { classPropertyName: "checkboxThirdState", publicName: "checkboxThirdState", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: false, isRequired: false, transformFunction: null }, selectable: { classPropertyName: "selectable", publicName: "selectable", isSignal: true, isRequired: false, transformFunction: null }, selectAllRow: { classPropertyName: "selectAllRow", publicName: "selectAllRow", isSignal: true, isRequired: false, transformFunction: null }, showCheckbox: { classPropertyName: "showCheckbox", publicName: "showCheckbox", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { onSelectionChange: "onSelectionChange" }, host: { listeners: { "focusin": "focus()", "mouseenter": "onMouseenter()", "blur": "blur()", "click": "selectViaInteraction($event)", "keydown": "onKeydown($event)" }, properties: { "class.kbq-tree-option_multiple": "tree.multiple", "class.kbq-selected": "selected", "class.kbq-focused": "hasFocus", "class.kbq-disabled": "disabled", "class.kbq-action-button-focused": "actionButton()?.active", "attr.id": "id", "attr.tabindex": "-1", "attr.disabled": "disabled || null" }, classAttribute: "kbq-tree-option" }, providers: [
1720
+ resolvePredicates() {
1721
+ const branch = !this.selectAllRow() && this.tree.treeControl.isExpandable(this.data);
1722
+ return { disabled: this.disabled, expanded: branch ? this.isExpanded : null };
1723
+ }
1724
+ /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqTreeOption, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1725
+ /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.25", type: KbqTreeOption, isStandalone: true, selector: "kbq-tree-option", inputs: { checkboxThirdState: { classPropertyName: "checkboxThirdState", publicName: "checkboxThirdState", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, selectable: { classPropertyName: "selectable", publicName: "selectable", isSignal: true, isRequired: false, transformFunction: null }, selectAllRow: { classPropertyName: "selectAllRow", publicName: "selectAllRow", isSignal: true, isRequired: false, transformFunction: null }, showCheckboxInput: { classPropertyName: "showCheckboxInput", publicName: "showCheckbox", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange", onSelectionChange: "onSelectionChange" }, host: { attributes: { "role": "treeitem" }, listeners: { "focusin": "focus()", "blur": "blur()", "click": "selectViaInteraction($event)", "keydown": "onKeydown($event)" }, properties: { "class.kbq-tree-option_multiple": "tree.multiple", "class.kbq-selected": "selected", "class.kbq-focused": "hasFocus", "class.kbq-disabled": "checkedDisabled", "class.kbq-action-button-focused": "actionButton()?.active", "attr.id": "id", "attr.tabindex": "-1", "attr.aria-disabled": "checkedDisabled || null", "attr.aria-expanded": "ariaExpanded", "attr.aria-checked": "ariaChecked", "attr.aria-selected": "ariaSelected" }, classAttribute: "kbq-tree-option" }, providers: [
1134
1726
  { provide: KbqTreeNode, useExisting: KbqTreeOption },
1135
1727
  { provide: KBQ_TITLE_TEXT_REF, useExisting: KbqTreeOption },
1136
1728
  { provide: KBQ_OPTION_ACTION_PARENT, useExisting: KbqTreeOption }
1137
- ], queries: [{ propertyName: "toggleElementDirective", first: true, predicate: KbqTreeNodeToggleDirective, descendants: true, isSignal: true }, { propertyName: "toggleElementComponent", first: true, predicate: KbqTreeNodeToggleComponent, descendants: true, isSignal: true }, { propertyName: "pseudoCheckbox", first: true, predicate: KbqPseudoCheckbox, descendants: true, isSignal: true }, { propertyName: "actionButton", first: true, predicate: KbqOptionActionComponent, descendants: true, isSignal: true }, { propertyName: "tooltipTrigger", first: true, predicate: KbqTooltipTrigger, descendants: true }, { propertyName: "dropdownTrigger", first: true, predicate: KbqDropdownTrigger, descendants: true }], viewQueries: [{ propertyName: "parentTextElement", first: true, predicate: ["kbqTitleContainer"], descendants: true }], exportAs: ["kbqTreeOption"], usesInheritance: true, ngImport: i0, template: "<ng-content select=\"kbq-tree-node-toggle, [kbq-tree-node-toggle], [kbqTreeNodeToggle]\" />\n\n@if (externalPseudoCheckbox) {\n <ng-content select=\"kbq-pseudo-checkbox\" />\n} @else if (showCheckbox) {\n <kbq-pseudo-checkbox [disabled]=\"disabled\" [state]=\"checkboxState\" />\n}\n\n<ng-content select=\"kbq-checkbox\" />\n\n<ng-content select=\"[kbq-icon]\" />\n\n<ng-content select=\"kbq-progress-spinner\" />\n\n<span #kbqTitleContainer class=\"kbq-option-text\">\n <ng-content />\n</span>\n\n@if (actionButton()) {\n <kbq-action-container>\n <ng-content select=\"kbq-option-action\" />\n </kbq-action-container>\n}\n", styles: ["@keyframes kbq-progress{0%{background-position:0 0}to{background-position:64px 0}}.kbq-progress{position:relative}.kbq-progress:after{content:\"\";position:absolute;border-radius:inherit;inset:0;background:linear-gradient(135deg,#0000000a 12px,#ffffff1a 12px 22px,#0000000a 22px 34px,#ffffff1a 34px) repeat;background-size:32px 32px;animation:kbq-progress 1s linear infinite}@media(prefers-reduced-motion:reduce){.kbq-progress:after{animation:none}}.kbq-group{display:flex;flex-direction:row}.kbq-group_justified>.kbq-group-item{width:100%}.kbq-group .kbq-group-item+.kbq-group-item{margin-left:calc(-1 * var(--kbq-size-border-width))}.kbq-group>.kbq-group-item:first-child:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.kbq-group>.kbq-group-item:last-child:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.kbq-group>.kbq-group-item:not(:first-child):not(:last-child){border-radius:0}.kbq-group>.kbq-group-item:first-child:not(:last-child) .kbq-form-field__container{border-bottom-right-radius:0;border-top-right-radius:0}.kbq-group>.kbq-group-item:last-child:not(:first-child) .kbq-form-field__container{border-bottom-left-radius:0;border-top-left-radius:0}.kbq-group>.kbq-group-item:not(:first-child):not(:last-child) .kbq-form-field__container{border-radius:0}.kbq-vertical-group{display:flex;flex-direction:column}.kbq-vertical-group>.kbq-group-item:first-child:not(:last-child){border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-right-radius:var(--kbq-size-border-radius)}.kbq-vertical-group>.kbq-group-item:last-child:not(:first-child){border-top-right-radius:0;border-top-left-radius:0;border-bottom-left-radius:var(--kbq-size-border-radius)}.kbq-vertical-group>.kbq-group-item:not(:first-child):not(:last-child){border-radius:0}.kbq-vertical-group .kbq-group-item+.kbq-group-item{margin-top:calc(-1 * var(--kbq-size-border-width))}.kbq-vertical-group>.kbq-group-item:first-child:not(:last-child) .kbq-form-field__container{border-bottom-right-radius:0;border-bottom-left-radius:0}.kbq-vertical-group>.kbq-group-item:last-child:not(:first-child) .kbq-form-field__container{border-top-right-radius:0;border-top-left-radius:0}.kbq-vertical-group>.kbq-group-item:not(:first-child):not(:last-child) .kbq-form-field__container{border-radius:0}.kbq-truncate-line{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.kbq-no-select,.kbq-tree-option{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.kbq-tree-option:not(.kbq-disabled):hover .kbq-action-container,.kbq-tree-option:not(.kbq-disabled).kbq-hovered .kbq-action-container,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused .kbq-action-container{display:flex}.kbq-tree-selection.cdk-keyboard-focused .kbq-tree-option:not(.kbq-disabled).kbq-focused .kbq-action-container{display:flex}.kbq-tree-option{position:relative;box-sizing:border-box;display:flex;align-items:center;min-height:32px;overflow-wrap:break-word;border-width:var(--kbq-tree-size-container-focus-outline-width);border-style:solid;border-color:transparent;border-radius:var(--kbq-tree-option-border-radius);padding-top:calc(var(--kbq-tree-size-container-padding-vertical) - var(--kbq-tree-size-container-focus-outline-width));padding-right:calc(var(--kbq-tree-size-container-padding-right) - var(--kbq-tree-size-container-focus-outline-width));padding-bottom:calc(var(--kbq-tree-size-container-padding-vertical) - var(--kbq-tree-size-container-focus-outline-width));gap:var(--kbq-tree-size-container-content-gap-horizontal)}.kbq-tree-option .kbq-option-text>*{margin:0;padding:0;font-weight:400;font-size:inherit}.kbq-tree-option .kbq-option-text{display:flex;flex-direction:column;width:100%;box-sizing:content-box;overflow:hidden}.kbq-tree-option .kbq-option-text:empty{display:none}.kbq-tree-option .kbq-option-text{display:inline-block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;padding-top:var(--kbq-list-size-text-padding-vertical, 0);padding-bottom:var(--kbq-list-size-text-padding-vertical, 0)}.kbq-tree-option:has(.kbq-option-caption)>[kbq-tree-node-toggle],.kbq-tree-option:has(.kbq-option-caption)>[kbqTreeNodeToggle],.kbq-tree-option:has(.kbq-option-caption)>.kbq-tree-node-toggle,.kbq-tree-option:has(.kbq-option-caption)>.kbq-pseudo-checkbox,.kbq-tree-option:has(.kbq-option-caption)>kbq-checkbox,.kbq-tree-option:has(.kbq-option-caption)>[kbq-icon],.kbq-tree-option:has(.kbq-option-caption)>kbq-progress-spinner{align-self:flex-start;margin-top:var(--kbq-size-3xs)}.kbq-tree-option:has(.kbq-option-caption)>.kbq-tree-node-toggle{height:var(--kbq-typography-text-normal-line-height);margin-top:0}.kbq-tree-option:focus{outline:none}.kbq-tree-option:not(.kbq-disabled){cursor:pointer}.kbq-tree-option:is(.kbq-checked,.kbq-selected,.kbq-focused):has(+:is(.kbq-checked,.kbq-selected,.kbq-focused)){border-bottom-left-radius:0;border-bottom-right-radius:0}.kbq-tree-option:is(.kbq-checked,.kbq-selected,.kbq-focused)+:is(.kbq-checked,.kbq-selected,.kbq-focused){border-top-left-radius:0;border-top-right-radius:0}\n", ".kbq-tree,.kbq-tree-selection{--kbq-tree-size-indent-level: var(--kbq-size-xxl);--kbq-tree-size-container-padding-right: var(--kbq-size-s);--kbq-tree-size-container-padding-vertical: var(--kbq-size-xxs);--kbq-tree-size-container-content-gap-horizontal: var(--kbq-size-s);--kbq-tree-size-container-content-gap-vertical: 0px;--kbq-tree-size-container-focus-outline-width: var(--kbq-size-3xs);--kbq-tree-size-text-padding-vertical: var(--kbq-size-3xs);--kbq-tree-option-border-radius: var(--kbq-size-border-radius);--kbq-tree-default-container-background: transparent;--kbq-tree-default-text-color: var(--kbq-foreground-contrast);--kbq-tree-default-icon-color: var(--kbq-icon-contrast);--kbq-tree-default-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-hover-container-background: var(--kbq-states-background-transparent-hover);--kbq-tree-states-active-container-background: var(--kbq-states-background-transparent-active);--kbq-tree-states-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-focused-focus-outline-color: var(--kbq-states-line-focus-theme);--kbq-tree-states-selected-container-background: var(--kbq-background-theme-less);--kbq-tree-multiple-states-selected-container-background: var(--kbq-background-contrast-less);--kbq-tree-states-selected-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-selected-hover-container-background: var(--kbq-states-background-theme-less-hover);--kbq-tree-states-selected-active-container-background: var(--kbq-states-background-theme-less-active);--kbq-tree-multiple-states-selected-hover-container-background: var(--kbq-states-background-contrast-less-hover);--kbq-tree-multiple-states-selected-active-container-background: var(--kbq-states-background-contrast-less-active);--kbq-tree-states-selected-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-disabled-container-background: transparent;--kbq-tree-states-disabled-text-color: var(--kbq-states-foreground-disabled);--kbq-tree-states-disabled-icon-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-tree-toggle-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-action-button-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-caption-color: var(--kbq-states-foreground-disabled)}\n"], dependencies: [{ kind: "component", type: KbqPseudoCheckbox, selector: "kbq-pseudo-checkbox", inputs: ["big", "state", "disabled"] }, { kind: "component", type: KbqActionContainer, selector: "kbq-action-container", exportAs: ["kbqActionContainer"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
1729
+ ], queries: [{ propertyName: "toggleElementDirective", first: true, predicate: KbqTreeNodeToggleDirective, descendants: true, isSignal: true }, { propertyName: "toggleElementComponent", first: true, predicate: KbqTreeNodeToggleComponent, descendants: true, isSignal: true }, { propertyName: "pseudoCheckbox", first: true, predicate: KbqPseudoCheckbox, descendants: true, isSignal: true }, { propertyName: "actionButton", first: true, predicate: KbqOptionActionComponent, descendants: true, isSignal: true }, { propertyName: "tooltipTriggerQuery", first: true, predicate: KbqTooltipTrigger, descendants: true, isSignal: true }, { propertyName: "dropdownTriggerQuery", first: true, predicate: KbqDropdownTrigger, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "titleContainer", first: true, predicate: ["kbqTitleContainer"], descendants: true, isSignal: true }], exportAs: ["kbqTreeOption"], usesInheritance: true, ngImport: i0, template: "<ng-content select=\"kbq-tree-node-toggle, [kbq-tree-node-toggle], [kbqTreeNodeToggle]\" />\n\n@if (externalPseudoCheckbox) {\n <ng-content select=\"kbq-pseudo-checkbox\" />\n} @else if (showCheckbox) {\n <kbq-pseudo-checkbox [disabled]=\"disabled\" [state]=\"checkboxState\" />\n}\n\n<ng-content select=\"kbq-checkbox\" />\n\n<ng-content select=\"[kbq-icon]\" />\n\n<ng-content select=\"kbq-progress-spinner\" />\n\n<span #kbqTitleContainer class=\"kbq-option-text\">\n <ng-content />\n</span>\n\n@if (actionButton()) {\n <kbq-action-container>\n <ng-content select=\"kbq-option-action\" />\n </kbq-action-container>\n}\n", styles: ["@charset \"UTF-8\";.kbq-group{display:flex;flex-direction:row}.kbq-group_justified>.kbq-group-item{width:100%}.kbq-group .kbq-group-item+.kbq-group-item{margin-inline-start:calc(-1 * var(--kbq-size-border-width))}.kbq-group>.kbq-group-item:first-child:not(:last-child){border-start-end-radius:0;border-end-end-radius:0}.kbq-group>.kbq-group-item:last-child:not(:first-child){border-start-start-radius:0;border-end-start-radius:0}.kbq-group>.kbq-group-item:not(:first-child):not(:last-child){border-radius:0}.kbq-group>.kbq-group-item:first-child:not(:last-child) .kbq-form-field__container{border-start-end-radius:0;border-end-end-radius:0}.kbq-group>.kbq-group-item:last-child:not(:first-child) .kbq-form-field__container{border-start-start-radius:0;border-end-start-radius:0}.kbq-group>.kbq-group-item:not(:first-child):not(:last-child) .kbq-form-field__container{border-radius:0}.kbq-vertical-group{display:flex;flex-direction:column}.kbq-vertical-group>.kbq-group-item:first-child:not(:last-child){border-end-start-radius:0;border-end-end-radius:0;border-start-end-radius:var(--kbq-size-border-radius)}@supports (corner-shape: squircle){.kbq-vertical-group>.kbq-group-item:first-child:not(:last-child){corner-shape:squircle;border-start-end-radius:clamp(var(--kbq-size-border-radius) * 1.85,var(--kbq-size-border-radius) * 2.3 - 3.6px,var(--kbq-size-border-radius) * 2)}}.kbq-vertical-group>.kbq-group-item:last-child:not(:first-child){border-start-start-radius:0;border-start-end-radius:0;border-end-start-radius:var(--kbq-size-border-radius)}@supports (corner-shape: squircle){.kbq-vertical-group>.kbq-group-item:last-child:not(:first-child){corner-shape:squircle;border-end-start-radius:clamp(var(--kbq-size-border-radius) * 1.85,var(--kbq-size-border-radius) * 2.3 - 3.6px,var(--kbq-size-border-radius) * 2)}}.kbq-vertical-group>.kbq-group-item:not(:first-child):not(:last-child){border-radius:0}.kbq-vertical-group .kbq-group-item+.kbq-group-item{margin-top:calc(-1 * var(--kbq-size-border-width))}.kbq-vertical-group>.kbq-group-item:first-child:not(:last-child) .kbq-form-field__container{border-end-start-radius:0;border-end-end-radius:0}.kbq-vertical-group>.kbq-group-item:last-child:not(:first-child) .kbq-form-field__container{border-start-start-radius:0;border-start-end-radius:0}.kbq-vertical-group>.kbq-group-item:not(:first-child):not(:last-child) .kbq-form-field__container{border-radius:0}.kbq-truncate-line{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.kbq-tree-option{-webkit-user-select:none;user-select:none}.kbq-tree-option:not(.kbq-disabled):hover .kbq-action-container,.kbq-tree-option:not(.kbq-disabled).kbq-hovered .kbq-action-container,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused .kbq-action-container{display:flex}.kbq-tree-selection.cdk-keyboard-focused .kbq-tree-option:not(.kbq-disabled).kbq-focused .kbq-action-container{display:flex}.kbq-tree-option{position:relative;box-sizing:border-box;display:flex;align-items:center;min-height:32px;overflow-wrap:break-word;border-width:var(--kbq-tree-size-container-focus-outline-width);border-style:solid;border-color:transparent;border-radius:var(--kbq-tree-option-border-radius)}@supports (corner-shape: squircle){.kbq-tree-option{corner-shape:squircle;border-radius:clamp(var(--kbq-tree-option-border-radius) * 1.85,var(--kbq-tree-option-border-radius) * 2.3 - 3.6px,var(--kbq-tree-option-border-radius) * 2)}}.kbq-tree-option{padding-top:calc(var(--kbq-tree-size-container-padding-vertical) - var(--kbq-tree-size-container-focus-outline-width));padding-right:calc(var(--kbq-tree-size-container-padding-right) - var(--kbq-tree-size-container-focus-outline-width));padding-bottom:calc(var(--kbq-tree-size-container-padding-vertical) - var(--kbq-tree-size-container-focus-outline-width));gap:var(--kbq-tree-size-container-content-gap-horizontal)}.kbq-tree-option .kbq-option-text>*{margin:0;padding:0;font-weight:400;font-size:inherit}.kbq-tree-option .kbq-option-text{display:flex;flex-direction:column;width:100%;box-sizing:content-box;overflow:hidden}.kbq-tree-option .kbq-option-text:empty{display:none}.kbq-tree-option .kbq-option-text{display:inline-block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.kbq-tree-option:has(.kbq-option-caption)>[kbq-tree-node-toggle],.kbq-tree-option:has(.kbq-option-caption)>[kbqTreeNodeToggle],.kbq-tree-option:has(.kbq-option-caption)>.kbq-tree-node-toggle,.kbq-tree-option:has(.kbq-option-caption)>.kbq-pseudo-checkbox,.kbq-tree-option:has(.kbq-option-caption)>kbq-checkbox,.kbq-tree-option:has(.kbq-option-caption)>[kbq-icon],.kbq-tree-option:has(.kbq-option-caption)>kbq-progress-spinner{align-self:flex-start;margin-top:var(--kbq-size-3xs)}.kbq-tree-option:has(.kbq-option-caption)>.kbq-tree-node-toggle{height:var(--kbq-typography-text-normal-line-height);margin-top:0}.kbq-tree-option:focus{outline:none}.kbq-tree-option:not(.kbq-disabled){cursor:pointer}.kbq-tree-option:is(.kbq-checked,.kbq-selected,.kbq-focused):has(+:is(.kbq-checked,.kbq-selected,.kbq-focused)){border-bottom-left-radius:0;border-bottom-right-radius:0}.kbq-tree-option:is(.kbq-checked,.kbq-selected,.kbq-focused)+:is(.kbq-checked,.kbq-selected,.kbq-focused){border-top-left-radius:0;border-top-right-radius:0}\n", ".kbq-tree,.kbq-tree-selection{--kbq-tree-size-indent-level: var(--kbq-size-xxl);--kbq-tree-size-container-padding-right: var(--kbq-size-s);--kbq-tree-size-container-padding-vertical: var(--kbq-size-xxs);--kbq-tree-size-container-content-gap-horizontal: var(--kbq-size-s);--kbq-tree-size-container-focus-outline-width: var(--kbq-size-3xs);--kbq-tree-size-text-padding-vertical: var(--kbq-size-3xs);--kbq-tree-option-border-radius: var(--kbq-size-border-radius);--kbq-tree-default-container-background: transparent;--kbq-tree-default-text-color: var(--kbq-foreground-contrast);--kbq-tree-default-icon-color: var(--kbq-icon-contrast);--kbq-tree-default-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-hover-container-background: var(--kbq-states-background-transparent-hover);--kbq-tree-states-active-container-background: var(--kbq-states-background-transparent-active);--kbq-tree-states-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-focused-focus-outline-color: var(--kbq-states-line-focus-theme);--kbq-tree-states-selected-container-background: var(--kbq-background-theme-less);--kbq-tree-multiple-states-selected-container-background: var(--kbq-background-contrast-less);--kbq-tree-states-selected-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-selected-hover-container-background: var(--kbq-states-background-theme-less-hover);--kbq-tree-states-selected-active-container-background: var(--kbq-states-background-theme-less-active);--kbq-tree-multiple-states-selected-hover-container-background: var(--kbq-states-background-contrast-less-hover);--kbq-tree-multiple-states-selected-active-container-background: var(--kbq-states-background-contrast-less-active);--kbq-tree-states-selected-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-disabled-container-background: transparent;--kbq-tree-states-disabled-text-color: var(--kbq-states-foreground-disabled);--kbq-tree-states-disabled-icon-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-tree-toggle-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-action-button-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-caption-color: var(--kbq-states-foreground-disabled)}\n"], dependencies: [{ kind: "component", type: KbqPseudoCheckbox, selector: "kbq-pseudo-checkbox", inputs: ["big", "state", "disabled"] }, { kind: "component", type: KbqActionContainer, selector: "kbq-action-container", exportAs: ["kbqActionContainer"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
1138
1730
  }
1139
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqTreeOption, decorators: [{
1731
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqTreeOption, decorators: [{
1140
1732
  type: Component,
1141
1733
  args: [{ selector: 'kbq-tree-option', imports: [
1142
1734
  KbqPseudoCheckbox,
@@ -1147,34 +1739,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImpo
1147
1739
  { provide: KBQ_OPTION_ACTION_PARENT, useExisting: KbqTreeOption }
1148
1740
  ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
1149
1741
  class: 'kbq-tree-option',
1742
+ // The "select all" row is a treeitem too: `role="checkbox"` would be an invalid child of
1743
+ // `role="tree"`, and `aria-checked` already carries its state.
1744
+ role: 'treeitem',
1150
1745
  '[class.kbq-tree-option_multiple]': 'tree.multiple',
1151
1746
  '[class.kbq-selected]': 'selected',
1152
1747
  '[class.kbq-focused]': 'hasFocus',
1153
- '[class.kbq-disabled]': 'disabled',
1748
+ '[class.kbq-disabled]': 'checkedDisabled',
1154
1749
  '[class.kbq-action-button-focused]': 'actionButton()?.active',
1155
1750
  '[attr.id]': 'id',
1156
1751
  '[attr.tabindex]': '-1',
1157
- '[attr.disabled]': 'disabled || null',
1752
+ '[attr.aria-disabled]': 'checkedDisabled || null',
1753
+ '[attr.aria-expanded]': 'ariaExpanded',
1754
+ // `aria-level` comes from `KbqTreeNode`: a second binding here would read `level` twice.
1755
+ '[attr.aria-checked]': 'ariaChecked',
1756
+ '[attr.aria-selected]': 'ariaSelected',
1158
1757
  '(focusin)': 'focus()',
1159
- '(mouseenter)': 'onMouseenter()',
1160
1758
  '(blur)': 'blur()',
1161
1759
  '(click)': 'selectViaInteraction($event)',
1162
1760
  '(keydown)': 'onKeydown($event)'
1163
- }, exportAs: 'kbqTreeOption', template: "<ng-content select=\"kbq-tree-node-toggle, [kbq-tree-node-toggle], [kbqTreeNodeToggle]\" />\n\n@if (externalPseudoCheckbox) {\n <ng-content select=\"kbq-pseudo-checkbox\" />\n} @else if (showCheckbox) {\n <kbq-pseudo-checkbox [disabled]=\"disabled\" [state]=\"checkboxState\" />\n}\n\n<ng-content select=\"kbq-checkbox\" />\n\n<ng-content select=\"[kbq-icon]\" />\n\n<ng-content select=\"kbq-progress-spinner\" />\n\n<span #kbqTitleContainer class=\"kbq-option-text\">\n <ng-content />\n</span>\n\n@if (actionButton()) {\n <kbq-action-container>\n <ng-content select=\"kbq-option-action\" />\n </kbq-action-container>\n}\n", styles: ["@keyframes kbq-progress{0%{background-position:0 0}to{background-position:64px 0}}.kbq-progress{position:relative}.kbq-progress:after{content:\"\";position:absolute;border-radius:inherit;inset:0;background:linear-gradient(135deg,#0000000a 12px,#ffffff1a 12px 22px,#0000000a 22px 34px,#ffffff1a 34px) repeat;background-size:32px 32px;animation:kbq-progress 1s linear infinite}@media(prefers-reduced-motion:reduce){.kbq-progress:after{animation:none}}.kbq-group{display:flex;flex-direction:row}.kbq-group_justified>.kbq-group-item{width:100%}.kbq-group .kbq-group-item+.kbq-group-item{margin-left:calc(-1 * var(--kbq-size-border-width))}.kbq-group>.kbq-group-item:first-child:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.kbq-group>.kbq-group-item:last-child:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.kbq-group>.kbq-group-item:not(:first-child):not(:last-child){border-radius:0}.kbq-group>.kbq-group-item:first-child:not(:last-child) .kbq-form-field__container{border-bottom-right-radius:0;border-top-right-radius:0}.kbq-group>.kbq-group-item:last-child:not(:first-child) .kbq-form-field__container{border-bottom-left-radius:0;border-top-left-radius:0}.kbq-group>.kbq-group-item:not(:first-child):not(:last-child) .kbq-form-field__container{border-radius:0}.kbq-vertical-group{display:flex;flex-direction:column}.kbq-vertical-group>.kbq-group-item:first-child:not(:last-child){border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-right-radius:var(--kbq-size-border-radius)}.kbq-vertical-group>.kbq-group-item:last-child:not(:first-child){border-top-right-radius:0;border-top-left-radius:0;border-bottom-left-radius:var(--kbq-size-border-radius)}.kbq-vertical-group>.kbq-group-item:not(:first-child):not(:last-child){border-radius:0}.kbq-vertical-group .kbq-group-item+.kbq-group-item{margin-top:calc(-1 * var(--kbq-size-border-width))}.kbq-vertical-group>.kbq-group-item:first-child:not(:last-child) .kbq-form-field__container{border-bottom-right-radius:0;border-bottom-left-radius:0}.kbq-vertical-group>.kbq-group-item:last-child:not(:first-child) .kbq-form-field__container{border-top-right-radius:0;border-top-left-radius:0}.kbq-vertical-group>.kbq-group-item:not(:first-child):not(:last-child) .kbq-form-field__container{border-radius:0}.kbq-truncate-line{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.kbq-no-select,.kbq-tree-option{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.kbq-tree-option:not(.kbq-disabled):hover .kbq-action-container,.kbq-tree-option:not(.kbq-disabled).kbq-hovered .kbq-action-container,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused .kbq-action-container{display:flex}.kbq-tree-selection.cdk-keyboard-focused .kbq-tree-option:not(.kbq-disabled).kbq-focused .kbq-action-container{display:flex}.kbq-tree-option{position:relative;box-sizing:border-box;display:flex;align-items:center;min-height:32px;overflow-wrap:break-word;border-width:var(--kbq-tree-size-container-focus-outline-width);border-style:solid;border-color:transparent;border-radius:var(--kbq-tree-option-border-radius);padding-top:calc(var(--kbq-tree-size-container-padding-vertical) - var(--kbq-tree-size-container-focus-outline-width));padding-right:calc(var(--kbq-tree-size-container-padding-right) - var(--kbq-tree-size-container-focus-outline-width));padding-bottom:calc(var(--kbq-tree-size-container-padding-vertical) - var(--kbq-tree-size-container-focus-outline-width));gap:var(--kbq-tree-size-container-content-gap-horizontal)}.kbq-tree-option .kbq-option-text>*{margin:0;padding:0;font-weight:400;font-size:inherit}.kbq-tree-option .kbq-option-text{display:flex;flex-direction:column;width:100%;box-sizing:content-box;overflow:hidden}.kbq-tree-option .kbq-option-text:empty{display:none}.kbq-tree-option .kbq-option-text{display:inline-block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;padding-top:var(--kbq-list-size-text-padding-vertical, 0);padding-bottom:var(--kbq-list-size-text-padding-vertical, 0)}.kbq-tree-option:has(.kbq-option-caption)>[kbq-tree-node-toggle],.kbq-tree-option:has(.kbq-option-caption)>[kbqTreeNodeToggle],.kbq-tree-option:has(.kbq-option-caption)>.kbq-tree-node-toggle,.kbq-tree-option:has(.kbq-option-caption)>.kbq-pseudo-checkbox,.kbq-tree-option:has(.kbq-option-caption)>kbq-checkbox,.kbq-tree-option:has(.kbq-option-caption)>[kbq-icon],.kbq-tree-option:has(.kbq-option-caption)>kbq-progress-spinner{align-self:flex-start;margin-top:var(--kbq-size-3xs)}.kbq-tree-option:has(.kbq-option-caption)>.kbq-tree-node-toggle{height:var(--kbq-typography-text-normal-line-height);margin-top:0}.kbq-tree-option:focus{outline:none}.kbq-tree-option:not(.kbq-disabled){cursor:pointer}.kbq-tree-option:is(.kbq-checked,.kbq-selected,.kbq-focused):has(+:is(.kbq-checked,.kbq-selected,.kbq-focused)){border-bottom-left-radius:0;border-bottom-right-radius:0}.kbq-tree-option:is(.kbq-checked,.kbq-selected,.kbq-focused)+:is(.kbq-checked,.kbq-selected,.kbq-focused){border-top-left-radius:0;border-top-right-radius:0}\n", ".kbq-tree,.kbq-tree-selection{--kbq-tree-size-indent-level: var(--kbq-size-xxl);--kbq-tree-size-container-padding-right: var(--kbq-size-s);--kbq-tree-size-container-padding-vertical: var(--kbq-size-xxs);--kbq-tree-size-container-content-gap-horizontal: var(--kbq-size-s);--kbq-tree-size-container-content-gap-vertical: 0px;--kbq-tree-size-container-focus-outline-width: var(--kbq-size-3xs);--kbq-tree-size-text-padding-vertical: var(--kbq-size-3xs);--kbq-tree-option-border-radius: var(--kbq-size-border-radius);--kbq-tree-default-container-background: transparent;--kbq-tree-default-text-color: var(--kbq-foreground-contrast);--kbq-tree-default-icon-color: var(--kbq-icon-contrast);--kbq-tree-default-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-hover-container-background: var(--kbq-states-background-transparent-hover);--kbq-tree-states-active-container-background: var(--kbq-states-background-transparent-active);--kbq-tree-states-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-focused-focus-outline-color: var(--kbq-states-line-focus-theme);--kbq-tree-states-selected-container-background: var(--kbq-background-theme-less);--kbq-tree-multiple-states-selected-container-background: var(--kbq-background-contrast-less);--kbq-tree-states-selected-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-selected-hover-container-background: var(--kbq-states-background-theme-less-hover);--kbq-tree-states-selected-active-container-background: var(--kbq-states-background-theme-less-active);--kbq-tree-multiple-states-selected-hover-container-background: var(--kbq-states-background-contrast-less-hover);--kbq-tree-multiple-states-selected-active-container-background: var(--kbq-states-background-contrast-less-active);--kbq-tree-states-selected-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-disabled-container-background: transparent;--kbq-tree-states-disabled-text-color: var(--kbq-states-foreground-disabled);--kbq-tree-states-disabled-icon-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-tree-toggle-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-action-button-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-caption-color: var(--kbq-states-foreground-disabled)}\n"] }]
1164
- }], ctorParameters: () => [], propDecorators: { parentTextElement: [{
1165
- type: ViewChild,
1166
- args: ['kbqTitleContainer']
1167
- }], toggleElementDirective: [{ type: i0.ContentChild, args: [i0.forwardRef(() => KbqTreeNodeToggleDirective), { isSignal: true }] }], toggleElementComponent: [{ type: i0.ContentChild, args: [i0.forwardRef(() => KbqTreeNodeToggleComponent), { isSignal: true }] }], pseudoCheckbox: [{ type: i0.ContentChild, args: [i0.forwardRef(() => KbqPseudoCheckbox), { isSignal: true }] }], actionButton: [{ type: i0.ContentChild, args: [i0.forwardRef(() => KbqOptionActionComponent), { isSignal: true }] }], tooltipTrigger: [{
1168
- type: ContentChild,
1169
- args: [KbqTooltipTrigger]
1170
- }], dropdownTrigger: [{
1171
- type: ContentChild,
1172
- args: [KbqDropdownTrigger]
1173
- }], checkboxThirdState: [{ type: i0.Input, args: [{ isSignal: true, alias: "checkboxThirdState", required: false }] }], disabled: [{
1174
- type: Input
1175
- }], selectable: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectable", required: false }] }], selectAllRow: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectAllRow", required: false }] }], showCheckbox: [{
1176
- type: Input
1177
- }], onSelectionChange: [{ type: i0.Output, args: ["onSelectionChange"] }] } });
1761
+ }, exportAs: 'kbqTreeOption', template: "<ng-content select=\"kbq-tree-node-toggle, [kbq-tree-node-toggle], [kbqTreeNodeToggle]\" />\n\n@if (externalPseudoCheckbox) {\n <ng-content select=\"kbq-pseudo-checkbox\" />\n} @else if (showCheckbox) {\n <kbq-pseudo-checkbox [disabled]=\"disabled\" [state]=\"checkboxState\" />\n}\n\n<ng-content select=\"kbq-checkbox\" />\n\n<ng-content select=\"[kbq-icon]\" />\n\n<ng-content select=\"kbq-progress-spinner\" />\n\n<span #kbqTitleContainer class=\"kbq-option-text\">\n <ng-content />\n</span>\n\n@if (actionButton()) {\n <kbq-action-container>\n <ng-content select=\"kbq-option-action\" />\n </kbq-action-container>\n}\n", styles: ["@charset \"UTF-8\";.kbq-group{display:flex;flex-direction:row}.kbq-group_justified>.kbq-group-item{width:100%}.kbq-group .kbq-group-item+.kbq-group-item{margin-inline-start:calc(-1 * var(--kbq-size-border-width))}.kbq-group>.kbq-group-item:first-child:not(:last-child){border-start-end-radius:0;border-end-end-radius:0}.kbq-group>.kbq-group-item:last-child:not(:first-child){border-start-start-radius:0;border-end-start-radius:0}.kbq-group>.kbq-group-item:not(:first-child):not(:last-child){border-radius:0}.kbq-group>.kbq-group-item:first-child:not(:last-child) .kbq-form-field__container{border-start-end-radius:0;border-end-end-radius:0}.kbq-group>.kbq-group-item:last-child:not(:first-child) .kbq-form-field__container{border-start-start-radius:0;border-end-start-radius:0}.kbq-group>.kbq-group-item:not(:first-child):not(:last-child) .kbq-form-field__container{border-radius:0}.kbq-vertical-group{display:flex;flex-direction:column}.kbq-vertical-group>.kbq-group-item:first-child:not(:last-child){border-end-start-radius:0;border-end-end-radius:0;border-start-end-radius:var(--kbq-size-border-radius)}@supports (corner-shape: squircle){.kbq-vertical-group>.kbq-group-item:first-child:not(:last-child){corner-shape:squircle;border-start-end-radius:clamp(var(--kbq-size-border-radius) * 1.85,var(--kbq-size-border-radius) * 2.3 - 3.6px,var(--kbq-size-border-radius) * 2)}}.kbq-vertical-group>.kbq-group-item:last-child:not(:first-child){border-start-start-radius:0;border-start-end-radius:0;border-end-start-radius:var(--kbq-size-border-radius)}@supports (corner-shape: squircle){.kbq-vertical-group>.kbq-group-item:last-child:not(:first-child){corner-shape:squircle;border-end-start-radius:clamp(var(--kbq-size-border-radius) * 1.85,var(--kbq-size-border-radius) * 2.3 - 3.6px,var(--kbq-size-border-radius) * 2)}}.kbq-vertical-group>.kbq-group-item:not(:first-child):not(:last-child){border-radius:0}.kbq-vertical-group .kbq-group-item+.kbq-group-item{margin-top:calc(-1 * var(--kbq-size-border-width))}.kbq-vertical-group>.kbq-group-item:first-child:not(:last-child) .kbq-form-field__container{border-end-start-radius:0;border-end-end-radius:0}.kbq-vertical-group>.kbq-group-item:last-child:not(:first-child) .kbq-form-field__container{border-start-start-radius:0;border-start-end-radius:0}.kbq-vertical-group>.kbq-group-item:not(:first-child):not(:last-child) .kbq-form-field__container{border-radius:0}.kbq-truncate-line{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.kbq-tree-option{-webkit-user-select:none;user-select:none}.kbq-tree-option:not(.kbq-disabled):hover .kbq-action-container,.kbq-tree-option:not(.kbq-disabled).kbq-hovered .kbq-action-container,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused .kbq-action-container{display:flex}.kbq-tree-selection.cdk-keyboard-focused .kbq-tree-option:not(.kbq-disabled).kbq-focused .kbq-action-container{display:flex}.kbq-tree-option{position:relative;box-sizing:border-box;display:flex;align-items:center;min-height:32px;overflow-wrap:break-word;border-width:var(--kbq-tree-size-container-focus-outline-width);border-style:solid;border-color:transparent;border-radius:var(--kbq-tree-option-border-radius)}@supports (corner-shape: squircle){.kbq-tree-option{corner-shape:squircle;border-radius:clamp(var(--kbq-tree-option-border-radius) * 1.85,var(--kbq-tree-option-border-radius) * 2.3 - 3.6px,var(--kbq-tree-option-border-radius) * 2)}}.kbq-tree-option{padding-top:calc(var(--kbq-tree-size-container-padding-vertical) - var(--kbq-tree-size-container-focus-outline-width));padding-right:calc(var(--kbq-tree-size-container-padding-right) - var(--kbq-tree-size-container-focus-outline-width));padding-bottom:calc(var(--kbq-tree-size-container-padding-vertical) - var(--kbq-tree-size-container-focus-outline-width));gap:var(--kbq-tree-size-container-content-gap-horizontal)}.kbq-tree-option .kbq-option-text>*{margin:0;padding:0;font-weight:400;font-size:inherit}.kbq-tree-option .kbq-option-text{display:flex;flex-direction:column;width:100%;box-sizing:content-box;overflow:hidden}.kbq-tree-option .kbq-option-text:empty{display:none}.kbq-tree-option .kbq-option-text{display:inline-block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.kbq-tree-option:has(.kbq-option-caption)>[kbq-tree-node-toggle],.kbq-tree-option:has(.kbq-option-caption)>[kbqTreeNodeToggle],.kbq-tree-option:has(.kbq-option-caption)>.kbq-tree-node-toggle,.kbq-tree-option:has(.kbq-option-caption)>.kbq-pseudo-checkbox,.kbq-tree-option:has(.kbq-option-caption)>kbq-checkbox,.kbq-tree-option:has(.kbq-option-caption)>[kbq-icon],.kbq-tree-option:has(.kbq-option-caption)>kbq-progress-spinner{align-self:flex-start;margin-top:var(--kbq-size-3xs)}.kbq-tree-option:has(.kbq-option-caption)>.kbq-tree-node-toggle{height:var(--kbq-typography-text-normal-line-height);margin-top:0}.kbq-tree-option:focus{outline:none}.kbq-tree-option:not(.kbq-disabled){cursor:pointer}.kbq-tree-option:is(.kbq-checked,.kbq-selected,.kbq-focused):has(+:is(.kbq-checked,.kbq-selected,.kbq-focused)){border-bottom-left-radius:0;border-bottom-right-radius:0}.kbq-tree-option:is(.kbq-checked,.kbq-selected,.kbq-focused)+:is(.kbq-checked,.kbq-selected,.kbq-focused){border-top-left-radius:0;border-top-right-radius:0}\n", ".kbq-tree,.kbq-tree-selection{--kbq-tree-size-indent-level: var(--kbq-size-xxl);--kbq-tree-size-container-padding-right: var(--kbq-size-s);--kbq-tree-size-container-padding-vertical: var(--kbq-size-xxs);--kbq-tree-size-container-content-gap-horizontal: var(--kbq-size-s);--kbq-tree-size-container-focus-outline-width: var(--kbq-size-3xs);--kbq-tree-size-text-padding-vertical: var(--kbq-size-3xs);--kbq-tree-option-border-radius: var(--kbq-size-border-radius);--kbq-tree-default-container-background: transparent;--kbq-tree-default-text-color: var(--kbq-foreground-contrast);--kbq-tree-default-icon-color: var(--kbq-icon-contrast);--kbq-tree-default-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-hover-container-background: var(--kbq-states-background-transparent-hover);--kbq-tree-states-active-container-background: var(--kbq-states-background-transparent-active);--kbq-tree-states-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-focused-focus-outline-color: var(--kbq-states-line-focus-theme);--kbq-tree-states-selected-container-background: var(--kbq-background-theme-less);--kbq-tree-multiple-states-selected-container-background: var(--kbq-background-contrast-less);--kbq-tree-states-selected-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-selected-hover-container-background: var(--kbq-states-background-theme-less-hover);--kbq-tree-states-selected-active-container-background: var(--kbq-states-background-theme-less-active);--kbq-tree-multiple-states-selected-hover-container-background: var(--kbq-states-background-contrast-less-hover);--kbq-tree-multiple-states-selected-active-container-background: var(--kbq-states-background-contrast-less-active);--kbq-tree-states-selected-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-disabled-container-background: transparent;--kbq-tree-states-disabled-text-color: var(--kbq-states-foreground-disabled);--kbq-tree-states-disabled-icon-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-tree-toggle-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-action-button-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-caption-color: var(--kbq-states-foreground-disabled)}\n"] }]
1762
+ }], ctorParameters: () => [], propDecorators: { titleContainer: [{ type: i0.ViewChild, args: ['kbqTitleContainer', { isSignal: true }] }], toggleElementDirective: [{ type: i0.ContentChild, args: [i0.forwardRef(() => KbqTreeNodeToggleDirective), { isSignal: true }] }], toggleElementComponent: [{ type: i0.ContentChild, args: [i0.forwardRef(() => KbqTreeNodeToggleComponent), { isSignal: true }] }], pseudoCheckbox: [{ type: i0.ContentChild, args: [i0.forwardRef(() => KbqPseudoCheckbox), { isSignal: true }] }], actionButton: [{ type: i0.ContentChild, args: [i0.forwardRef(() => KbqOptionActionComponent), { isSignal: true }] }], tooltipTriggerQuery: [{ type: i0.ContentChild, args: [i0.forwardRef(() => KbqTooltipTrigger), { isSignal: true }] }], dropdownTriggerQuery: [{ type: i0.ContentChild, args: [i0.forwardRef(() => KbqDropdownTrigger), { isSignal: true }] }], checkboxThirdState: [{ type: i0.Input, args: [{ isSignal: true, alias: "checkboxThirdState", required: false }] }], disabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], selectable: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectable", required: false }] }], selectAllRow: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectAllRow", required: false }] }], showCheckboxInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCheckbox", required: false }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], onSelectionChange: [{ type: i0.Output, args: ["onSelectionChange"] }] } });
1178
1763
 
1179
1764
  /** Regex used to split a string on its CSS units. */
1180
1765
  const cssUnitPattern = /([A-Za-z%]+)$/;
@@ -1185,49 +1770,65 @@ class KbqTreeNodePadding {
1185
1770
  set level(value) {
1186
1771
  this.setLevelInput(value);
1187
1772
  }
1188
- // TODO: Skipped for migration because:
1189
- // Accessor inputs cannot be migrated as they are too complex.
1190
- get indent() {
1191
- return this._indent;
1192
- }
1193
- set indent(indent) {
1194
- this.setIndentInput(indent);
1195
- }
1196
1773
  get leftPadding() {
1197
- return (this.withIcon ? 0 : this.iconWidth) + this._indent;
1774
+ return (this.withIcon ? 0 : this.iconWidth) + this.parsedIndent().value;
1198
1775
  }
1199
1776
  get leftPaddingForFirstLevel() {
1200
1777
  const border = 2;
1201
- return (this.withIcon ? 0 : this.iconWidth) + this._indent - border;
1778
+ return (this.withIcon ? 0 : this.iconWidth) + this.parsedIndent().value - border;
1779
+ }
1780
+ /** CSS units used for the indentation value. */
1781
+ get indentUnits() {
1782
+ return this.parsedIndent().units;
1202
1783
  }
1203
1784
  constructor() {
1204
1785
  this.treeNode = inject(KbqTreeNode);
1205
1786
  this.tree = inject(KbqTreeBase);
1206
1787
  this.renderer = inject(Renderer2);
1207
1788
  this.element = inject(ElementRef);
1208
- this.option = inject(KbqTreeOption);
1789
+ // Optional so the directive also works on a bare `kbq-tree-node`, which has no option around it.
1790
+ this.option = inject(KbqTreeOption, { optional: true });
1209
1791
  this.dir = inject(Directionality, { optional: true });
1210
- this._indent = 12;
1211
- /** CSS units used for the indentation value. */
1212
- this.indentUnits = 'px';
1792
+ /** Indentation added per nesting level. Accepts a bare number (px) or a value with CSS units. */
1793
+ this.indent = input(12, { ...(ngDevMode ? { debugName: "indent" } : /* istanbul ignore next */ {}), alias: 'kbqTreeNodePaddingIndent' });
1794
+ this.parsedIndent = computed(() => {
1795
+ const indent = this.indent();
1796
+ if (typeof indent !== 'string') {
1797
+ return { value: coerceNumberProperty(indent), units: 'px' };
1798
+ }
1799
+ const [value, units] = indent.split(cssUnitPattern);
1800
+ return { value: coerceNumberProperty(value), units: units || 'px' };
1801
+ }, ...(ngDevMode ? [{ debugName: "parsedIndent" }] : /* istanbul ignore next */ []));
1802
+ /**
1803
+ * Horizontal room a toggle takes up in a row: its own 16px box plus the option's 8px `gap`. A node
1804
+ * without a toggle reserves the same amount so its content lines up with a sibling that has one —
1805
+ * which is why widening the toggle itself pushes every branch row out of line.
1806
+ */
1213
1807
  this.iconWidth = 24;
1214
1808
  this.dir?.change?.pipe(takeUntilDestroyed()).subscribe(() => this.setPadding());
1809
+ // The node the padding was computed from is gone once its view is reused, and the replacement
1810
+ // can sit at a different level.
1811
+ this.treeNode.refreshed.pipe(takeUntilDestroyed()).subscribe(() => this.setPadding());
1812
+ effect(() => {
1813
+ this.parsedIndent();
1814
+ this.setPadding();
1815
+ });
1215
1816
  }
1216
1817
  ngAfterViewInit() {
1217
- this.withIcon = this.option.isToggleInDefaultPlace;
1818
+ this.withIcon = this.option?.isToggleInDefaultPlace ?? false;
1218
1819
  this.setPadding();
1219
1820
  }
1220
1821
  paddingIndent() {
1221
1822
  const treeControl = this.tree.treeControl;
1222
1823
  const nodeLevel = this.treeNode.data && treeControl.getLevel ? treeControl.getLevel(this.treeNode.data) : 0;
1223
1824
  const level = this.level || nodeLevel;
1224
- return level > 0 ? `${level * this._indent + this.leftPadding}px` : `${this.leftPaddingForFirstLevel}px`;
1825
+ const { value, units } = this.parsedIndent();
1826
+ return level > 0 ? `${level * value + this.leftPadding}${units}` : `${this.leftPaddingForFirstLevel}${units}`;
1225
1827
  }
1226
1828
  /**
1227
1829
  * This has been extracted to a util because of TS 4 and VE.
1228
1830
  * View Engine doesn't support property rename inheritance.
1229
1831
  * TS 4.0 doesn't allow properties to override accessors or vice-versa.
1230
- * @docs-private
1231
1832
  */
1232
1833
  setLevelInput(value) {
1233
1834
  // Set to null as the fallback value so that _setPadding can fall back to the node level if the
@@ -1236,58 +1837,40 @@ class KbqTreeNodePadding {
1236
1837
  this._level = coerceNumberProperty(value, null);
1237
1838
  this.setPadding();
1238
1839
  }
1239
- /**
1240
- * This has been extracted to a util because of TS 4 and VE.
1241
- * View Engine doesn't support property rename inheritance.
1242
- * TS 4.0 doesn't allow properties to override accessors or vice-versa.
1243
- * @docs-private
1244
- */
1245
- setIndentInput(indent) {
1246
- let value = indent;
1247
- let units = 'px';
1248
- if (typeof indent === 'string') {
1249
- const parts = indent.split(cssUnitPattern);
1250
- value = parts[0];
1251
- units = parts[1] || units;
1252
- }
1253
- this.indentUnits = units;
1254
- this._indent = coerceNumberProperty(value);
1255
- this.setPadding();
1256
- }
1257
1840
  setPadding() {
1258
1841
  const padding = this.paddingIndent();
1259
1842
  const paddingProp = this.dir?.value === 'rtl' ? 'paddingRight' : 'paddingLeft';
1260
1843
  this.renderer.setStyle(this.element.nativeElement, paddingProp, padding);
1261
1844
  }
1262
- /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqTreeNodePadding, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1263
- /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.30", type: KbqTreeNodePadding, isStandalone: true, selector: "[kbqTreeNodePadding]", inputs: { indent: ["kbqTreeNodePaddingIndent", "indent"] }, exportAs: ["kbqTreeNodePadding"], ngImport: i0 }); }
1845
+ /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqTreeNodePadding, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1846
+ /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.25", type: KbqTreeNodePadding, isStandalone: true, selector: "[kbqTreeNodePadding]", inputs: { indent: { classPropertyName: "indent", publicName: "kbqTreeNodePaddingIndent", isSignal: true, isRequired: false, transformFunction: null } }, exportAs: ["kbqTreeNodePadding"], ngImport: i0 }); }
1264
1847
  }
1265
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqTreeNodePadding, decorators: [{
1848
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqTreeNodePadding, decorators: [{
1266
1849
  type: Directive,
1267
1850
  args: [{
1268
1851
  selector: '[kbqTreeNodePadding]',
1269
1852
  exportAs: 'kbqTreeNodePadding'
1270
1853
  }]
1271
- }], ctorParameters: () => [], propDecorators: { indent: [{
1272
- type: Input,
1273
- args: ['kbqTreeNodePaddingIndent']
1274
- }] } });
1854
+ }], ctorParameters: () => [], propDecorators: { indent: [{ type: i0.Input, args: [{ isSignal: true, alias: "kbqTreeNodePaddingIndent", required: false }] }] } });
1275
1855
 
1276
1856
  class KbqTree extends KbqTreeBase {
1277
- /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqTree, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
1278
- /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.30", type: KbqTree, isStandalone: true, selector: "kbq-tree", host: { classAttribute: "kbq-tree" }, exportAs: ["kbqTree"], usesInheritance: true, ngImport: i0, template: `
1857
+ /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqTree, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
1858
+ /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.25", type: KbqTree, isStandalone: true, selector: "kbq-tree", host: { attributes: { "role": "tree" }, classAttribute: "kbq-tree" }, providers: [{ provide: KbqTreeBase, useExisting: KbqTree }], exportAs: ["kbqTree"], usesInheritance: true, hostDirectives: [{ directive: i1.KbqStateSaving, inputs: ["useStateSaving", "useStateSaving", "stateSavingKey", "stateSavingKey"] }], ngImport: i0, template: `
1279
1859
  <ng-container kbqTreeNodeOutlet />
1280
- `, isInline: true, styles: [".kbq-tree{display:block}.kbq-tree-selection:focus{outline:none}.kbq-tree-option{--kbq-option-background: var(--kbq-tree-default-container-background);background:var(--kbq-tree-default-container-background)}.kbq-tree-option .kbq-option-text{color:var(--kbq-tree-default-text-color)}.kbq-tree-option .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-default-action-button-color)}.kbq-tree-option .kbq-option-caption{color:var(--kbq-tree-default-caption-color)}.kbq-tree-option:not(.kbq-disabled):hover,.kbq-tree-option:not(.kbq-disabled).kbq-hovered,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused{--kbq-option-background: var(--kbq-tree-states-hover-container-background);background:var(--kbq-tree-states-hover-container-background)}.kbq-tree-option:not(.kbq-disabled):hover .kbq-option-text,.kbq-tree-option:not(.kbq-disabled).kbq-hovered .kbq-option-text,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused .kbq-option-text{color:var(--kbq-tree-states-hover-text-color)}.kbq-tree-option:not(.kbq-disabled):hover .kbq-option-action .kbq-icon.kbq-empty,.kbq-tree-option:not(.kbq-disabled).kbq-hovered .kbq-option-action .kbq-icon.kbq-empty,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-hover-action-button-color)}.kbq-tree-option:not(.kbq-disabled):hover .kbq-option-caption,.kbq-tree-option:not(.kbq-disabled).kbq-hovered .kbq-option-caption,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused .kbq-option-caption{color:var(--kbq-tree-states-hover-caption-color)}.kbq-tree-option:not(.kbq-disabled):active,.kbq-tree-option:not(.kbq-disabled).kbq-active{--kbq-option-background: var(--kbq-tree-states-active-container-background);background:var(--kbq-tree-states-active-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-selected{--kbq-option-background: var(--kbq-tree-states-selected-container-background);background:var(--kbq-tree-states-selected-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-selected .kbq-option-text{color:var(--kbq-tree-states-selected-text-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-selected-action-button-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected .kbq-option-caption{color:var(--kbq-tree-states-selected-caption-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered{--kbq-option-background: var(--kbq-tree-states-selected-hover-container-background);background:var(--kbq-tree-states-selected-hover-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover .kbq-option-text,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered .kbq-option-text{color:var(--kbq-tree-states-selected-hover-text-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover .kbq-option-action .kbq-icon.kbq-empty,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-selected-hover-action-button-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover .kbq-option-caption,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered .kbq-option-caption{color:var(--kbq-tree-states-selected-hover-caption-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:active,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-active{--kbq-option-background: var(--kbq-tree-states-selected-active-container-background);background:var(--kbq-tree-states-selected-active-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected),.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected{--kbq-option-background: var(--kbq-tree-multiple-states-selected-container-background);background:var(--kbq-tree-multiple-states-selected-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected):hover,.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected).kbq-hovered,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected:hover,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected.kbq-hovered{--kbq-option-background: var(--kbq-tree-multiple-states-selected-hover-container-background);background:var(--kbq-tree-multiple-states-selected-hover-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected):active,.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected).kbq-active,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected:active,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected.kbq-active{--kbq-option-background: var(--kbq-tree-multiple-states-selected-active-container-background);background:var(--kbq-tree-multiple-states-selected-active-container-background)}.kbq-tree-option.kbq-disabled{--kbq-option-background: var(--kbq-tree-states-disabled-container-background);background:var(--kbq-tree-states-disabled-container-background)}.kbq-tree-option.kbq-disabled .kbq-option-text{color:var(--kbq-tree-states-disabled-text-color)}.kbq-tree-option.kbq-disabled .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-disabled-action-button-color)}.kbq-tree-option.kbq-disabled .kbq-option-caption{color:var(--kbq-tree-states-disabled-caption-color)}.kbq-tree-option.kbq-disabled .kbq-icon.kbq-empty:not(.kbq-tree-node-toggle .kbq-icon){color:var(--kbq-states-icon-disabled)}.kbq-tree-selection.cdk-keyboard-focused .kbq-tree-option.kbq-focused:not(.kbq-action-button-focused){border-color:var(--kbq-tree-states-focused-focus-outline-color)}.kbq-tree-option{font-size:var(--kbq-typography-text-normal-font-size);font-style:var(--kbq-typography-text-normal-font-style);font-weight:var(--kbq-typography-text-normal-font-weight);line-height:var(--kbq-typography-text-normal-line-height);font-family:var(--kbq-typography-text-normal-font-family);text-transform:var(--kbq-typography-text-normal-text-transform);font-feature-settings:var(--kbq-typography-text-normal-font-feature-settings);letter-spacing:var(--kbq-typography-text-normal-letter-spacing)}.kbq-option-caption{font-size:var(--kbq-typography-text-compact-font-size);font-style:var(--kbq-typography-text-compact-font-style);font-weight:var(--kbq-typography-text-compact-font-weight);line-height:var(--kbq-typography-text-compact-line-height);font-family:var(--kbq-typography-text-compact-font-family);text-transform:var(--kbq-typography-text-compact-text-transform);font-feature-settings:var(--kbq-typography-text-compact-font-feature-settings);letter-spacing:var(--kbq-typography-text-compact-letter-spacing)}\n", ".kbq-tree,.kbq-tree-selection{--kbq-tree-size-indent-level: var(--kbq-size-xxl);--kbq-tree-size-container-padding-right: var(--kbq-size-s);--kbq-tree-size-container-padding-vertical: var(--kbq-size-xxs);--kbq-tree-size-container-content-gap-horizontal: var(--kbq-size-s);--kbq-tree-size-container-content-gap-vertical: 0px;--kbq-tree-size-container-focus-outline-width: var(--kbq-size-3xs);--kbq-tree-size-text-padding-vertical: var(--kbq-size-3xs);--kbq-tree-option-border-radius: var(--kbq-size-border-radius);--kbq-tree-default-container-background: transparent;--kbq-tree-default-text-color: var(--kbq-foreground-contrast);--kbq-tree-default-icon-color: var(--kbq-icon-contrast);--kbq-tree-default-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-hover-container-background: var(--kbq-states-background-transparent-hover);--kbq-tree-states-active-container-background: var(--kbq-states-background-transparent-active);--kbq-tree-states-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-focused-focus-outline-color: var(--kbq-states-line-focus-theme);--kbq-tree-states-selected-container-background: var(--kbq-background-theme-less);--kbq-tree-multiple-states-selected-container-background: var(--kbq-background-contrast-less);--kbq-tree-states-selected-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-selected-hover-container-background: var(--kbq-states-background-theme-less-hover);--kbq-tree-states-selected-active-container-background: var(--kbq-states-background-theme-less-active);--kbq-tree-multiple-states-selected-hover-container-background: var(--kbq-states-background-contrast-less-hover);--kbq-tree-multiple-states-selected-active-container-background: var(--kbq-states-background-contrast-less-active);--kbq-tree-states-selected-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-disabled-container-background: transparent;--kbq-tree-states-disabled-text-color: var(--kbq-states-foreground-disabled);--kbq-tree-states-disabled-icon-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-tree-toggle-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-action-button-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-caption-color: var(--kbq-states-foreground-disabled)}\n"], dependencies: [{ kind: "directive", type: KbqTreeNodeOutlet, selector: "[kbqTreeNodeOutlet]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
1860
+ `, isInline: true, styles: [".kbq-tree{display:block}\n", ".kbq-tree,.kbq-tree-selection{--kbq-tree-size-indent-level: var(--kbq-size-xxl);--kbq-tree-size-container-padding-right: var(--kbq-size-s);--kbq-tree-size-container-padding-vertical: var(--kbq-size-xxs);--kbq-tree-size-container-content-gap-horizontal: var(--kbq-size-s);--kbq-tree-size-container-focus-outline-width: var(--kbq-size-3xs);--kbq-tree-size-text-padding-vertical: var(--kbq-size-3xs);--kbq-tree-option-border-radius: var(--kbq-size-border-radius);--kbq-tree-default-container-background: transparent;--kbq-tree-default-text-color: var(--kbq-foreground-contrast);--kbq-tree-default-icon-color: var(--kbq-icon-contrast);--kbq-tree-default-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-hover-container-background: var(--kbq-states-background-transparent-hover);--kbq-tree-states-active-container-background: var(--kbq-states-background-transparent-active);--kbq-tree-states-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-focused-focus-outline-color: var(--kbq-states-line-focus-theme);--kbq-tree-states-selected-container-background: var(--kbq-background-theme-less);--kbq-tree-multiple-states-selected-container-background: var(--kbq-background-contrast-less);--kbq-tree-states-selected-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-selected-hover-container-background: var(--kbq-states-background-theme-less-hover);--kbq-tree-states-selected-active-container-background: var(--kbq-states-background-theme-less-active);--kbq-tree-multiple-states-selected-hover-container-background: var(--kbq-states-background-contrast-less-hover);--kbq-tree-multiple-states-selected-active-container-background: var(--kbq-states-background-contrast-less-active);--kbq-tree-states-selected-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-disabled-container-background: transparent;--kbq-tree-states-disabled-text-color: var(--kbq-states-foreground-disabled);--kbq-tree-states-disabled-icon-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-tree-toggle-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-action-button-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-caption-color: var(--kbq-states-foreground-disabled)}\n"], dependencies: [{ kind: "directive", type: KbqTreeNodeOutlet, selector: "[kbqTreeNodeOutlet]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
1281
1861
  }
1282
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqTree, decorators: [{
1862
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqTree, decorators: [{
1283
1863
  type: Component,
1284
1864
  args: [{ selector: 'kbq-tree', imports: [
1285
1865
  KbqTreeNodeOutlet
1286
1866
  ], template: `
1287
1867
  <ng-container kbqTreeNodeOutlet />
1288
- `, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
1289
- class: 'kbq-tree'
1290
- }, exportAs: 'kbqTree', styles: [".kbq-tree{display:block}.kbq-tree-selection:focus{outline:none}.kbq-tree-option{--kbq-option-background: var(--kbq-tree-default-container-background);background:var(--kbq-tree-default-container-background)}.kbq-tree-option .kbq-option-text{color:var(--kbq-tree-default-text-color)}.kbq-tree-option .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-default-action-button-color)}.kbq-tree-option .kbq-option-caption{color:var(--kbq-tree-default-caption-color)}.kbq-tree-option:not(.kbq-disabled):hover,.kbq-tree-option:not(.kbq-disabled).kbq-hovered,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused{--kbq-option-background: var(--kbq-tree-states-hover-container-background);background:var(--kbq-tree-states-hover-container-background)}.kbq-tree-option:not(.kbq-disabled):hover .kbq-option-text,.kbq-tree-option:not(.kbq-disabled).kbq-hovered .kbq-option-text,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused .kbq-option-text{color:var(--kbq-tree-states-hover-text-color)}.kbq-tree-option:not(.kbq-disabled):hover .kbq-option-action .kbq-icon.kbq-empty,.kbq-tree-option:not(.kbq-disabled).kbq-hovered .kbq-option-action .kbq-icon.kbq-empty,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-hover-action-button-color)}.kbq-tree-option:not(.kbq-disabled):hover .kbq-option-caption,.kbq-tree-option:not(.kbq-disabled).kbq-hovered .kbq-option-caption,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused .kbq-option-caption{color:var(--kbq-tree-states-hover-caption-color)}.kbq-tree-option:not(.kbq-disabled):active,.kbq-tree-option:not(.kbq-disabled).kbq-active{--kbq-option-background: var(--kbq-tree-states-active-container-background);background:var(--kbq-tree-states-active-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-selected{--kbq-option-background: var(--kbq-tree-states-selected-container-background);background:var(--kbq-tree-states-selected-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-selected .kbq-option-text{color:var(--kbq-tree-states-selected-text-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-selected-action-button-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected .kbq-option-caption{color:var(--kbq-tree-states-selected-caption-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered{--kbq-option-background: var(--kbq-tree-states-selected-hover-container-background);background:var(--kbq-tree-states-selected-hover-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover .kbq-option-text,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered .kbq-option-text{color:var(--kbq-tree-states-selected-hover-text-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover .kbq-option-action .kbq-icon.kbq-empty,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-selected-hover-action-button-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover .kbq-option-caption,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered .kbq-option-caption{color:var(--kbq-tree-states-selected-hover-caption-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:active,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-active{--kbq-option-background: var(--kbq-tree-states-selected-active-container-background);background:var(--kbq-tree-states-selected-active-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected),.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected{--kbq-option-background: var(--kbq-tree-multiple-states-selected-container-background);background:var(--kbq-tree-multiple-states-selected-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected):hover,.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected).kbq-hovered,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected:hover,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected.kbq-hovered{--kbq-option-background: var(--kbq-tree-multiple-states-selected-hover-container-background);background:var(--kbq-tree-multiple-states-selected-hover-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected):active,.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected).kbq-active,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected:active,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected.kbq-active{--kbq-option-background: var(--kbq-tree-multiple-states-selected-active-container-background);background:var(--kbq-tree-multiple-states-selected-active-container-background)}.kbq-tree-option.kbq-disabled{--kbq-option-background: var(--kbq-tree-states-disabled-container-background);background:var(--kbq-tree-states-disabled-container-background)}.kbq-tree-option.kbq-disabled .kbq-option-text{color:var(--kbq-tree-states-disabled-text-color)}.kbq-tree-option.kbq-disabled .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-disabled-action-button-color)}.kbq-tree-option.kbq-disabled .kbq-option-caption{color:var(--kbq-tree-states-disabled-caption-color)}.kbq-tree-option.kbq-disabled .kbq-icon.kbq-empty:not(.kbq-tree-node-toggle .kbq-icon){color:var(--kbq-states-icon-disabled)}.kbq-tree-selection.cdk-keyboard-focused .kbq-tree-option.kbq-focused:not(.kbq-action-button-focused){border-color:var(--kbq-tree-states-focused-focus-outline-color)}.kbq-tree-option{font-size:var(--kbq-typography-text-normal-font-size);font-style:var(--kbq-typography-text-normal-font-style);font-weight:var(--kbq-typography-text-normal-font-weight);line-height:var(--kbq-typography-text-normal-line-height);font-family:var(--kbq-typography-text-normal-font-family);text-transform:var(--kbq-typography-text-normal-text-transform);font-feature-settings:var(--kbq-typography-text-normal-font-feature-settings);letter-spacing:var(--kbq-typography-text-normal-letter-spacing)}.kbq-option-caption{font-size:var(--kbq-typography-text-compact-font-size);font-style:var(--kbq-typography-text-compact-font-style);font-weight:var(--kbq-typography-text-compact-font-weight);line-height:var(--kbq-typography-text-compact-line-height);font-family:var(--kbq-typography-text-compact-font-family);text-transform:var(--kbq-typography-text-compact-text-transform);font-feature-settings:var(--kbq-typography-text-compact-font-feature-settings);letter-spacing:var(--kbq-typography-text-compact-letter-spacing)}\n", ".kbq-tree,.kbq-tree-selection{--kbq-tree-size-indent-level: var(--kbq-size-xxl);--kbq-tree-size-container-padding-right: var(--kbq-size-s);--kbq-tree-size-container-padding-vertical: var(--kbq-size-xxs);--kbq-tree-size-container-content-gap-horizontal: var(--kbq-size-s);--kbq-tree-size-container-content-gap-vertical: 0px;--kbq-tree-size-container-focus-outline-width: var(--kbq-size-3xs);--kbq-tree-size-text-padding-vertical: var(--kbq-size-3xs);--kbq-tree-option-border-radius: var(--kbq-size-border-radius);--kbq-tree-default-container-background: transparent;--kbq-tree-default-text-color: var(--kbq-foreground-contrast);--kbq-tree-default-icon-color: var(--kbq-icon-contrast);--kbq-tree-default-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-hover-container-background: var(--kbq-states-background-transparent-hover);--kbq-tree-states-active-container-background: var(--kbq-states-background-transparent-active);--kbq-tree-states-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-focused-focus-outline-color: var(--kbq-states-line-focus-theme);--kbq-tree-states-selected-container-background: var(--kbq-background-theme-less);--kbq-tree-multiple-states-selected-container-background: var(--kbq-background-contrast-less);--kbq-tree-states-selected-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-selected-hover-container-background: var(--kbq-states-background-theme-less-hover);--kbq-tree-states-selected-active-container-background: var(--kbq-states-background-theme-less-active);--kbq-tree-multiple-states-selected-hover-container-background: var(--kbq-states-background-contrast-less-hover);--kbq-tree-multiple-states-selected-active-container-background: var(--kbq-states-background-contrast-less-active);--kbq-tree-states-selected-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-disabled-container-background: transparent;--kbq-tree-states-disabled-text-color: var(--kbq-states-foreground-disabled);--kbq-tree-states-disabled-icon-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-tree-toggle-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-action-button-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-caption-color: var(--kbq-states-foreground-disabled)}\n"] }]
1868
+ `, providers: [{ provide: KbqTreeBase, useExisting: KbqTree }], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
1869
+ class: 'kbq-tree',
1870
+ role: 'tree'
1871
+ }, hostDirectives: [
1872
+ { directive: KbqStateSaving, inputs: ['useStateSaving', 'stateSavingKey'] }
1873
+ ], exportAs: 'kbqTree', styles: [".kbq-tree{display:block}\n", ".kbq-tree,.kbq-tree-selection{--kbq-tree-size-indent-level: var(--kbq-size-xxl);--kbq-tree-size-container-padding-right: var(--kbq-size-s);--kbq-tree-size-container-padding-vertical: var(--kbq-size-xxs);--kbq-tree-size-container-content-gap-horizontal: var(--kbq-size-s);--kbq-tree-size-container-focus-outline-width: var(--kbq-size-3xs);--kbq-tree-size-text-padding-vertical: var(--kbq-size-3xs);--kbq-tree-option-border-radius: var(--kbq-size-border-radius);--kbq-tree-default-container-background: transparent;--kbq-tree-default-text-color: var(--kbq-foreground-contrast);--kbq-tree-default-icon-color: var(--kbq-icon-contrast);--kbq-tree-default-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-hover-container-background: var(--kbq-states-background-transparent-hover);--kbq-tree-states-active-container-background: var(--kbq-states-background-transparent-active);--kbq-tree-states-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-focused-focus-outline-color: var(--kbq-states-line-focus-theme);--kbq-tree-states-selected-container-background: var(--kbq-background-theme-less);--kbq-tree-multiple-states-selected-container-background: var(--kbq-background-contrast-less);--kbq-tree-states-selected-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-selected-hover-container-background: var(--kbq-states-background-theme-less-hover);--kbq-tree-states-selected-active-container-background: var(--kbq-states-background-theme-less-active);--kbq-tree-multiple-states-selected-hover-container-background: var(--kbq-states-background-contrast-less-hover);--kbq-tree-multiple-states-selected-active-container-background: var(--kbq-states-background-contrast-less-active);--kbq-tree-states-selected-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-disabled-container-background: transparent;--kbq-tree-states-disabled-text-color: var(--kbq-states-foreground-disabled);--kbq-tree-states-disabled-icon-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-tree-toggle-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-action-button-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-caption-color: var(--kbq-states-foreground-disabled)}\n"] }]
1291
1874
  }] });
1292
1875
 
1293
1876
  const KBQ_SELECTION_TREE_VALUE_ACCESSOR = {
@@ -1295,6 +1878,8 @@ const KBQ_SELECTION_TREE_VALUE_ACCESSOR = {
1295
1878
  useExisting: forwardRef(() => KbqTreeSelection),
1296
1879
  multi: true
1297
1880
  };
1881
+ /** How long the key manager collects keystrokes before matching them against the option labels. */
1882
+ const typeAheadDebounce = 200;
1298
1883
  class KbqTreeSelectAllEvent {
1299
1884
  constructor(source, options) {
1300
1885
  this.source = source;
@@ -1330,30 +1915,95 @@ class KbqTreeSelectionChange {
1330
1915
  }
1331
1916
  }
1332
1917
  class KbqTreeSelection extends KbqTreeBase {
1333
- // TODO: Skipped for migration because:
1334
- // Accessor inputs cannot be migrated as they are too complex.
1918
+ /**
1919
+ * Accessible name written to the host.
1920
+ *
1921
+ * The host is the very element the consumer writes, and a host binding runs after their own
1922
+ * `[attr.aria-label]` binding on that element — an unset input reporting `null` would erase the name
1923
+ * they just set, because `[attr.]` never reaches the aliased input. Whatever is already on the
1924
+ * element therefore stands in for an unset input.
1925
+ */
1926
+ get resolvedAriaLabel() {
1927
+ return this.ariaLabel() || this.elementRef.nativeElement.getAttribute('aria-label');
1928
+ }
1929
+ /** Labelling element of the host. Falls back to the element's own attribute, see `resolvedAriaLabel`. */
1930
+ get resolvedAriaLabelledby() {
1931
+ return this.ariaLabelledby() || this.elementRef.nativeElement.getAttribute('aria-labelledby');
1932
+ }
1933
+ get unorderedOptions() {
1934
+ return this.unorderedOptionsList();
1935
+ }
1936
+ /**
1937
+ * Whether clicking a node clears the rest of the selection. Defaults to `true`, and to `false` for
1938
+ * `multiple="checkbox"`.
1939
+ *
1940
+ * Assigning it — from a template binding or imperatively, as `KbqTreeSelect` does — replaces the
1941
+ * derived default, so a later {@link multiple} change leaves the value alone.
1942
+ */
1335
1943
  get autoSelect() {
1336
- return this._autoSelect;
1944
+ return this.autoSelectState() ?? this.mode() !== MultipleMode.CHECKBOX;
1337
1945
  }
1338
1946
  set autoSelect(value) {
1339
- this._autoSelect = coerceBooleanProperty(value);
1947
+ this.autoSelectState.set(coerceBooleanProperty(value));
1340
1948
  }
1949
+ /** Emits when an option of the tree takes focus. */
1341
1950
  get optionFocusChanges() {
1342
- return merge(...this.renderedOptions.map((option) => option.onFocus));
1951
+ return this.optionFocusEvents.asObservable();
1343
1952
  }
1953
+ /** Emits when an option of the tree loses focus. */
1344
1954
  get optionBlurChanges() {
1345
- return merge(...this.renderedOptions.map((option) => option.onBlur));
1955
+ return this.optionBlurEvents.asObservable();
1346
1956
  }
1957
+ /**
1958
+ * Selection mode of the tree.
1959
+ *
1960
+ * `checkbox` renders a checkbox in every node, `keyboard` selects without one. A bare `multiple` and
1961
+ * `true` both mean `checkbox`; `single`, `false` and an absent attribute mean single selection. The mode
1962
+ * can be changed at any time — narrowing it to single selection keeps the first selected node and
1963
+ * reports the shortened value through the `ControlValueAccessor`.
1964
+ *
1965
+ * A tree rendered inside a `kbq-tree-select` shares its `SelectionModel` with the select, so the
1966
+ * select decides how many nodes may be selected: switching this input between single and multiple
1967
+ * selection there throws. Switching between `checkbox` and `keyboard` only changes the presentation
1968
+ * and is allowed.
1969
+ *
1970
+ * The getter reports whether more than one node can be selected; read {@link multipleMode} for the mode
1971
+ * itself.
1972
+ */
1347
1973
  get multiple() {
1348
- return !!this.multipleMode;
1974
+ return !!this.mode();
1349
1975
  }
1350
- // TODO: Skipped for migration because:
1351
- // Accessor inputs cannot be migrated as they are too complex.
1976
+ /** Resolved selection mode, or `null` when only one node can be selected. */
1977
+ get multipleMode() {
1978
+ return this.mode();
1979
+ }
1980
+ set multipleMode(value) {
1981
+ this.setMultipleMode(value);
1982
+ }
1983
+ /**
1984
+ * Whether the last selected node can be deselected.
1985
+ * Derived from the mode until assigned, like {@link autoSelect}.
1986
+ */
1352
1987
  get noUnselectLast() {
1353
- return this._noUnselectLast;
1988
+ return this.noUnselectLastState() ?? this.mode() !== MultipleMode.CHECKBOX;
1354
1989
  }
1355
1990
  set noUnselectLast(value) {
1356
- this._noUnselectLast = coerceBooleanProperty(value);
1991
+ this.noUnselectLastState.set(coerceBooleanProperty(value));
1992
+ }
1993
+ /**
1994
+ * Whether typing printable characters moves the focus to the next option whose label starts with
1995
+ * them. On by default.
1996
+ *
1997
+ * Turn it off wherever the tree shares its keystrokes with a text field: an embedder such as
1998
+ * `KbqTreeSelect` routes everything the user types — the search query included — into this key
1999
+ * manager, and type-ahead would move the active option out from under the query.
2000
+ */
2001
+ get typeAhead() {
2002
+ return this.typeAheadState();
2003
+ }
2004
+ // Written imperatively by `KbqTreeSelect`, like `autoSelect` and `noUnselectLast`.
2005
+ set typeAhead(value) {
2006
+ this.typeAheadState.set(value);
1357
2007
  }
1358
2008
  /**
1359
2009
  * Whether to render the "select all" master checkbox above the nodes. Multiple selection only.
@@ -1361,11 +2011,10 @@ class KbqTreeSelection extends KbqTreeBase {
1361
2011
  * Enabling it also makes Ctrl/Cmd + A a two-way toggle, so the shortcut and the checkbox never
1362
2012
  * disagree (`selectAllToggle` is implied).
1363
2013
  */
1364
- // Written imperatively by `KbqTreeSelect`, like `autoSelect` and `noUnselectLast`, so it cannot be a
1365
- // signal input; the signal behind it is what keeps the template in step.
1366
2014
  get selectAll() {
1367
2015
  return this.selectAllEnabled();
1368
2016
  }
2017
+ // Written imperatively by `KbqTreeSelect`, like `autoSelect` and `noUnselectLast`.
1369
2018
  set selectAll(value) {
1370
2019
  this.selectAllEnabled.set(value);
1371
2020
  }
@@ -1384,6 +2033,10 @@ class KbqTreeSelection extends KbqTreeBase {
1384
2033
  get selectAllState() {
1385
2034
  return getSelectAllState(this.selectAllAdapter);
1386
2035
  }
2036
+ /** Label of the "select all" row. Follows the active locale. */
2037
+ get selectAllText() {
2038
+ return this.localeConfiguration().selectAll;
2039
+ }
1387
2040
  /**
1388
2041
  * Data nodes "select all" acts on, and the ones its checkbox state is derived from.
1389
2042
  *
@@ -1391,27 +2044,24 @@ class KbqTreeSelection extends KbqTreeBase {
1391
2044
  * is looking at, and selecting them would contradict a master checkbox that can only report on what
1392
2045
  * is on screen. Without a filter the whole data set qualifies, collapsed branches included.
1393
2046
  */
1394
- // `any`, not `unknown`: `treeControl`/`selectionModel` are themselves `any`-typed data-node generics
1395
- // pre-dating this feature (`KbqTreeBase<any>`, `SelectionModel<SelectionModelOption>`), so `unknown`
1396
- // here would only relocate the unsafety into a cast at every call site, not remove it.
1397
2047
  get selectAllTargets() {
1398
- // `treeControl` is an `@Input`, so it is still unset on the change-detection pass that sets it:
2048
+ // `treeControl` is an input, so it is still unset on the change-detection pass that sets it:
1399
2049
  // a consumer reading `allOptionsSelected`/`selectAllState` off a template reference — which is
1400
2050
  // exactly how the docs suggest swapping the trigger label — would otherwise get a TypeError
1401
2051
  // before the tree is wired up. Nothing is selectable yet at that point, so an empty set is right.
1402
2052
  if (!this.treeControl) {
1403
2053
  return [];
1404
2054
  }
1405
- const nonSelectableDataNodes = this.renderedOptions
2055
+ const nonSelectableDataNodes = new Set(this.renderedOptions
1406
2056
  .filter((option) => option.disabled || !option.selectable())
1407
- .map((option) => option.data);
2057
+ .map((option) => option.data));
1408
2058
  const candidates = this.treeControl.filterValue.value?.length
1409
2059
  ? this.renderedOptions.map((option) => option.data)
1410
2060
  : (this.treeControl.dataNodes ?? []);
1411
- // The `includes` check comes first on purpose: the "select all" row is itself a non-selectable
2061
+ // The `has` check comes first on purpose: the "select all" row is itself a non-selectable
1412
2062
  // rendered option with no `data`, and `isDisabled` belongs to the consumer — it must never be
1413
2063
  // handed a node their data source has never seen.
1414
- return candidates.filter((node) => !nonSelectableDataNodes.includes(node) && !this.treeControl.isDisabled(node));
2064
+ return candidates.filter((node) => !nonSelectableDataNodes.has(node) && !this.treeControl.isDisabled(node));
1415
2065
  }
1416
2066
  /** Adapter shared by the master checkbox and the Ctrl/Cmd + A handler, so the two cannot drift apart. */
1417
2067
  get selectAllAdapter() {
@@ -1422,29 +2072,16 @@ class KbqTreeSelection extends KbqTreeBase {
1422
2072
  setSelected: (node, selected) => selected ? this.selectionModel.select(node) : this.selectionModel.deselect(node)
1423
2073
  };
1424
2074
  }
1425
- // TODO: Skipped for migration because:
1426
- // Accessor inputs cannot be migrated as they are too complex.
2075
+ /** Whether the tree is disabled, bound with `[disabled]` or set by a form control. */
1427
2076
  get disabled() {
1428
- return this._disabled;
2077
+ return this.disabledState();
1429
2078
  }
1430
- set disabled(rawValue) {
1431
- const value = coerceBooleanProperty(rawValue);
1432
- if (this._disabled !== value) {
1433
- this._disabled = value;
1434
- this.markOptionsForCheck();
1435
- }
1436
- }
1437
- // TODO: Skipped for migration because:
1438
- // Accessor inputs cannot be migrated as they are too complex.
2079
+ /** Tab index of the tree, `-1` while it is disabled. */
1439
2080
  get tabIndex() {
1440
- return this.disabled ? -1 : this._tabIndex;
1441
- }
1442
- set tabIndex(value) {
1443
- this._tabIndex = value;
1444
- this.userTabIndex = value;
2081
+ return this.disabled ? -1 : this.tabIndexState();
1445
2082
  }
1446
2083
  get showCheckbox() {
1447
- return this.multipleMode === MultipleMode.CHECKBOX;
2084
+ return this.mode() === MultipleMode.CHECKBOX;
1448
2085
  }
1449
2086
  get isEmpty() {
1450
2087
  return this.sortedNodes.length === 0;
@@ -1457,13 +2094,23 @@ class KbqTreeSelection extends KbqTreeBase {
1457
2094
  get nodesCount() {
1458
2095
  return this.sortedNodes.length;
1459
2096
  }
2097
+ /**
2098
+ * Whether the tree is changing the selection model itself — to a value the form wrote, or onto the nodes of
2099
+ * reloaded data — rather than acting on the user. A host sharing the model, such as `KbqTreeSelect`, reports
2100
+ * no such change.
2101
+ *
2102
+ * @docs-private
2103
+ */
2104
+ get syncingSelection() {
2105
+ return this.writingValue;
2106
+ }
1460
2107
  constructor() {
1461
- const multiple = inject(new HostAttributeToken('multiple'), { optional: true });
1462
2108
  super();
1463
2109
  this.elementRef = inject(ElementRef);
1464
2110
  this.scheduler = inject(AsyncScheduler);
1465
2111
  this.clipboard = inject(Clipboard, { optional: true });
1466
2112
  this.platform = inject(Platform);
2113
+ this.injector = inject(Injector);
1467
2114
  this.focusMonitor = inject(FocusMonitor);
1468
2115
  /**
1469
2116
  * Whether this tree-selection is rendered inside a select panel (enables option
@@ -1473,38 +2120,122 @@ class KbqTreeSelection extends KbqTreeBase {
1473
2120
  */
1474
2121
  this.inSelect = !!inject(KBQ_FORM_FIELD, { optional: true, host: true });
1475
2122
  this.renderedOptions = new QueryList();
2123
+ /**
2124
+ * Accessible name of the tree. Set it whenever the tree has no visible label of its own; a tree
2125
+ * embedded in a `kbq-tree-select` is labelled by the select instead.
2126
+ */
2127
+ this.ariaLabel = input(undefined, { ...(ngDevMode ? { debugName: "ariaLabel" } : /* istanbul ignore next */ {}), alias: 'aria-label' });
2128
+ /** Id of the element that labels the tree, for when the label is rendered next to it. */
2129
+ this.ariaLabelledby = input(undefined, { ...(ngDevMode ? { debugName: "ariaLabelledby" } : /* istanbul ignore next */ {}), alias: 'aria-labelledby' });
1476
2130
  this.resetFocusedItemOnBlur = true;
1477
- this.multipleMode = null;
1478
2131
  this.userTabIndex = null;
1479
2132
  // this parameter used when select has a search field
1480
2133
  this.optionShouldHoldFocusOnBlur = false;
2134
+ /**
2135
+ * Whether the tree acts on keyboard input itself. Turned off by an embedding host that owns the
2136
+ * keyboard, such as `KbqTreeSelect`.
2137
+ */
2138
+ this.ownsKeyboard = true;
1481
2139
  /** Reference to the built-in "select all" row, rendered only while `selectAll` is on. */
1482
- this.selectAllOption = viewChild(KbqTreeOption, ...(ngDevMode ? [{ debugName: "selectAllOption" }] : []));
2140
+ this.selectAllOption = viewChild(KbqTreeOption, ...(ngDevMode ? [{ debugName: "selectAllOption" }] : /* istanbul ignore next */ []));
2141
+ this.unorderedOptionsQuery = contentChildren(KbqTreeOption, ...(ngDevMode ? [{ debugName: "unorderedOptionsQuery" }] : /* istanbul ignore next */ []));
2142
+ this.unorderedOptionsList = kbqQueryListFrom(this.unorderedOptionsQuery);
1483
2143
  this.navigationChange = output();
2144
+ /**
2145
+ * Emits when the selection changes. A stream rather than an `output()`: `KbqTreeSelect` pipes it with rxjs.
2146
+ */
1484
2147
  this.selectionChange = new EventEmitter();
1485
- this.onSelectAll = output();
2148
+ /** @docs-private */
2149
+ this.selectionChangeOutput = outputFromObservable(this.selectionChange, { alias: 'selectionChange' });
2150
+ /** Emits after "select all" ran, with the options it could act on. */
2151
+ this.selectAllChange = output();
2152
+ /** @deprecated Use `selectAllChange` instead. Will be removed in 22.0.0. */
2153
+ this.onSelectAll = output({ alias: 'onSelectAll' });
2154
+ /**
2155
+ * Emits when the active option is copied with Ctrl/Cmd + C. Subscribing replaces the built-in
2156
+ * clipboard handler, so the event has to stay an `EventEmitter`: the decision is made by reading
2157
+ * `observed`, which `OutputEmitterRef` does not have. A template listener subscribes to it through
2158
+ * the output below.
2159
+ */
2160
+ this.copyChange = new EventEmitter();
2161
+ /** @docs-private */
2162
+ this.copyChangeOutput = outputFromObservable(this.copyChange, { alias: 'copyChange' });
2163
+ /** @deprecated Use `copyChange` instead. Will be removed in 22.0.0. */
1486
2164
  this.onCopy = new EventEmitter();
2165
+ /** @docs-private */
2166
+ this.onCopyOutput = outputFromObservable(this.onCopy, { alias: 'onCopy' });
1487
2167
  this.sortedNodes = [];
1488
2168
  this.lastSyncedDataNodes = null;
1489
- this._autoSelect = true;
1490
- this._noUnselectLast = true;
2169
+ /** @docs-private */
2170
+ this.autoSelectInput = input(undefined, { ...(ngDevMode ? { debugName: "autoSelectInput" } : /* istanbul ignore next */ {}), alias: 'autoSelect',
2171
+ transform: booleanAttribute });
2172
+ /** `undefined` while the value is derived from the mode. Written by `KbqTreeSelect` as well. */
2173
+ this.autoSelectState = linkedSignal(() => this.autoSelectInput(), ...(ngDevMode ? [{ debugName: "autoSelectState" }] : /* istanbul ignore next */ []));
2174
+ // Options report here, so a subscriber also hears the rows rendered after it subscribed.
2175
+ this.optionFocusEvents = new Subject();
2176
+ this.optionBlurEvents = new Subject();
2177
+ /** @docs-private */
2178
+ this.multipleInput = input(undefined, { ...(ngDevMode ? { debugName: "multipleInput" } : /* istanbul ignore next */ {}), alias: 'multiple' });
2179
+ /**
2180
+ * Backing signal of {@link multipleMode}. A signal rather than a field because the mode is also written
2181
+ * from inside the component and by `KbqTreeSelect`: options read it through `multiple` and
2182
+ * `showCheckbox`, and only a signal read re-runs their `OnPush` views and host bindings.
2183
+ */
2184
+ this.mode = signal(null, ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
2185
+ /** @docs-private */
2186
+ this.noUnselectLastInput = input(undefined, { ...(ngDevMode ? { debugName: "noUnselectLastInput" } : /* istanbul ignore next */ {}), alias: 'noUnselectLast',
2187
+ transform: booleanAttribute });
2188
+ /** `undefined` while the value is derived from the mode. Written by `KbqTreeSelect` as well. */
2189
+ this.noUnselectLastState = linkedSignal(() => this.noUnselectLastInput(), ...(ngDevMode ? [{ debugName: "noUnselectLastState" }] : /* istanbul ignore next */ []));
2190
+ /** @docs-private */
2191
+ this.typeAheadInput = input(true, { ...(ngDevMode ? { debugName: "typeAheadInput" } : /* istanbul ignore next */ {}), alias: 'typeAhead',
2192
+ transform: booleanAttribute });
2193
+ this.typeAheadState = linkedSignal(() => this.typeAheadInput(), ...(ngDevMode ? [{ debugName: "typeAheadState" }] : /* istanbul ignore next */ []));
1491
2194
  /** When `true`, a repeated Ctrl/Cmd+A deselects all options. Off by default (Ctrl+A only selects). */
1492
- this.selectAllToggle = input(false, ...(ngDevMode ? [{ debugName: "selectAllToggle", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
1493
- this.selectAllEnabled = signal(false, ...(ngDevMode ? [{ debugName: "selectAllEnabled" }] : []));
1494
- /** Label of the "select all" row. Kept in step with the locale service. */
1495
- this.selectAllText = ruRULocaleData.select.selectAll;
1496
- this._disabled = false;
1497
- this._tabIndex = 0;
1498
- this.localeService = inject(KBQ_LOCALE_SERVICE, { optional: true });
1499
- /** Updates locale parameters from the locale service. */
1500
- this.updateLocaleParams = () => {
1501
- // Locale data registered by a consumer through `KBQ_LOCALE_DATA`/`addLocale` may predate this key.
1502
- this.selectAllText = this.localeService?.getParams('select')?.selectAll ?? ruRULocaleData.select.selectAll;
1503
- this.changeDetectorRef.markForCheck();
1504
- };
1505
- /** `View -> model callback called when value changes` */
2195
+ this.selectAllToggle = input(false, { ...(ngDevMode ? { debugName: "selectAllToggle" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
2196
+ /** @docs-private */
2197
+ this.selectAllInput = input(false, { ...(ngDevMode ? { debugName: "selectAllInput" } : /* istanbul ignore next */ {}), alias: 'selectAll',
2198
+ transform: booleanAttribute });
2199
+ this.selectAllEnabled = linkedSignal(() => this.selectAllInput(), ...(ngDevMode ? [{ debugName: "selectAllEnabled" }] : /* istanbul ignore next */ []));
2200
+ this.localeConfiguration = inject(KbqLocaleOverridesDirective, { self: true }).read('select', KBQ_SELECT_LOCALE_CONFIGURATION);
2201
+ /** @docs-private */
2202
+ this.disabledInput = input(undefined, { ...(ngDevMode ? { debugName: "disabledInput" } : /* istanbul ignore next */ {}), alias: 'disabled',
2203
+ transform: booleanAttribute });
2204
+ this.disabledState = signal(false, ...(ngDevMode ? [{ debugName: "disabledState" }] : /* istanbul ignore next */ []));
2205
+ /** @docs-private */
2206
+ this.tabIndexInput = input(undefined, { ...(ngDevMode ? { debugName: "tabIndexInput" } : /* istanbul ignore next */ {}), alias: 'tabIndex',
2207
+ transform: kbqOptionalNumberAttribute });
2208
+ this.tabIndexState = signal(0, ...(ngDevMode ? [{ debugName: "tabIndexState" }] : /* istanbul ignore next */ []));
2209
+ this.selectionModelSubscription = null;
2210
+ // A selection change asks for a sweep here, not through `renderedOptions.changes`: the key manager and an
2211
+ // embedding select listen to that, and no row changed.
2212
+ this.selectionSweeps = new Subject();
2213
+ /** Whether a value report is queued for the end of the current tick. Cleared by `writeValue` to cancel it. */
2214
+ this.pendingValueReport = false;
2215
+ /** Backs {@link syncingSelection}: a change of the selection made by code is no change to report back. */
2216
+ this.writingValue = false;
2217
+ /**
2218
+ * The last value the form wrote while some of the nodes it names were not in the data yet. Applied again as the
2219
+ * data changes, until every node is found or the selection is reported to the form.
2220
+ */
2221
+ this.unresolvedValue = null;
2222
+ this.destroyed = false;
2223
+ /** `treeControl.dataNodes` the options' checkbox states were last recomputed against. */
2224
+ this.checkboxSyncedDataNodes = null;
2225
+ /** @docs-private */
2226
+ this.selectAllHandlerInput = input(undefined, { ...(ngDevMode ? { debugName: "selectAllHandlerInput" } : /* istanbul ignore next */ {}), alias: 'selectAllHandler',
2227
+ transform: kbqSelectAllHandlerTransform });
2228
+ /**
2229
+ * Called when the value changes. Needed to properly implement `ControlValueAccessor`.
2230
+ *
2231
+ * @docs-private
2232
+ */
1506
2233
  this.onChange = () => { };
1507
- /** `View -> model callback called when select has been touched` */
2234
+ /**
2235
+ * Called when the control is blurred. Needed to properly implement `ControlValueAccessor`.
2236
+ *
2237
+ * @docs-private
2238
+ */
1508
2239
  this.onTouched = () => { };
1509
2240
  this.updateRenderedOptions = () => {
1510
2241
  const orderedOptions = [];
@@ -1515,8 +2246,19 @@ class KbqTreeSelection extends KbqTreeBase {
1515
2246
  if (selectAllOption) {
1516
2247
  orderedOptions.push(selectAllOption);
1517
2248
  }
2249
+ // Indexed once per render, as a search per node is quadratic in the rows. The first option wins in both maps.
2250
+ const optionsByNode = new Map();
2251
+ const optionsByValue = new Map();
2252
+ this.unorderedOptions.forEach((option) => {
2253
+ if (!optionsByNode.has(option.data))
2254
+ optionsByNode.set(option.data, option);
2255
+ if (!optionsByValue.has(option.value))
2256
+ optionsByValue.set(option.value, option);
2257
+ });
1518
2258
  this.sortedNodes.forEach((node) => {
1519
- const found = this.unorderedOptions.find((option) => option.value === this.treeControl.getValue(node));
2259
+ // By node first: nodes do not have to carry distinct values, and a value match would hand every node with
2260
+ // the same value the first option holding it.
2261
+ const found = optionsByNode.get(node) ?? optionsByValue.get(this.treeControl.getValue(node));
1520
2262
  if (found) {
1521
2263
  orderedOptions.push(found);
1522
2264
  }
@@ -1525,24 +2267,45 @@ class KbqTreeSelection extends KbqTreeBase {
1525
2267
  this.renderedOptions.notifyOnChanges();
1526
2268
  this.updateScrollSize();
1527
2269
  };
1528
- if (multiple === MultipleMode.CHECKBOX || multiple === MultipleMode.KEYBOARD) {
1529
- this.multipleMode = multiple;
1530
- }
1531
- else if (multiple !== null) {
1532
- this.multipleMode = MultipleMode.CHECKBOX;
1533
- }
1534
- if (this.multipleMode === MultipleMode.CHECKBOX) {
1535
- this.autoSelect = false;
1536
- this.noUnselectLast = false;
1537
- }
1538
- this.selectionModel = new SelectionModel(this.multiple);
1539
- this.localeService?.changes.pipe(takeUntilDestroyed()).subscribe(this.updateLocaleParams);
2270
+ this.destroyRef.onDestroy(() => (this.destroyed = true));
2271
+ // Single selection until the `multiple` input says otherwise. A model has to exist this early
2272
+ // because `KbqTreeOption.setSelected` refuses to touch the selection without one, and a static
2273
+ // `multiple` attribute reaches the input right after the constructor, before any node exists.
2274
+ this.selectionModel = this.ownSelectionModel = new SelectionModel(false);
2275
+ effect(() => {
2276
+ this.multipleInput();
2277
+ untracked(() => this.applyMultipleInput());
2278
+ });
2279
+ effect(() => {
2280
+ this.disabledInput();
2281
+ untracked(() => this.applyDisabledInput());
2282
+ });
2283
+ // Unbound, the input leaves the default, which follows the rendered options; bound back to `undefined` or
2284
+ // `null`, it restores that default.
2285
+ effect(() => {
2286
+ const tabIndex = this.tabIndexInput();
2287
+ untracked(() => {
2288
+ if (tabIndex !== undefined) {
2289
+ this.userTabIndex = tabIndex;
2290
+ this.tabIndexState.set(tabIndex);
2291
+ }
2292
+ else if (this.userTabIndex !== null) {
2293
+ this.userTabIndex = null;
2294
+ this.updateTabIndex();
2295
+ }
2296
+ });
2297
+ });
2298
+ effect(() => {
2299
+ this.typeAheadState();
2300
+ untracked(() => this.applyTypeAhead());
2301
+ });
1540
2302
  // `unorderedOptions.changes` never fires for the "select all" row — it is a view child — so the
1541
2303
  // rendered list has to be rebuilt whenever the view query resolves or drops it.
1542
2304
  effect(() => {
1543
2305
  this.selectAllOption();
1544
2306
  if (this.renderedOptions) {
1545
- this.updateRenderedOptions();
2307
+ // Untracked: the options are read too, and their changes come through `unorderedOptions.changes`.
2308
+ untracked(() => this.updateRenderedOptions());
1546
2309
  }
1547
2310
  });
1548
2311
  }
@@ -1550,14 +2313,144 @@ class KbqTreeSelection extends KbqTreeBase {
1550
2313
  toggleSelectAll() {
1551
2314
  this.selectAllOptions(true);
1552
2315
  }
2316
+ /**
2317
+ * Sets the mode from the `multiple` binding, once per bound value: an unbound input leaves what
2318
+ * `KbqTreeSelect` or the {@link multipleMode} setter wrote, and a value bound back to `undefined` means
2319
+ * single selection.
2320
+ *
2321
+ * Called by an effect, and by `writeValue` ahead of it: a forms directive on this element writes the
2322
+ * value from its own `ngOnChanges`, which runs before any effect of the view.
2323
+ */
2324
+ applyMultipleInput() {
2325
+ const multiple = this.multipleInput();
2326
+ if (multiple === this.appliedMultipleInput)
2327
+ return;
2328
+ this.appliedMultipleInput = multiple;
2329
+ this.setMultipleMode(resolveMultipleMode(multiple));
2330
+ }
2331
+ /**
2332
+ * Sets the disabled state from the `disabled` binding, once per bound value, so that whichever of the binding
2333
+ * and the form control changed last wins. An unbound input leaves what the form control wrote.
2334
+ *
2335
+ * Called by an effect, and by `setDisabledState` ahead of it: a forms directive on this element calls that
2336
+ * from its own `ngOnChanges`, after the binding is set but before any effect of the view runs.
2337
+ */
2338
+ applyDisabledInput() {
2339
+ const disabled = this.disabledInput();
2340
+ if (disabled === this.appliedDisabledInput)
2341
+ return;
2342
+ this.appliedDisabledInput = disabled;
2343
+ this.disabledState.set(!!disabled);
2344
+ }
2345
+ /**
2346
+ * Applies a new selection mode, rebuilding the `SelectionModel` when the multiplicity itself changes —
2347
+ * CDK freezes that flag at construction, so the model has to be replaced rather than reconfigured.
2348
+ */
2349
+ setMultipleMode(next) {
2350
+ if (next === this.mode()) {
2351
+ return;
2352
+ }
2353
+ const rebuildNeeded = this.selectionModel.isMultipleSelection() !== !!next;
2354
+ // `KbqTreeSelect` hands the tree its own model and subscribes to it as well, so the multiplicity is
2355
+ // the select's to decide; replacing a model we do not own would drop those subscriptions. Thrown
2356
+ // rather than ignored: Angular caches the bound value either way, so a silently dropped write
2357
+ // leaves the binding and the tree permanently out of step with no way to retry.
2358
+ if (rebuildNeeded && this.selectionModel !== this.ownSelectionModel) {
2359
+ throw getKbqTreeSelectionOwnedMultipleError();
2360
+ }
2361
+ this.mode.set(next);
2362
+ // While the checkbox is hidden, the options leave its state as it was.
2363
+ if (next === MultipleMode.CHECKBOX)
2364
+ this.scheduleCheckboxSync(true);
2365
+ if (rebuildNeeded) {
2366
+ this.rebuildSelectionModel(!!next);
2367
+ }
2368
+ }
2369
+ /** Replaces the `SelectionModel` with one of the given multiplicity, keeping what the new one can hold. */
2370
+ rebuildSelectionModel(multiple) {
2371
+ // Copied because CDK hands back its own cached array.
2372
+ const selected = [...this.selectionModel.selected];
2373
+ // Narrowing keeps one node: the first selected one in render order, falling back to the model's own
2374
+ // order when every selected node sits inside a collapsed branch and is therefore not rendered.
2375
+ // Asked of the model rather than of the option, whose mirror is only re-synced a macrotask later.
2376
+ const rendered = this.renderedOptions?.find((option) => this.selectionModel.isSelected(option.data))?.data;
2377
+ const kept = multiple ? selected : selected.slice(0, 1);
2378
+ if (!multiple && rendered !== undefined && selected.includes(rendered)) {
2379
+ kept[0] = rendered;
2380
+ }
2381
+ const dropped = selected.filter((node) => !kept.includes(node));
2382
+ const droppedOptions = (this.renderedOptions?.toArray() ?? []).filter((option) => dropped.includes(option.data));
2383
+ // `initiallySelectedValues` seeds the model without emitting.
2384
+ this.selectionModel = this.ownSelectionModel = new SelectionModel(multiple, kept);
2385
+ this.bindSelectionModel();
2386
+ // Reconciles both directions against the model that is actually in use now, so no node is left
2387
+ // painted by a stale mirror — a node whose option was created while it was already selected has
2388
+ // one, and so does every node the narrowing just dropped.
2389
+ this.renderedOptions?.forEach((option) => option.setSelected(this.selectionModel.isSelected(option.data)));
2390
+ if (droppedOptions.length) {
2391
+ // The nodes lost their selection without going through the model, so nothing else would
2392
+ // announce it.
2393
+ this.selectionChange.emit(new KbqTreeSelectionChange(this, droppedOptions[0], droppedOptions));
2394
+ }
2395
+ // Reported on every multiplicity change, not only when the selection shrank: `getSelectedValues`
2396
+ // returns a bare value in single selection and an array in multiple, so widening changes the shape
2397
+ // the form control has to hold even though nothing was dropped.
2398
+ this.scheduleValueReport();
2399
+ }
2400
+ /**
2401
+ * Reports the value once the current change-detection pass is over: a bound `[multiple]` is written
2402
+ * during change detection, and reporting straight back to the form control there would raise
2403
+ * "Expression has changed after it was checked". Coalesced so that several mode changes in one tick
2404
+ * produce one notification, and dropped if the form writes a value or the tree is gone by the time it runs.
2405
+ */
2406
+ scheduleValueReport() {
2407
+ if (this.pendingValueReport) {
2408
+ return;
2409
+ }
2410
+ this.pendingValueReport = true;
2411
+ Promise.resolve().then(() => {
2412
+ if (!this.pendingValueReport)
2413
+ return;
2414
+ this.pendingValueReport = false;
2415
+ if (!this.destroyed) {
2416
+ this.reportValue();
2417
+ }
2418
+ });
2419
+ }
2420
+ /** Reports the selection to the form, which then holds it instead of a value still waiting for its nodes. */
2421
+ reportValue() {
2422
+ this.unresolvedValue = null;
2423
+ this.onChange(this.getSelectedValues());
2424
+ }
2425
+ /** (Re)points the change subscription at the current {@link selectionModel}. */
2426
+ bindSelectionModel() {
2427
+ this.selectionModelSubscription?.unsubscribe();
2428
+ this.selectionModelSubscription = this.selectionModel.changed
2429
+ .pipe(takeUntilDestroyed(this.destroyRef))
2430
+ .subscribe(() => {
2431
+ if (!this.writingValue) {
2432
+ this.reportValue();
2433
+ }
2434
+ this.selectionSweeps.next();
2435
+ // The "select all" row renders the selection state.
2436
+ this.changeDetectorRef.markForCheck();
2437
+ });
2438
+ }
1553
2439
  ngAfterContentInit() {
2440
+ super.ngAfterContentInit();
1554
2441
  if (this.platform.isBrowser) {
1555
- this.unorderedOptions.changes.subscribe(this.updateRenderedOptions);
2442
+ this.unorderedOptions.changes
2443
+ .pipe(takeUntilDestroyed(this.destroyRef))
2444
+ .subscribe(this.updateRenderedOptions);
1556
2445
  }
1557
2446
  this.keyManager = new FocusKeyManager(this.renderedOptions)
1558
2447
  .withVerticalOrientation(true)
1559
2448
  .withHorizontalOrientation(null);
2449
+ this.applyTypeAhead();
1560
2450
  this.keyManager.change.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {
2451
+ // `aria-activedescendant` is bound to the active option, and nothing else in this view
2452
+ // changes when the key manager moves.
2453
+ this.changeDetectorRef.markForCheck();
1561
2454
  if (this.keyManager.activeItem) {
1562
2455
  this.emitNavigationEvent(this.keyManager.activeItem);
1563
2456
  // todo need check this logic
@@ -1566,21 +2459,22 @@ class KbqTreeSelection extends KbqTreeBase {
1566
2459
  }
1567
2460
  }
1568
2461
  });
1569
- this.keyManager.tabOut.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => this.allowFocusEscape());
1570
- this.selectionModel.changed.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {
1571
- this.onChange(this.getSelectedValues());
1572
- this.renderedOptions.notifyOnChanges();
1573
- });
1574
- this.renderedOptions.changes
1575
- .pipe(delay(0, this.scheduler), takeUntilDestroyed(this.destroyRef))
1576
- .subscribe((options) => {
1577
- this.resetOptions();
2462
+ kbqLeaveTabOrderOnTabOut(this.keyManager.tabOut, this.elementRef.nativeElement, () => this.tabIndex, this.destroyRef);
2463
+ this.bindSelectionModel();
2464
+ this.listenToOptionsFocus();
2465
+ // A render and the selection changes of one task each notify, each with its own timer: the first to fire sweeps
2466
+ // for all of them and the rest are dropped. `auditTime` would tie the later ones to the first one's timer.
2467
+ let sweeps = 0;
2468
+ merge(this.renderedOptions.changes, this.selectionSweeps)
2469
+ .pipe(map(() => sweeps), delay(0, this.scheduler), filter((sweepsWhenNotified) => sweepsWhenNotified === sweeps), takeUntilDestroyed(this.destroyRef))
2470
+ .subscribe(() => {
2471
+ sweeps++;
1578
2472
  // Check to see if we need to update our tab index
1579
2473
  this.updateTabIndex();
1580
2474
  this.syncSelectionModelToDataNodes();
1581
- const selectedValues = this.multiple ? this.getSelectedValues() : [this.getSelectedValues()];
1582
- options.forEach((option) => {
1583
- if (selectedValues.includes(option.value)) {
2475
+ this.renderedOptions.forEach((option) => {
2476
+ // By node rather than by value: rows may share a value.
2477
+ if (this.selectionModel.isSelected(option.data)) {
1584
2478
  option.select(false);
1585
2479
  }
1586
2480
  else {
@@ -1590,11 +2484,39 @@ class KbqTreeSelection extends KbqTreeBase {
1590
2484
  });
1591
2485
  });
1592
2486
  }
2487
+ /**
2488
+ * Rebuilds the tree around a selection model owned by an embedding host, such as `KbqTreeSelect`.
2489
+ *
2490
+ * The host has to take the model over before the tree starts reacting to it, and re-running
2491
+ * `ngAfterContentInit()` is not a way to do that: neither `unorderedOptions` nor `renderedOptions` is
2492
+ * ever re-created, so a second run would only leave a second set of subscribers on both — every options
2493
+ * change handled twice, and the whole option sweep run twice per emission. Only the subscription that
2494
+ * depends on the model has to move, which is exactly what `bindSelectionModel` does.
2495
+ */
2496
+ initializeForEmbedding(selectionModel) {
2497
+ this.selectionModel = selectionModel;
2498
+ this.bindSelectionModel();
2499
+ }
2500
+ ngAfterContentChecked() {
2501
+ // Syncs the list here so `changes` emits after the projected items are bound and before the host bindings.
2502
+ this.unorderedOptionsList();
2503
+ super.ngAfterContentChecked();
2504
+ }
1593
2505
  ngAfterViewInit() {
1594
- this.focusMonitor.monitor(this.elementRef, true);
2506
+ // Reports the focus leaving only when it lands outside the tree (or nowhere): the host hands it to an option
2507
+ // on entry, and options hand it on to each other or to their action buttons, none of which blurs the tree.
2508
+ this.focusMonitor
2509
+ .monitor(this.elementRef, true)
2510
+ .pipe(takeUntilDestroyed(this.destroyRef))
2511
+ .subscribe((origin) => {
2512
+ if (!origin)
2513
+ this.blur();
2514
+ });
1595
2515
  }
1596
2516
  ngOnDestroy() {
1597
2517
  super.ngOnDestroy();
2518
+ this.optionFocusEvents.complete();
2519
+ this.optionBlurEvents.complete();
1598
2520
  this.focusMonitor.stopMonitoring(this.elementRef);
1599
2521
  }
1600
2522
  focus($event) {
@@ -1610,17 +2532,45 @@ class KbqTreeSelection extends KbqTreeBase {
1610
2532
  }
1611
2533
  this.keyManager.setFocusOrigin('program');
1612
2534
  }
2535
+ /** @docs-private */
1613
2536
  highlightSelectedOption() {
1614
- this.renderedOptions.find((item) => item.data === this.selectionModel.selected[0])?.focus();
2537
+ untracked(() => {
2538
+ // The selection can hold nodes that are not rendered — collapsed branches, or references left
2539
+ // over from a data replacement. Falling back keeps `focus()` from ending with nothing focused
2540
+ // at all, since it already took the branch that skips `setFirstItemActive`.
2541
+ const target = this.renderedOptions.find((item) => item.data === this.selectionModel.selected[0]) ??
2542
+ this.keyManager.activeItem;
2543
+ if (target) {
2544
+ target.focus();
2545
+ }
2546
+ else {
2547
+ this.keyManager.setFirstItemActive();
2548
+ }
2549
+ });
1615
2550
  }
1616
2551
  blur() {
1617
- if (!this.hasFocusedOption() && this.resetFocusedItemOnBlur) {
1618
- this.keyManager.setActiveItem(-1);
1619
- }
1620
- this.onTouched();
1621
- this.changeDetectorRef.markForCheck();
2552
+ untracked(() => {
2553
+ if (!this.hasFocusedOption() && this.resetFocusedItemOnBlur) {
2554
+ this.keyManager.setActiveItem(-1);
2555
+ }
2556
+ this.onTouched();
2557
+ this.changeDetectorRef.markForCheck();
2558
+ });
1622
2559
  }
2560
+ /**
2561
+ * Host listener for keyboard input.
2562
+ *
2563
+ * Does nothing while an embedding host owns the keyboard — `KbqTreeSelect` routes every key through
2564
+ * its own panel handler and calls back into `handleKeydown` for the parts it delegates, so without
2565
+ * this guard the same event would be acted on twice.
2566
+ */
1623
2567
  onKeyDown(event) {
2568
+ if (!this.ownsKeyboard)
2569
+ return;
2570
+ this.handleKeydown(event);
2571
+ }
2572
+ /** Runs the tree's own keyboard handling, whether or not it owns the keyboard. */
2573
+ handleKeydown(event) {
1624
2574
  this.keyManager.setFocusOrigin('keyboard');
1625
2575
  const keyCode = event.keyCode;
1626
2576
  if ([SPACE, LEFT_ARROW, RIGHT_ARROW].includes(keyCode) || isVerticalMovement(event)) {
@@ -1642,14 +2592,22 @@ class KbqTreeSelection extends KbqTreeBase {
1642
2592
  const activeItem = this.keyManager.activeItem;
1643
2593
  if (activeItem.isExpandable && activeItem.isExpanded) {
1644
2594
  this.treeControl.collapse(activeItem.data);
2595
+ this.saveState();
1645
2596
  }
1646
2597
  else {
1647
2598
  this.setActiveParentOption(activeItem);
1648
2599
  }
1649
2600
  return;
1650
2601
  }
1651
- else if (keyCode === RIGHT_ARROW && this.keyManager.activeItem?.isExpandable) {
1652
- this.treeControl.expand(this.keyManager.activeItem.data);
2602
+ else if (keyCode === RIGHT_ARROW && this.keyManager.activeItem) {
2603
+ const activeItem = this.keyManager.activeItem;
2604
+ if (activeItem.isExpandable && !activeItem.isExpanded) {
2605
+ this.treeControl.expand(activeItem.data);
2606
+ this.saveState();
2607
+ }
2608
+ else if (activeItem.isExpandable) {
2609
+ this.setActiveFirstChildOption(activeItem);
2610
+ }
1653
2611
  return;
1654
2612
  }
1655
2613
  else if (keyCode === DOWN_ARROW) {
@@ -1674,12 +2632,26 @@ class KbqTreeSelection extends KbqTreeBase {
1674
2632
  else if (keyCode === PAGE_DOWN) {
1675
2633
  this.keyManager.setNextPageItemActive();
1676
2634
  }
2635
+ else {
2636
+ // Whatever is left is either a printable character, which the key manager turns into a
2637
+ // type-ahead query, or a key nothing here reacts to. Every key handled above returns or is
2638
+ // matched before this point, so the manager only ever sees the leftovers.
2639
+ //
2640
+ // Ctrl/Cmd/Alt combinations are the application's shortcuts, not text: the key manager feeds
2641
+ // its letter stream from the `default` branch without a modifier guard of its own, so Ctrl+S
2642
+ // would otherwise type-ahead to the first option starting with "S" and move focus there.
2643
+ if (!hasModifierKey(event, 'ctrlKey', 'metaKey', 'altKey')) {
2644
+ this.keyManager.onKeydown(event);
2645
+ }
2646
+ return;
2647
+ }
1677
2648
  if (this.keyManager.activeItem && isVerticalMovement(event)) {
1678
2649
  this.setSelectedOptionsByKey(this.keyManager.activeItem, hasModifierKey(event, 'shiftKey'),
1679
2650
  // ctrlKey is for Windows, metaKey is for MacOS
1680
2651
  hasModifierKey(event, 'ctrlKey', 'metaKey'));
1681
2652
  }
1682
2653
  }
2654
+ /** @docs-private */
1683
2655
  updateScrollSize() {
1684
2656
  if (!this.renderedOptions.first) {
1685
2657
  return;
@@ -1692,6 +2664,7 @@ class KbqTreeSelection extends KbqTreeBase {
1692
2664
  }
1693
2665
  this.keyManager.withScrollSize(Math.floor(this.getHeight() / optionHeight));
1694
2666
  }
2667
+ /** @docs-private */
1695
2668
  setSelectedOptionsByKey(option, shiftKey, ctrlKey) {
1696
2669
  if (shiftKey && this.multiple) {
1697
2670
  this.selectActiveOptions();
@@ -1708,6 +2681,15 @@ class KbqTreeSelection extends KbqTreeBase {
1708
2681
  this.emitChangeEvent(option);
1709
2682
  }
1710
2683
  }
2684
+ /** @docs-private */
2685
+ reportOptionFocus(event) {
2686
+ this.optionFocusEvents.next(event);
2687
+ }
2688
+ /** @docs-private */
2689
+ reportOptionBlur(event) {
2690
+ this.optionBlurEvents.next(event);
2691
+ }
2692
+ /** @docs-private */
1711
2693
  setSelectedOptionsByClick(option, shiftKey, ctrlKey) {
1712
2694
  if (option.disabled || !option.selectable()) {
1713
2695
  return;
@@ -1734,11 +2716,13 @@ class KbqTreeSelection extends KbqTreeBase {
1734
2716
  }
1735
2717
  this.emitChangeEvent(option);
1736
2718
  }
2719
+ /** @docs-private */
1737
2720
  selectActiveOptions() {
1738
2721
  const options = this.renderedOptions.toArray();
1739
2722
  let fromIndex = this.keyManager.previousActiveItemIndex;
1740
2723
  let toIndex = (this.keyManager.previousActiveItemIndex = this.keyManager.activeItemIndex);
1741
- const selectedOptionState = options[fromIndex]?.selected;
2724
+ // Asked of the model: an option's own state lags it until the next sweep.
2725
+ const selectedOptionState = this.selectionModel.isSelected(options[fromIndex]?.data);
1742
2726
  if (toIndex === fromIndex || fromIndex === -1) {
1743
2727
  if (options[toIndex]?.selectable()) {
1744
2728
  options[toIndex].toggle();
@@ -1748,19 +2732,23 @@ class KbqTreeSelection extends KbqTreeBase {
1748
2732
  if (fromIndex > toIndex) {
1749
2733
  [fromIndex, toIndex] = [toIndex, fromIndex];
1750
2734
  }
1751
- options
2735
+ const nodes = options
1752
2736
  .slice(fromIndex, toIndex + 1)
1753
2737
  .filter((item) => !item.disabled && item.selectable())
1754
- .forEach((renderedOption) => {
1755
- if (!selectedOptionState && this.noUnselectLast && this.selectionModel.selected.length === 1) {
1756
- return;
1757
- }
1758
- renderedOption.setSelected(selectedOptionState);
1759
- });
1760
- }
1761
- setFocusedOption(option) {
1762
- this.keyManager.setActiveItem(option);
2738
+ .map((item) => item.data);
2739
+ // One write for the range, so the selection changes once rather than once per row.
2740
+ if (selectedOptionState) {
2741
+ this.selectionModel.select(...nodes);
2742
+ return;
2743
+ }
2744
+ const selected = nodes.filter((node) => this.selectionModel.isSelected(node));
2745
+ // With `noUnselectLast` the last selected node stays, the range giving up its own in order until then.
2746
+ const released = this.noUnselectLast
2747
+ ? Math.max(0, Math.min(selected.length, this.selectionModel.selected.length - 1))
2748
+ : selected.length;
2749
+ this.selectionModel.deselect(...selected.slice(0, released));
1763
2750
  }
2751
+ /** @docs-private */
1764
2752
  toggleFocusedOption() {
1765
2753
  const focusedOption = this.keyManager.activeItem;
1766
2754
  // The row is not selectable, so nothing below would act on it. Handling it here covers both focus
@@ -1776,14 +2764,51 @@ class KbqTreeSelection extends KbqTreeBase {
1776
2764
  this.emitChangeEvent(focusedOption);
1777
2765
  }
1778
2766
  }
2767
+ /** @docs-private */
1779
2768
  renderNodeChanges(data, dataDiffer = this.dataDiffer, viewContainer = this.nodeOutlet.viewContainer, parentData) {
1780
- super.renderNodeChanges(data, dataDiffer, viewContainer, parentData);
2769
+ // Not `super.renderNodeChanges`: that would run change detection over this very view before
2770
+ // `sortedNodes` is refreshed, so the "select all" row — which is rendered off `isEmpty` — would
2771
+ // need a second pass to catch up. One pass, after the state its template reads is current.
2772
+ const changed = this.applyNodeChanges(data, dataDiffer, viewContainer, parentData);
1781
2773
  this.sortedNodes = this.getSortedNodes(viewContainer);
1782
- this.nodeOutlet.changeDetectorRef.detectChanges();
2774
+ this.changeDetectorRef.detectChanges();
2775
+ // The options query lists the options in the order their views were created, not in the order of the rows, so
2776
+ // rows that only moved (reused through `trackBy`) never make it emit.
2777
+ if (changed && this.renderedOptionsOutOfOrder())
2778
+ this.updateRenderedOptions();
2779
+ this.scheduleCheckboxSync(false);
2780
+ // The "select all" row is rendered ahead of what its state reads: new rows bind their inputs after it and join
2781
+ // `renderedOptions` only once bound, and a consumer's data source can assign `dataNodes` after it emits.
2782
+ // Nothing else in the tree reads that state but the checkbox sync above, so a tree without the row is done in
2783
+ // this one pass. Marked for check, which reaches the views above too: a template reading `allOptionsSelected`
2784
+ // by reference reads the same state.
2785
+ if (!this.showSelectAll)
2786
+ return;
2787
+ const dataNodes = this.treeControl.dataNodes;
2788
+ afterNextRender(() => {
2789
+ if (changed || this.treeControl.dataNodes !== dataNodes)
2790
+ this.changeDetectorRef.markForCheck();
2791
+ }, { injector: this.injector });
2792
+ }
2793
+ /**
2794
+ * Recomputes every option's checkbox state where no selection change follows to do it: after `dataNodes` is
2795
+ * replaced, which moves the descendants a branch counts, and once a hidden checkbox appears. A microtask later, as
2796
+ * a consumer's data source can assign `dataNodes` after it emits.
2797
+ */
2798
+ scheduleCheckboxSync(force) {
2799
+ Promise.resolve().then(() => {
2800
+ const dataNodes = this.treeControl?.dataNodes ?? null;
2801
+ if (this.destroyed || (!force && dataNodes === this.checkboxSyncedDataNodes))
2802
+ return;
2803
+ this.checkboxSyncedDataNodes = dataNodes;
2804
+ this.unorderedOptions.forEach((option) => option.markForCheck());
2805
+ });
1783
2806
  }
2807
+ /** @docs-private */
1784
2808
  emitNavigationEvent(option) {
1785
2809
  this.navigationChange.emit(new KbqTreeNavigationChange(this, option));
1786
2810
  }
2811
+ /** @docs-private */
1787
2812
  emitChangeEvent(option) {
1788
2813
  this.selectionChange.emit(new KbqTreeSelectionChange(this, option, [option]));
1789
2814
  }
@@ -1792,46 +2817,63 @@ class KbqTreeSelection extends KbqTreeBase {
1792
2817
  * which toggles the selection of all non-disabled, selectable options.
1793
2818
  */
1794
2819
  get selectAllHandler() {
1795
- return this._selectAllHandler;
1796
- }
1797
- set selectAllHandler(fn) {
1798
- if (typeof fn !== 'function') {
1799
- throw Error('`selectAllHandler` must be a function.');
1800
- }
1801
- this._selectAllHandler = fn;
2820
+ return this.selectAllHandlerInput() ?? this.defaultSelectAllHandler;
1802
2821
  }
1803
- _selectAllHandler(event, tree) {
2822
+ defaultSelectAllHandler(event, tree) {
1804
2823
  event.preventDefault();
1805
2824
  tree.selectAllOptions();
1806
2825
  }
1807
- selectAllOptions(allowDeselect = this.selectAll || this.selectAllToggle()) {
1808
- // The row's own `(click)` and the Ctrl/Cmd + A shortcut both funnel through here, so this is the
1809
- // single place to refuse acting while the whole tree is disabled — mirrors the guard every other
1810
- // row already gets via `KbqTreeOption.selectViaInteraction()`.
1811
- if (this.disabled)
1812
- return;
1813
- // Selection is applied at the data-node level (incl. collapsed/non-rendered nodes unless a filter
1814
- // is active), while the emitted events carry the selectable rendered options.
1815
- const selectableOptions = this.renderedOptions.filter((option) => !option.disabled && option.selectable());
1816
- // `toggleSelectAll` returns the data nodes whose selection actually flipped — the source of
1817
- // truth, unlike the cached `option.selected` which lags until change detection.
1818
- const changed = toggleSelectAll(this.selectAllAdapter, { allowDeselect });
1819
- const changedData = new Set(changed);
1820
- const changedOptions = selectableOptions.filter((option) => changedData.has(option.data));
1821
- // Skip `selectionChange` on a no-op (e.g. Ctrl+A while everything is already selected and
1822
- // `allowDeselect` is off) so `KbqTreeSelectionChange.option` is never `undefined`.
1823
- if (changedOptions.length > 0) {
1824
- this.selectionChange.emit(new KbqTreeSelectionChange(this, changedOptions[0], changedOptions));
1825
- }
1826
- this.onSelectAll.emit(new KbqTreeSelectAllEvent(this, selectableOptions));
2826
+ selectAllOptions(allowDeselect) {
2827
+ // Untracked, its default included, like the other imperative methods: called from a consumer's `effect()`,
2828
+ // the state read on the way — the options, `disabled`, the mode, the inputs — would make the effect run
2829
+ // again whenever it changes.
2830
+ untracked(() => {
2831
+ // The row's own `(click)` and the Ctrl/Cmd + A shortcut both funnel through here, so this is the
2832
+ // single place to refuse acting while the whole tree is disabled — mirrors the guard every other
2833
+ // row already gets via `KbqTreeOption.selectViaInteraction()`.
2834
+ if (this.disabled)
2835
+ return;
2836
+ // Selection is applied at the data-node level (incl. collapsed/non-rendered nodes unless a filter
2837
+ // is active), while the emitted events carry the selectable rendered options.
2838
+ const selectableOptions = this.renderedOptions.filter((option) => !option.disabled && option.selectable());
2839
+ // A multiple selection takes the nodes in one write, so it changes once rather than once per node. A single
2840
+ // one cannot hold them, and keeps the node-by-node writes it always had.
2841
+ const batched = this.selectionModel.isMultipleSelection();
2842
+ const adapter = this.selectAllAdapter;
2843
+ // `toggleSelectAll` returns the data nodes whose selection actually flipped — the source of
2844
+ // truth, unlike the cached `option.selected` which lags until change detection.
2845
+ const changed = toggleSelectAll(batched ? { ...adapter, setSelected: () => { } } : adapter, {
2846
+ allowDeselect: allowDeselect ?? (this.selectAll || this.selectAllToggle())
2847
+ });
2848
+ if (batched && changed.length) {
2849
+ if (this.selectionModel.isSelected(changed[0])) {
2850
+ this.selectionModel.deselect(...changed);
2851
+ }
2852
+ else {
2853
+ this.selectionModel.select(...changed);
2854
+ }
2855
+ }
2856
+ const changedData = new Set(changed);
2857
+ const changedOptions = selectableOptions.filter((option) => changedData.has(option.data));
2858
+ // Skip `selectionChange` on a no-op (e.g. Ctrl+A while everything is already selected and
2859
+ // `allowDeselect` is off) so `KbqTreeSelectionChange.option` is never `undefined`.
2860
+ if (changedOptions.length > 0) {
2861
+ this.selectionChange.emit(new KbqTreeSelectionChange(this, changedOptions[0], changedOptions));
2862
+ }
2863
+ const selectAllEvent = new KbqTreeSelectAllEvent(this, selectableOptions);
2864
+ this.selectAllChange.emit(selectAllEvent);
2865
+ this.onSelectAll.emit(selectAllEvent);
2866
+ });
1827
2867
  }
1828
2868
  copyActiveOption(event) {
1829
2869
  if (!this.keyManager.activeItem)
1830
2870
  return;
1831
2871
  const option = this.keyManager.activeItem;
1832
2872
  option.preventBlur = true;
1833
- if (this.onCopy.observed) {
1834
- this.onCopy.emit(new KbqTreeCopyEvent(this, this.keyManager.activeItem, event));
2873
+ if (this.copyChange.observed || this.onCopy.observed) {
2874
+ const copyEvent = new KbqTreeCopyEvent(this, option, event);
2875
+ this.copyChange.emit(copyEvent);
2876
+ this.onCopy.emit(copyEvent);
1835
2877
  }
1836
2878
  else {
1837
2879
  this.onCopyDefaultHandler();
@@ -1840,20 +2882,44 @@ class KbqTreeSelection extends KbqTreeBase {
1840
2882
  option.preventBlur = false;
1841
2883
  }
1842
2884
  writeValue(value) {
1843
- if (this.multiple && value && !Array.isArray(value)) {
1844
- throw getKbqSelectNonArrayValueError();
1845
- }
1846
- if (value) {
1847
- this.setOptionsFromValues(this.multiple ? value : [value]);
1848
- }
1849
- else {
1850
- this.selectionModel.clear();
2885
+ untracked(() => {
2886
+ this.applyMultipleInput();
2887
+ if (this.multiple && value && !Array.isArray(value)) {
2888
+ throw getKbqSelectNonArrayValueError();
2889
+ }
2890
+ // The form holds the value it writes, so a mode change has nothing left to report.
2891
+ this.pendingValueReport = false;
2892
+ this.applyWrittenValue(value);
2893
+ });
2894
+ }
2895
+ /** Selects the nodes of a value the form wrote, and keeps the value for the data still to come if any is missing. */
2896
+ applyWrittenValue(value) {
2897
+ // A node value can be falsy, `0` or `''`: only a missing value clears the single selection.
2898
+ const values = this.multiple
2899
+ ? Array.isArray(value)
2900
+ ? value
2901
+ : null
2902
+ : value === null || value === undefined
2903
+ ? null
2904
+ : [value];
2905
+ this.syncSelection(() => (values ? this.setOptionsFromValues(values) : this.selectionModel.clear()));
2906
+ this.unresolvedValue = values?.some((item) => !this.treeControl.hasValue(item)) ? { value } : null;
2907
+ }
2908
+ /** Runs a change of the selection made by code, which reports nothing back to the form or to a host. */
2909
+ syncSelection(change) {
2910
+ // Restored rather than cleared: a value written while this one is applied must not end the outer write.
2911
+ const wasWritingValue = this.writingValue;
2912
+ this.writingValue = true;
2913
+ try {
2914
+ change();
2915
+ }
2916
+ finally {
2917
+ this.writingValue = wasWritingValue;
1851
2918
  }
1852
2919
  }
1853
2920
  registerOnChange(fn) {
1854
2921
  this.onChange = fn;
1855
2922
  }
1856
- // eslint-disable-next-line @typescript-eslint/no-empty-object-type
1857
2923
  registerOnTouched(fn) {
1858
2924
  this.onTouched = fn;
1859
2925
  }
@@ -1861,20 +2927,28 @@ class KbqTreeSelection extends KbqTreeBase {
1861
2927
  * Sets the disabled state of the control. Implemented as a part of ControlValueAccessor.
1862
2928
  */
1863
2929
  setDisabledState(isDisabled) {
1864
- this._disabled = isDisabled;
1865
- this.changeDetectorRef.markForCheck();
2930
+ untracked(() => {
2931
+ this.applyDisabledInput();
2932
+ this.disabledState.set(isDisabled);
2933
+ });
1866
2934
  }
2935
+ /** @docs-private */
1867
2936
  setOptionsFromValues(values) {
1868
- this.selectionModel.clear();
1869
- const valuesToSelect = values.reduce((result, value) => {
1870
- return this.treeControl.hasValue(value) ? [...result, this.treeControl.hasValue(value)] : [...result];
1871
- }, []);
1872
- this.selectionModel.select(...valuesToSelect);
2937
+ untracked(() => {
2938
+ this.selectionModel.clear();
2939
+ const valuesToSelect = values.reduce((result, value) => {
2940
+ return this.treeControl.hasValue(value) ? [...result, this.treeControl.hasValue(value)] : [...result];
2941
+ }, []);
2942
+ this.selectionModel.select(...valuesToSelect);
2943
+ });
1873
2944
  }
1874
2945
  /**
1875
2946
  * Rebinds orphan node references in selectionModel to current treeControl.dataNodes by value.
1876
2947
  * Needed after dataSource.data is replaced — selectionModel holds references to old node
1877
2948
  * objects, but options render with new ones, so toggle()/isSelected() break on identity.
2949
+ *
2950
+ * A value the form wrote ahead of its nodes is applied again instead, which resolves every node anew.
2951
+ * Either way the selection only follows the data, so nothing is reported.
1878
2952
  */
1879
2953
  syncSelectionModelToDataNodes() {
1880
2954
  const currentNodes = this.treeControl.dataNodes;
@@ -1883,6 +2957,10 @@ class KbqTreeSelection extends KbqTreeBase {
1883
2957
  if (currentNodes === this.lastSyncedDataNodes)
1884
2958
  return;
1885
2959
  this.lastSyncedDataNodes = currentNodes;
2960
+ if (this.unresolvedValue) {
2961
+ this.applyWrittenValue(this.unresolvedValue.value);
2962
+ return;
2963
+ }
1886
2964
  if (this.selectionModel.isEmpty() || !currentNodes?.length)
1887
2965
  return;
1888
2966
  const selected = this.selectionModel.selected;
@@ -1902,23 +2980,23 @@ class KbqTreeSelection extends KbqTreeBase {
1902
2980
  const replacement = this.treeControl.hasValue(this.treeControl.getValue(node));
1903
2981
  return replacement ?? node;
1904
2982
  });
1905
- this.selectionModel.setSelection(...reconciled);
2983
+ this.syncSelection(() => this.selectionModel.setSelection(...reconciled));
1906
2984
  }
2985
+ /** @docs-private */
1907
2986
  getSelectedValues() {
1908
2987
  const selectedValues = this.selectionModel.selected.map((selected) => this.treeControl.getValue(selected));
1909
2988
  return this.multiple ? selectedValues : selectedValues[0];
1910
2989
  }
1911
- getItemHeight() {
1912
- return this.renderedOptions.first ? this.renderedOptions.first.getHeight() : 0;
1913
- }
1914
2990
  setStateChildren(option, state) {
1915
- const valuesToChange = this.treeControl.getDescendants(option.data);
1916
- if (state) {
1917
- this.selectionModel.select(...valuesToChange);
1918
- }
1919
- else {
1920
- this.selectionModel.deselect(...valuesToChange);
1921
- }
2991
+ untracked(() => {
2992
+ const valuesToChange = this.treeControl.getDescendants(option.data);
2993
+ if (state) {
2994
+ this.selectionModel.select(...valuesToChange);
2995
+ }
2996
+ else {
2997
+ this.selectionModel.deselect(...valuesToChange);
2998
+ }
2999
+ });
1922
3000
  }
1923
3001
  onCopyDefaultHandler() {
1924
3002
  this.clipboard?.copy(this.keyManager.activeItem.value);
@@ -1951,11 +3029,48 @@ class KbqTreeSelection extends KbqTreeBase {
1951
3029
  level = option.level;
1952
3030
  }
1953
3031
  }
3032
+ /** `-1` is the key manager's way of keeping the letter stream running but never matching on it. */
3033
+ applyTypeAhead() {
3034
+ this.keyManager?.withTypeAhead(typeAheadDebounce, this.typeAhead ? 0 : -1);
3035
+ }
3036
+ /**
3037
+ * Moves focus to the first child of an already-expanded option — ArrowRight on an expanded node.
3038
+ *
3039
+ * The mirror of `setActiveParentOption`: the first rendered option after the active one is its
3040
+ * first child whenever its level is greater, so nothing has to be re-derived from `treeControl`.
3041
+ * A disabled child cannot take focus, so the walk continues while the options stay inside the
3042
+ * subtree, and stops as soon as the level falls back to the active option's own.
3043
+ */
3044
+ setActiveFirstChildOption(activeOption) {
3045
+ const options = this.renderedOptions.toArray();
3046
+ for (let index = this.keyManager.activeItemIndex + 1; index < options.length; index++) {
3047
+ const option = options[index];
3048
+ if (option.level <= activeOption.level) {
3049
+ return;
3050
+ }
3051
+ if (!option.disabled) {
3052
+ this.keyManager.setActiveItem(index);
3053
+ return;
3054
+ }
3055
+ }
3056
+ }
1954
3057
  getHeight() {
1955
3058
  return kbqGetElementHeight(this.elementRef.nativeElement);
1956
3059
  }
3060
+ /** A tree with nothing rendered leaves the tab order, unless a tab index other than `0` is bound. */
1957
3061
  updateTabIndex() {
1958
- this._tabIndex = this.renderedOptions.length === 0 ? -1 : 0;
3062
+ this.tabIndexState.set(this.userTabIndex || (this.renderedOptions.length === 0 ? -1 : 0));
3063
+ }
3064
+ /**
3065
+ * Whether the same options as before now stand for the rows in another order. A different count means rows were
3066
+ * added or removed, which the options query reports itself.
3067
+ */
3068
+ renderedOptionsOutOfOrder() {
3069
+ const options = this.renderedOptions.toArray();
3070
+ const offset = this.selectAllOption() ? 1 : 0;
3071
+ if (options.length - offset !== this.sortedNodes.length)
3072
+ return false;
3073
+ return this.sortedNodes.some((node, index) => options[index + offset].data !== node);
1959
3074
  }
1960
3075
  getSortedNodes(viewContainer) {
1961
3076
  const array = [];
@@ -1965,41 +3080,29 @@ class KbqTreeSelection extends KbqTreeBase {
1965
3080
  }
1966
3081
  return array;
1967
3082
  }
1968
- allowFocusEscape() {
1969
- if (this._tabIndex !== -1) {
1970
- this._tabIndex = -1;
1971
- setTimeout(() => {
1972
- this._tabIndex = this.userTabIndex || 0;
1973
- this.changeDetectorRef.markForCheck();
1974
- });
1975
- }
1976
- }
1977
- resetOptions() {
1978
- this.dropSubscriptions();
1979
- this.listenToOptionsFocus();
1980
- }
1981
- dropSubscriptions() {
1982
- if (this.optionFocusSubscription) {
1983
- this.optionFocusSubscription.unsubscribe();
1984
- this.optionFocusSubscription = null;
1985
- }
1986
- if (this.optionBlurSubscription) {
1987
- this.optionBlurSubscription.unsubscribe();
1988
- this.optionBlurSubscription = null;
1989
- }
1990
- }
1991
3083
  listenToOptionsFocus() {
1992
- this.optionFocusSubscription = this.optionFocusChanges.subscribe((event) => {
3084
+ // Both streams complete with the tree.
3085
+ this.optionFocusEvents.subscribe((event) => {
1993
3086
  const index = this.renderedOptions.toArray().indexOf(event.option);
1994
3087
  this.renderedOptions.filter((option) => option.hasFocus).forEach((option) => (option.hasFocus = false));
1995
3088
  if (this.isValidIndex(index)) {
1996
3089
  this.keyManager.updateActiveItem(index);
1997
3090
  }
1998
3091
  });
1999
- this.optionBlurSubscription = this.optionBlurChanges.subscribe(() => this.blur());
3092
+ // Moving the active option blurs the one being left, so an option blur alone does not mean the
3093
+ // options lost the focus — and resetting here would drop the active option the key manager has just
3094
+ // set, because `KbqTreeOption.hasFocus` is cleared synchronously but only raised a microtask later, so
3095
+ // `hasFocusedOption()` reports nothing focused for the whole move. Only a blur of the option the
3096
+ // key manager still points at is the focus actually leaving the options.
3097
+ this.optionBlurEvents.subscribe(({ option }) => {
3098
+ if (option === this.keyManager.activeItem && !this.hasFocusedOption() && this.resetFocusedItemOnBlur) {
3099
+ this.keyManager.setActiveItem(-1);
3100
+ }
3101
+ });
2000
3102
  }
2001
3103
  /**
2002
3104
  * Utility to ensure all indexes are valid.
3105
+ *
2003
3106
  * @param index The index to be checked.
2004
3107
  * @returns True if the index is valid for our list of options.
2005
3108
  */
@@ -2010,9 +3113,6 @@ class KbqTreeSelection extends KbqTreeBase {
2010
3113
  hasFocusedOption() {
2011
3114
  return this.renderedOptions.some((option) => option.hasFocus);
2012
3115
  }
2013
- markOptionsForCheck() {
2014
- this.renderedOptions.forEach((option) => option.markForCheck());
2015
- }
2016
3116
  updateOptionsFocus() {
2017
3117
  this.renderedOptions.filter((option) => option.hasFocus).forEach((option) => (option.hasFocus = false));
2018
3118
  }
@@ -2025,28 +3125,27 @@ class KbqTreeSelection extends KbqTreeBase {
2025
3125
  }
2026
3126
  return $event.relatedTarget.classList.contains('kbq-tree-option');
2027
3127
  }
2028
- /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqTreeSelection, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2029
- /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.30", type: KbqTreeSelection, isStandalone: true, selector: "kbq-tree-selection", inputs: { treeControl: { classPropertyName: "treeControl", publicName: "treeControl", isSignal: false, isRequired: false, transformFunction: null }, autoSelect: { classPropertyName: "autoSelect", publicName: "autoSelect", isSignal: false, isRequired: false, transformFunction: null }, noUnselectLast: { classPropertyName: "noUnselectLast", publicName: "noUnselectLast", isSignal: false, isRequired: false, transformFunction: null }, selectAllToggle: { classPropertyName: "selectAllToggle", publicName: "selectAllToggle", isSignal: true, isRequired: false, transformFunction: null }, selectAll: { classPropertyName: "selectAll", publicName: "selectAll", isSignal: false, isRequired: false, transformFunction: booleanAttribute }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: false, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: false, isRequired: false, transformFunction: null }, selectAllHandler: { classPropertyName: "selectAllHandler", publicName: "selectAllHandler", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { navigationChange: "navigationChange", selectionChange: "selectionChange", onSelectAll: "onSelectAll", onCopy: "onCopy" }, host: { listeners: { "blur": "blur()", "focus": "focus($event)", "keydown": "onKeyDown($event)", "window:resize": "updateScrollSize()" }, properties: { "attr.tabindex": "tabIndex", "attr.disabled": "disabled || null" }, classAttribute: "kbq-tree-selection" }, providers: [
3128
+ /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqTreeSelection, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3129
+ /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.25", type: KbqTreeSelection, isStandalone: true, selector: "kbq-tree-selection", inputs: { ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledby: { classPropertyName: "ariaLabelledby", publicName: "aria-labelledby", isSignal: true, isRequired: false, transformFunction: null }, autoSelectInput: { classPropertyName: "autoSelectInput", publicName: "autoSelect", isSignal: true, isRequired: false, transformFunction: null }, multipleInput: { classPropertyName: "multipleInput", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, noUnselectLastInput: { classPropertyName: "noUnselectLastInput", publicName: "noUnselectLast", isSignal: true, isRequired: false, transformFunction: null }, typeAheadInput: { classPropertyName: "typeAheadInput", publicName: "typeAhead", isSignal: true, isRequired: false, transformFunction: null }, selectAllToggle: { classPropertyName: "selectAllToggle", publicName: "selectAllToggle", isSignal: true, isRequired: false, transformFunction: null }, selectAllInput: { classPropertyName: "selectAllInput", publicName: "selectAll", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, tabIndexInput: { classPropertyName: "tabIndexInput", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, selectAllHandlerInput: { classPropertyName: "selectAllHandlerInput", publicName: "selectAllHandler", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { navigationChange: "navigationChange", selectionChangeOutput: "selectionChange", selectAllChange: "selectAllChange", onSelectAll: "onSelectAll", copyChangeOutput: "copyChange", onCopyOutput: "onCopy" }, host: { attributes: { "role": "tree" }, listeners: { "focus": "focus($event)", "keydown": "onKeyDown($event)", "window:resize": "updateScrollSize()" }, properties: { "attr.tabindex": "tabIndex", "attr.disabled": "disabled || null", "attr.aria-disabled": "disabled || null", "attr.aria-multiselectable": "multiple || null", "attr.aria-label": "resolvedAriaLabel", "attr.aria-labelledby": "resolvedAriaLabelledby", "attr.aria-activedescendant": "keyManager?.activeItem?.id" }, classAttribute: "kbq-tree-selection" }, providers: [
2030
3130
  KBQ_SELECTION_TREE_VALUE_ACCESSOR,
2031
3131
  { provide: KBQ_TREE_OPTION_PARENT_COMPONENT, useExisting: KbqTreeSelection },
2032
3132
  { provide: KbqTreeBase, useExisting: KbqTreeSelection }
2033
- ], queries: [{ propertyName: "unorderedOptions", predicate: KbqTreeOption }], viewQueries: [{ propertyName: "selectAllOption", first: true, predicate: KbqTreeOption, descendants: true, isSignal: true }, { propertyName: "nodeOutlet", first: true, predicate: KbqTreeNodeOutlet, descendants: true, static: true }], exportAs: ["kbqTreeSelection"], usesInheritance: true, ngImport: i0, template: `
3133
+ ], queries: [{ propertyName: "unorderedOptionsQuery", predicate: KbqTreeOption, isSignal: true }], viewQueries: [{ propertyName: "selectAllOption", first: true, predicate: KbqTreeOption, descendants: true, isSignal: true }], exportAs: ["kbqTreeSelection"], usesInheritance: true, hostDirectives: [{ directive: i1.KbqStateSaving, inputs: ["useStateSaving", "useStateSaving", "stateSavingKey", "stateSavingKey"] }, { directive: i1.KbqLocaleOverridesDirective, inputs: ["kbqLocaleOverrides", "localeOverrides"] }], ngImport: i0, template: `
2034
3134
  @if (showSelectAll) {
2035
- <!-- Every read of selectAllState re-filters the rendered nodes against the data set, and
2036
- allOptionsSelected is that same walk asking whether the state is "checked" — one read
2037
- covers all four. -->
3135
+ <!-- Every read of selectAllState re-filters the rendered nodes against the data set, so the
3136
+ two bindings below share one through @let. The row's own aria-checked host binding walks
3137
+ it a second time: Ivy evaluates that binding after this template, and the option reads
3138
+ the state through KBQ_TREE_OPTION_PARENT_COMPONENT rather than from here. -->
2038
3139
  @let selectAllCheckboxState = selectAllState;
2039
3140
 
3141
+ <!-- role and aria-checked come from the option's own host bindings: a host binding runs
3142
+ after the parent template's, so an override here would be the one that loses. -->
2040
3143
  <kbq-tree-option
2041
3144
  class="kbq-tree-option_select-all"
2042
3145
  kbqTreeNodePadding
2043
3146
  [selectAllRow]="true"
2044
3147
  [selectable]="false"
2045
3148
  [class.kbq-selected]="selectAllCheckboxState === 'checked'"
2046
- [attr.role]="'checkbox'"
2047
- [attr.aria-checked]="
2048
- selectAllCheckboxState === 'indeterminate' ? 'mixed' : selectAllCheckboxState === 'checked'
2049
- "
2050
3149
  (click)="toggleSelectAll()"
2051
3150
  >
2052
3151
  <kbq-pseudo-checkbox [state]="selectAllCheckboxState" />
@@ -2054,9 +3153,9 @@ class KbqTreeSelection extends KbqTreeBase {
2054
3153
  </kbq-tree-option>
2055
3154
  }
2056
3155
  <ng-container kbqTreeNodeOutlet />
2057
- `, isInline: true, styles: [".kbq-tree-selection{display:block}.kbq-tree-selection:focus{outline:none}.kbq-tree-option{--kbq-option-background: var(--kbq-tree-default-container-background);background:var(--kbq-tree-default-container-background)}.kbq-tree-option .kbq-option-text{color:var(--kbq-tree-default-text-color)}.kbq-tree-option .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-default-action-button-color)}.kbq-tree-option .kbq-option-caption{color:var(--kbq-tree-default-caption-color)}.kbq-tree-option:not(.kbq-disabled):hover,.kbq-tree-option:not(.kbq-disabled).kbq-hovered,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused{--kbq-option-background: var(--kbq-tree-states-hover-container-background);background:var(--kbq-tree-states-hover-container-background)}.kbq-tree-option:not(.kbq-disabled):hover .kbq-option-text,.kbq-tree-option:not(.kbq-disabled).kbq-hovered .kbq-option-text,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused .kbq-option-text{color:var(--kbq-tree-states-hover-text-color)}.kbq-tree-option:not(.kbq-disabled):hover .kbq-option-action .kbq-icon.kbq-empty,.kbq-tree-option:not(.kbq-disabled).kbq-hovered .kbq-option-action .kbq-icon.kbq-empty,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-hover-action-button-color)}.kbq-tree-option:not(.kbq-disabled):hover .kbq-option-caption,.kbq-tree-option:not(.kbq-disabled).kbq-hovered .kbq-option-caption,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused .kbq-option-caption{color:var(--kbq-tree-states-hover-caption-color)}.kbq-tree-option:not(.kbq-disabled):active,.kbq-tree-option:not(.kbq-disabled).kbq-active{--kbq-option-background: var(--kbq-tree-states-active-container-background);background:var(--kbq-tree-states-active-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-selected{--kbq-option-background: var(--kbq-tree-states-selected-container-background);background:var(--kbq-tree-states-selected-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-selected .kbq-option-text{color:var(--kbq-tree-states-selected-text-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-selected-action-button-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected .kbq-option-caption{color:var(--kbq-tree-states-selected-caption-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered{--kbq-option-background: var(--kbq-tree-states-selected-hover-container-background);background:var(--kbq-tree-states-selected-hover-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover .kbq-option-text,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered .kbq-option-text{color:var(--kbq-tree-states-selected-hover-text-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover .kbq-option-action .kbq-icon.kbq-empty,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-selected-hover-action-button-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover .kbq-option-caption,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered .kbq-option-caption{color:var(--kbq-tree-states-selected-hover-caption-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:active,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-active{--kbq-option-background: var(--kbq-tree-states-selected-active-container-background);background:var(--kbq-tree-states-selected-active-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected),.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected{--kbq-option-background: var(--kbq-tree-multiple-states-selected-container-background);background:var(--kbq-tree-multiple-states-selected-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected):hover,.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected).kbq-hovered,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected:hover,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected.kbq-hovered{--kbq-option-background: var(--kbq-tree-multiple-states-selected-hover-container-background);background:var(--kbq-tree-multiple-states-selected-hover-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected):active,.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected).kbq-active,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected:active,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected.kbq-active{--kbq-option-background: var(--kbq-tree-multiple-states-selected-active-container-background);background:var(--kbq-tree-multiple-states-selected-active-container-background)}.kbq-tree-option.kbq-disabled{--kbq-option-background: var(--kbq-tree-states-disabled-container-background);background:var(--kbq-tree-states-disabled-container-background)}.kbq-tree-option.kbq-disabled .kbq-option-text{color:var(--kbq-tree-states-disabled-text-color)}.kbq-tree-option.kbq-disabled .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-disabled-action-button-color)}.kbq-tree-option.kbq-disabled .kbq-option-caption{color:var(--kbq-tree-states-disabled-caption-color)}.kbq-tree-option.kbq-disabled .kbq-icon.kbq-empty:not(.kbq-tree-node-toggle .kbq-icon){color:var(--kbq-states-icon-disabled)}.kbq-tree-selection.cdk-keyboard-focused .kbq-tree-option.kbq-focused:not(.kbq-action-button-focused){border-color:var(--kbq-tree-states-focused-focus-outline-color)}.kbq-tree-option{font-size:var(--kbq-typography-text-normal-font-size);font-style:var(--kbq-typography-text-normal-font-style);font-weight:var(--kbq-typography-text-normal-font-weight);line-height:var(--kbq-typography-text-normal-line-height);font-family:var(--kbq-typography-text-normal-font-family);text-transform:var(--kbq-typography-text-normal-text-transform);font-feature-settings:var(--kbq-typography-text-normal-font-feature-settings);letter-spacing:var(--kbq-typography-text-normal-letter-spacing)}.kbq-option-caption{font-size:var(--kbq-typography-text-compact-font-size);font-style:var(--kbq-typography-text-compact-font-style);font-weight:var(--kbq-typography-text-compact-font-weight);line-height:var(--kbq-typography-text-compact-line-height);font-family:var(--kbq-typography-text-compact-font-family);text-transform:var(--kbq-typography-text-compact-text-transform);font-feature-settings:var(--kbq-typography-text-compact-font-feature-settings);letter-spacing:var(--kbq-typography-text-compact-letter-spacing)}\n", ".kbq-tree,.kbq-tree-selection{--kbq-tree-size-indent-level: var(--kbq-size-xxl);--kbq-tree-size-container-padding-right: var(--kbq-size-s);--kbq-tree-size-container-padding-vertical: var(--kbq-size-xxs);--kbq-tree-size-container-content-gap-horizontal: var(--kbq-size-s);--kbq-tree-size-container-content-gap-vertical: 0px;--kbq-tree-size-container-focus-outline-width: var(--kbq-size-3xs);--kbq-tree-size-text-padding-vertical: var(--kbq-size-3xs);--kbq-tree-option-border-radius: var(--kbq-size-border-radius);--kbq-tree-default-container-background: transparent;--kbq-tree-default-text-color: var(--kbq-foreground-contrast);--kbq-tree-default-icon-color: var(--kbq-icon-contrast);--kbq-tree-default-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-hover-container-background: var(--kbq-states-background-transparent-hover);--kbq-tree-states-active-container-background: var(--kbq-states-background-transparent-active);--kbq-tree-states-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-focused-focus-outline-color: var(--kbq-states-line-focus-theme);--kbq-tree-states-selected-container-background: var(--kbq-background-theme-less);--kbq-tree-multiple-states-selected-container-background: var(--kbq-background-contrast-less);--kbq-tree-states-selected-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-selected-hover-container-background: var(--kbq-states-background-theme-less-hover);--kbq-tree-states-selected-active-container-background: var(--kbq-states-background-theme-less-active);--kbq-tree-multiple-states-selected-hover-container-background: var(--kbq-states-background-contrast-less-hover);--kbq-tree-multiple-states-selected-active-container-background: var(--kbq-states-background-contrast-less-active);--kbq-tree-states-selected-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-disabled-container-background: transparent;--kbq-tree-states-disabled-text-color: var(--kbq-states-foreground-disabled);--kbq-tree-states-disabled-icon-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-tree-toggle-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-action-button-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-caption-color: var(--kbq-states-foreground-disabled)}\n"], dependencies: [{ kind: "directive", type: KbqTreeNodeOutlet, selector: "[kbqTreeNodeOutlet]" }, { kind: "component", type: KbqTreeOption, selector: "kbq-tree-option", inputs: ["checkboxThirdState", "disabled", "selectable", "selectAllRow", "showCheckbox"], outputs: ["onSelectionChange"], exportAs: ["kbqTreeOption"] }, { kind: "directive", type: KbqTreeNodePadding, selector: "[kbqTreeNodePadding]", inputs: ["kbqTreeNodePaddingIndent"], exportAs: ["kbqTreeNodePadding"] }, { kind: "component", type: KbqPseudoCheckbox, selector: "kbq-pseudo-checkbox", inputs: ["big", "state", "disabled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
3156
+ `, isInline: true, styles: [".kbq-tree-selection{display:block}.kbq-tree-selection:focus{outline:none}.kbq-tree-option{--kbq-option-background: var(--kbq-tree-default-container-background);background:var(--kbq-tree-default-container-background)}.kbq-tree-option .kbq-option-text{color:var(--kbq-tree-default-text-color)}.kbq-tree-option .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-default-action-button-color)}.kbq-tree-option .kbq-option-caption{color:var(--kbq-tree-default-caption-color)}.kbq-tree-option:not(.kbq-disabled):hover,.kbq-tree-option:not(.kbq-disabled).kbq-hovered,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused{--kbq-option-background: var(--kbq-tree-states-hover-container-background);background:var(--kbq-tree-states-hover-container-background)}.kbq-tree-option:not(.kbq-disabled):hover .kbq-option-text,.kbq-tree-option:not(.kbq-disabled).kbq-hovered .kbq-option-text,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused .kbq-option-text{color:var(--kbq-tree-states-hover-text-color)}.kbq-tree-option:not(.kbq-disabled):hover .kbq-option-action .kbq-icon.kbq-empty,.kbq-tree-option:not(.kbq-disabled).kbq-hovered .kbq-option-action .kbq-icon.kbq-empty,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-hover-action-button-color)}.kbq-tree-option:not(.kbq-disabled):hover .kbq-option-caption,.kbq-tree-option:not(.kbq-disabled).kbq-hovered .kbq-option-caption,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused .kbq-option-caption{color:var(--kbq-tree-states-hover-caption-color)}.kbq-tree-option:not(.kbq-disabled):active,.kbq-tree-option:not(.kbq-disabled).kbq-active{--kbq-option-background: var(--kbq-tree-states-active-container-background);background:var(--kbq-tree-states-active-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-selected{--kbq-option-background: var(--kbq-tree-states-selected-container-background);background:var(--kbq-tree-states-selected-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-selected .kbq-option-text{color:var(--kbq-tree-states-selected-text-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-selected-action-button-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected .kbq-option-caption{color:var(--kbq-tree-states-selected-caption-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered{--kbq-option-background: var(--kbq-tree-states-selected-hover-container-background);background:var(--kbq-tree-states-selected-hover-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover .kbq-option-text,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered .kbq-option-text{color:var(--kbq-tree-states-selected-hover-text-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover .kbq-option-action .kbq-icon.kbq-empty,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-selected-hover-action-button-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover .kbq-option-caption,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered .kbq-option-caption{color:var(--kbq-tree-states-selected-hover-caption-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:active,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-active{--kbq-option-background: var(--kbq-tree-states-selected-active-container-background);background:var(--kbq-tree-states-selected-active-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected),.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected{--kbq-option-background: var(--kbq-tree-multiple-states-selected-container-background);background:var(--kbq-tree-multiple-states-selected-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected):hover,.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected).kbq-hovered,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected:hover,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected.kbq-hovered{--kbq-option-background: var(--kbq-tree-multiple-states-selected-hover-container-background);background:var(--kbq-tree-multiple-states-selected-hover-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected):active,.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected).kbq-active,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected:active,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected.kbq-active{--kbq-option-background: var(--kbq-tree-multiple-states-selected-active-container-background);background:var(--kbq-tree-multiple-states-selected-active-container-background)}.kbq-tree-option.kbq-disabled{--kbq-option-background: var(--kbq-tree-states-disabled-container-background);background:var(--kbq-tree-states-disabled-container-background)}.kbq-tree-option.kbq-disabled .kbq-option-text{color:var(--kbq-tree-states-disabled-text-color)}.kbq-tree-option.kbq-disabled .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-disabled-action-button-color)}.kbq-tree-option.kbq-disabled .kbq-option-caption{color:var(--kbq-tree-states-disabled-caption-color)}.kbq-tree-option.kbq-disabled .kbq-icon.kbq-empty:not(.kbq-tree-node-toggle .kbq-icon){color:var(--kbq-states-icon-disabled)}.kbq-tree-selection.cdk-keyboard-focused .kbq-tree-option.kbq-focused:not(.kbq-action-button-focused){border-color:var(--kbq-tree-states-focused-focus-outline-color)}.kbq-tree-option{font-size:var(--kbq-typography-text-normal-font-size);font-style:var(--kbq-typography-text-normal-font-style);font-weight:var(--kbq-typography-text-normal-font-weight);line-height:var(--kbq-typography-text-normal-line-height);font-family:var(--kbq-typography-text-normal-font-family);text-transform:var(--kbq-typography-text-normal-text-transform);font-feature-settings:var(--kbq-typography-text-normal-font-feature-settings);letter-spacing:var(--kbq-typography-text-normal-letter-spacing)}.kbq-option-caption{font-size:var(--kbq-typography-text-compact-font-size);font-style:var(--kbq-typography-text-compact-font-style);font-weight:var(--kbq-typography-text-compact-font-weight);line-height:var(--kbq-typography-text-compact-line-height);font-family:var(--kbq-typography-text-compact-font-family);text-transform:var(--kbq-typography-text-compact-text-transform);font-feature-settings:var(--kbq-typography-text-compact-font-feature-settings);letter-spacing:var(--kbq-typography-text-compact-letter-spacing)}\n", ".kbq-tree,.kbq-tree-selection{--kbq-tree-size-indent-level: var(--kbq-size-xxl);--kbq-tree-size-container-padding-right: var(--kbq-size-s);--kbq-tree-size-container-padding-vertical: var(--kbq-size-xxs);--kbq-tree-size-container-content-gap-horizontal: var(--kbq-size-s);--kbq-tree-size-container-focus-outline-width: var(--kbq-size-3xs);--kbq-tree-size-text-padding-vertical: var(--kbq-size-3xs);--kbq-tree-option-border-radius: var(--kbq-size-border-radius);--kbq-tree-default-container-background: transparent;--kbq-tree-default-text-color: var(--kbq-foreground-contrast);--kbq-tree-default-icon-color: var(--kbq-icon-contrast);--kbq-tree-default-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-hover-container-background: var(--kbq-states-background-transparent-hover);--kbq-tree-states-active-container-background: var(--kbq-states-background-transparent-active);--kbq-tree-states-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-focused-focus-outline-color: var(--kbq-states-line-focus-theme);--kbq-tree-states-selected-container-background: var(--kbq-background-theme-less);--kbq-tree-multiple-states-selected-container-background: var(--kbq-background-contrast-less);--kbq-tree-states-selected-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-selected-hover-container-background: var(--kbq-states-background-theme-less-hover);--kbq-tree-states-selected-active-container-background: var(--kbq-states-background-theme-less-active);--kbq-tree-multiple-states-selected-hover-container-background: var(--kbq-states-background-contrast-less-hover);--kbq-tree-multiple-states-selected-active-container-background: var(--kbq-states-background-contrast-less-active);--kbq-tree-states-selected-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-disabled-container-background: transparent;--kbq-tree-states-disabled-text-color: var(--kbq-states-foreground-disabled);--kbq-tree-states-disabled-icon-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-tree-toggle-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-action-button-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-caption-color: var(--kbq-states-foreground-disabled)}\n"], dependencies: [{ kind: "directive", type: KbqTreeNodeOutlet, selector: "[kbqTreeNodeOutlet]" }, { kind: "component", type: KbqTreeOption, selector: "kbq-tree-option", inputs: ["checkboxThirdState", "disabled", "selectable", "selectAllRow", "showCheckbox"], outputs: ["selectionChange", "onSelectionChange"], exportAs: ["kbqTreeOption"] }, { kind: "directive", type: KbqTreeNodePadding, selector: "[kbqTreeNodePadding]", inputs: ["kbqTreeNodePaddingIndent"], exportAs: ["kbqTreeNodePadding"] }, { kind: "component", type: KbqPseudoCheckbox, selector: "kbq-pseudo-checkbox", inputs: ["big", "state", "disabled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
2058
3157
  }
2059
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqTreeSelection, decorators: [{
3158
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqTreeSelection, decorators: [{
2060
3159
  type: Component,
2061
3160
  args: [{ selector: 'kbq-tree-selection', imports: [
2062
3161
  KbqTreeNodeOutlet,
@@ -2065,21 +3164,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImpo
2065
3164
  KbqPseudoCheckbox
2066
3165
  ], template: `
2067
3166
  @if (showSelectAll) {
2068
- <!-- Every read of selectAllState re-filters the rendered nodes against the data set, and
2069
- allOptionsSelected is that same walk asking whether the state is "checked" — one read
2070
- covers all four. -->
3167
+ <!-- Every read of selectAllState re-filters the rendered nodes against the data set, so the
3168
+ two bindings below share one through @let. The row's own aria-checked host binding walks
3169
+ it a second time: Ivy evaluates that binding after this template, and the option reads
3170
+ the state through KBQ_TREE_OPTION_PARENT_COMPONENT rather than from here. -->
2071
3171
  @let selectAllCheckboxState = selectAllState;
2072
3172
 
3173
+ <!-- role and aria-checked come from the option's own host bindings: a host binding runs
3174
+ after the parent template's, so an override here would be the one that loses. -->
2073
3175
  <kbq-tree-option
2074
3176
  class="kbq-tree-option_select-all"
2075
3177
  kbqTreeNodePadding
2076
3178
  [selectAllRow]="true"
2077
3179
  [selectable]="false"
2078
3180
  [class.kbq-selected]="selectAllCheckboxState === 'checked'"
2079
- [attr.role]="'checkbox'"
2080
- [attr.aria-checked]="
2081
- selectAllCheckboxState === 'indeterminate' ? 'mixed' : selectAllCheckboxState === 'checked'
2082
- "
2083
3181
  (click)="toggleSelectAll()"
2084
3182
  >
2085
3183
  <kbq-pseudo-checkbox [state]="selectAllCheckboxState" />
@@ -2093,39 +3191,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImpo
2093
3191
  { provide: KbqTreeBase, useExisting: KbqTreeSelection }
2094
3192
  ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
2095
3193
  class: 'kbq-tree-selection',
3194
+ role: 'tree',
2096
3195
  '[attr.tabindex]': 'tabIndex',
2097
3196
  '[attr.disabled]': 'disabled || null',
2098
- '(blur)': 'blur()',
3197
+ '[attr.aria-disabled]': 'disabled || null',
3198
+ '[attr.aria-multiselectable]': 'multiple || null',
3199
+ '[attr.aria-label]': 'resolvedAriaLabel',
3200
+ '[attr.aria-labelledby]': 'resolvedAriaLabelledby',
3201
+ // The active option takes real DOM focus (`KbqTreeOption.focus`) and is advertised here on top
3202
+ // of that, so an AT that follows either model reports the same row.
3203
+ '[attr.aria-activedescendant]': 'keyManager?.activeItem?.id',
2099
3204
  '(focus)': 'focus($event)',
2100
3205
  '(keydown)': 'onKeyDown($event)',
2101
3206
  '(window:resize)': 'updateScrollSize()'
2102
- }, exportAs: 'kbqTreeSelection', styles: [".kbq-tree-selection{display:block}.kbq-tree-selection:focus{outline:none}.kbq-tree-option{--kbq-option-background: var(--kbq-tree-default-container-background);background:var(--kbq-tree-default-container-background)}.kbq-tree-option .kbq-option-text{color:var(--kbq-tree-default-text-color)}.kbq-tree-option .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-default-action-button-color)}.kbq-tree-option .kbq-option-caption{color:var(--kbq-tree-default-caption-color)}.kbq-tree-option:not(.kbq-disabled):hover,.kbq-tree-option:not(.kbq-disabled).kbq-hovered,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused{--kbq-option-background: var(--kbq-tree-states-hover-container-background);background:var(--kbq-tree-states-hover-container-background)}.kbq-tree-option:not(.kbq-disabled):hover .kbq-option-text,.kbq-tree-option:not(.kbq-disabled).kbq-hovered .kbq-option-text,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused .kbq-option-text{color:var(--kbq-tree-states-hover-text-color)}.kbq-tree-option:not(.kbq-disabled):hover .kbq-option-action .kbq-icon.kbq-empty,.kbq-tree-option:not(.kbq-disabled).kbq-hovered .kbq-option-action .kbq-icon.kbq-empty,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-hover-action-button-color)}.kbq-tree-option:not(.kbq-disabled):hover .kbq-option-caption,.kbq-tree-option:not(.kbq-disabled).kbq-hovered .kbq-option-caption,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused .kbq-option-caption{color:var(--kbq-tree-states-hover-caption-color)}.kbq-tree-option:not(.kbq-disabled):active,.kbq-tree-option:not(.kbq-disabled).kbq-active{--kbq-option-background: var(--kbq-tree-states-active-container-background);background:var(--kbq-tree-states-active-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-selected{--kbq-option-background: var(--kbq-tree-states-selected-container-background);background:var(--kbq-tree-states-selected-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-selected .kbq-option-text{color:var(--kbq-tree-states-selected-text-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-selected-action-button-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected .kbq-option-caption{color:var(--kbq-tree-states-selected-caption-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered{--kbq-option-background: var(--kbq-tree-states-selected-hover-container-background);background:var(--kbq-tree-states-selected-hover-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover .kbq-option-text,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered .kbq-option-text{color:var(--kbq-tree-states-selected-hover-text-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover .kbq-option-action .kbq-icon.kbq-empty,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-selected-hover-action-button-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover .kbq-option-caption,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered .kbq-option-caption{color:var(--kbq-tree-states-selected-hover-caption-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:active,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-active{--kbq-option-background: var(--kbq-tree-states-selected-active-container-background);background:var(--kbq-tree-states-selected-active-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected),.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected{--kbq-option-background: var(--kbq-tree-multiple-states-selected-container-background);background:var(--kbq-tree-multiple-states-selected-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected):hover,.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected).kbq-hovered,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected:hover,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected.kbq-hovered{--kbq-option-background: var(--kbq-tree-multiple-states-selected-hover-container-background);background:var(--kbq-tree-multiple-states-selected-hover-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected):active,.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected).kbq-active,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected:active,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected.kbq-active{--kbq-option-background: var(--kbq-tree-multiple-states-selected-active-container-background);background:var(--kbq-tree-multiple-states-selected-active-container-background)}.kbq-tree-option.kbq-disabled{--kbq-option-background: var(--kbq-tree-states-disabled-container-background);background:var(--kbq-tree-states-disabled-container-background)}.kbq-tree-option.kbq-disabled .kbq-option-text{color:var(--kbq-tree-states-disabled-text-color)}.kbq-tree-option.kbq-disabled .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-disabled-action-button-color)}.kbq-tree-option.kbq-disabled .kbq-option-caption{color:var(--kbq-tree-states-disabled-caption-color)}.kbq-tree-option.kbq-disabled .kbq-icon.kbq-empty:not(.kbq-tree-node-toggle .kbq-icon){color:var(--kbq-states-icon-disabled)}.kbq-tree-selection.cdk-keyboard-focused .kbq-tree-option.kbq-focused:not(.kbq-action-button-focused){border-color:var(--kbq-tree-states-focused-focus-outline-color)}.kbq-tree-option{font-size:var(--kbq-typography-text-normal-font-size);font-style:var(--kbq-typography-text-normal-font-style);font-weight:var(--kbq-typography-text-normal-font-weight);line-height:var(--kbq-typography-text-normal-line-height);font-family:var(--kbq-typography-text-normal-font-family);text-transform:var(--kbq-typography-text-normal-text-transform);font-feature-settings:var(--kbq-typography-text-normal-font-feature-settings);letter-spacing:var(--kbq-typography-text-normal-letter-spacing)}.kbq-option-caption{font-size:var(--kbq-typography-text-compact-font-size);font-style:var(--kbq-typography-text-compact-font-style);font-weight:var(--kbq-typography-text-compact-font-weight);line-height:var(--kbq-typography-text-compact-line-height);font-family:var(--kbq-typography-text-compact-font-family);text-transform:var(--kbq-typography-text-compact-text-transform);font-feature-settings:var(--kbq-typography-text-compact-font-feature-settings);letter-spacing:var(--kbq-typography-text-compact-letter-spacing)}\n", ".kbq-tree,.kbq-tree-selection{--kbq-tree-size-indent-level: var(--kbq-size-xxl);--kbq-tree-size-container-padding-right: var(--kbq-size-s);--kbq-tree-size-container-padding-vertical: var(--kbq-size-xxs);--kbq-tree-size-container-content-gap-horizontal: var(--kbq-size-s);--kbq-tree-size-container-content-gap-vertical: 0px;--kbq-tree-size-container-focus-outline-width: var(--kbq-size-3xs);--kbq-tree-size-text-padding-vertical: var(--kbq-size-3xs);--kbq-tree-option-border-radius: var(--kbq-size-border-radius);--kbq-tree-default-container-background: transparent;--kbq-tree-default-text-color: var(--kbq-foreground-contrast);--kbq-tree-default-icon-color: var(--kbq-icon-contrast);--kbq-tree-default-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-hover-container-background: var(--kbq-states-background-transparent-hover);--kbq-tree-states-active-container-background: var(--kbq-states-background-transparent-active);--kbq-tree-states-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-focused-focus-outline-color: var(--kbq-states-line-focus-theme);--kbq-tree-states-selected-container-background: var(--kbq-background-theme-less);--kbq-tree-multiple-states-selected-container-background: var(--kbq-background-contrast-less);--kbq-tree-states-selected-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-selected-hover-container-background: var(--kbq-states-background-theme-less-hover);--kbq-tree-states-selected-active-container-background: var(--kbq-states-background-theme-less-active);--kbq-tree-multiple-states-selected-hover-container-background: var(--kbq-states-background-contrast-less-hover);--kbq-tree-multiple-states-selected-active-container-background: var(--kbq-states-background-contrast-less-active);--kbq-tree-states-selected-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-disabled-container-background: transparent;--kbq-tree-states-disabled-text-color: var(--kbq-states-foreground-disabled);--kbq-tree-states-disabled-icon-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-tree-toggle-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-action-button-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-caption-color: var(--kbq-states-foreground-disabled)}\n"] }]
2103
- }], ctorParameters: () => [], propDecorators: { nodeOutlet: [{
2104
- type: ViewChild,
2105
- args: [KbqTreeNodeOutlet, { static: true }]
2106
- }], selectAllOption: [{ type: i0.ViewChild, args: [i0.forwardRef(() => KbqTreeOption), { isSignal: true }] }], unorderedOptions: [{
2107
- type: ContentChildren,
2108
- args: [KbqTreeOption]
2109
- }], treeControl: [{
2110
- type: Input
2111
- }], navigationChange: [{ type: i0.Output, args: ["navigationChange"] }], selectionChange: [{
2112
- type: Output
2113
- }], onSelectAll: [{ type: i0.Output, args: ["onSelectAll"] }], onCopy: [{
2114
- type: Output
2115
- }], autoSelect: [{
2116
- type: Input
2117
- }], noUnselectLast: [{
2118
- type: Input
2119
- }], selectAllToggle: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectAllToggle", required: false }] }], selectAll: [{
2120
- type: Input,
2121
- args: [{ transform: booleanAttribute }]
2122
- }], disabled: [{
2123
- type: Input
2124
- }], tabIndex: [{
2125
- type: Input
2126
- }], selectAllHandler: [{
2127
- type: Input
2128
- }] } });
3207
+ }, hostDirectives: [
3208
+ { directive: KbqStateSaving, inputs: ['useStateSaving', 'stateSavingKey'] },
3209
+ { directive: KbqLocaleOverridesDirective, inputs: ['kbqLocaleOverrides: localeOverrides'] }
3210
+ ], exportAs: 'kbqTreeSelection', styles: [".kbq-tree-selection{display:block}.kbq-tree-selection:focus{outline:none}.kbq-tree-option{--kbq-option-background: var(--kbq-tree-default-container-background);background:var(--kbq-tree-default-container-background)}.kbq-tree-option .kbq-option-text{color:var(--kbq-tree-default-text-color)}.kbq-tree-option .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-default-action-button-color)}.kbq-tree-option .kbq-option-caption{color:var(--kbq-tree-default-caption-color)}.kbq-tree-option:not(.kbq-disabled):hover,.kbq-tree-option:not(.kbq-disabled).kbq-hovered,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused{--kbq-option-background: var(--kbq-tree-states-hover-container-background);background:var(--kbq-tree-states-hover-container-background)}.kbq-tree-option:not(.kbq-disabled):hover .kbq-option-text,.kbq-tree-option:not(.kbq-disabled).kbq-hovered .kbq-option-text,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused .kbq-option-text{color:var(--kbq-tree-states-hover-text-color)}.kbq-tree-option:not(.kbq-disabled):hover .kbq-option-action .kbq-icon.kbq-empty,.kbq-tree-option:not(.kbq-disabled).kbq-hovered .kbq-option-action .kbq-icon.kbq-empty,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-hover-action-button-color)}.kbq-tree-option:not(.kbq-disabled):hover .kbq-option-caption,.kbq-tree-option:not(.kbq-disabled).kbq-hovered .kbq-option-caption,.kbq-tree-option:not(.kbq-disabled).kbq-action-button-focused .kbq-option-caption{color:var(--kbq-tree-states-hover-caption-color)}.kbq-tree-option:not(.kbq-disabled):active,.kbq-tree-option:not(.kbq-disabled).kbq-active{--kbq-option-background: var(--kbq-tree-states-active-container-background);background:var(--kbq-tree-states-active-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-selected{--kbq-option-background: var(--kbq-tree-states-selected-container-background);background:var(--kbq-tree-states-selected-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-selected .kbq-option-text{color:var(--kbq-tree-states-selected-text-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-selected-action-button-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected .kbq-option-caption{color:var(--kbq-tree-states-selected-caption-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered{--kbq-option-background: var(--kbq-tree-states-selected-hover-container-background);background:var(--kbq-tree-states-selected-hover-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover .kbq-option-text,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered .kbq-option-text{color:var(--kbq-tree-states-selected-hover-text-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover .kbq-option-action .kbq-icon.kbq-empty,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-selected-hover-action-button-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:hover .kbq-option-caption,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-hovered .kbq-option-caption{color:var(--kbq-tree-states-selected-hover-caption-color)}.kbq-tree-option:not(.kbq-disabled).kbq-selected:active,.kbq-tree-option:not(.kbq-disabled).kbq-selected.kbq-active{--kbq-option-background: var(--kbq-tree-states-selected-active-container-background);background:var(--kbq-tree-states-selected-active-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected),.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected{--kbq-option-background: var(--kbq-tree-multiple-states-selected-container-background);background:var(--kbq-tree-multiple-states-selected-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected):hover,.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected).kbq-hovered,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected:hover,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected.kbq-hovered{--kbq-option-background: var(--kbq-tree-multiple-states-selected-hover-container-background);background:var(--kbq-tree-multiple-states-selected-hover-container-background)}.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected):active,.kbq-tree-option:not(.kbq-disabled).kbq-checked:not(.kbq-selected).kbq-active,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected:active,.kbq-tree-option:not(.kbq-disabled).kbq-tree-option_multiple.kbq-selected.kbq-active{--kbq-option-background: var(--kbq-tree-multiple-states-selected-active-container-background);background:var(--kbq-tree-multiple-states-selected-active-container-background)}.kbq-tree-option.kbq-disabled{--kbq-option-background: var(--kbq-tree-states-disabled-container-background);background:var(--kbq-tree-states-disabled-container-background)}.kbq-tree-option.kbq-disabled .kbq-option-text{color:var(--kbq-tree-states-disabled-text-color)}.kbq-tree-option.kbq-disabled .kbq-option-action .kbq-icon.kbq-empty{color:var(--kbq-tree-states-disabled-action-button-color)}.kbq-tree-option.kbq-disabled .kbq-option-caption{color:var(--kbq-tree-states-disabled-caption-color)}.kbq-tree-option.kbq-disabled .kbq-icon.kbq-empty:not(.kbq-tree-node-toggle .kbq-icon){color:var(--kbq-states-icon-disabled)}.kbq-tree-selection.cdk-keyboard-focused .kbq-tree-option.kbq-focused:not(.kbq-action-button-focused){border-color:var(--kbq-tree-states-focused-focus-outline-color)}.kbq-tree-option{font-size:var(--kbq-typography-text-normal-font-size);font-style:var(--kbq-typography-text-normal-font-style);font-weight:var(--kbq-typography-text-normal-font-weight);line-height:var(--kbq-typography-text-normal-line-height);font-family:var(--kbq-typography-text-normal-font-family);text-transform:var(--kbq-typography-text-normal-text-transform);font-feature-settings:var(--kbq-typography-text-normal-font-feature-settings);letter-spacing:var(--kbq-typography-text-normal-letter-spacing)}.kbq-option-caption{font-size:var(--kbq-typography-text-compact-font-size);font-style:var(--kbq-typography-text-compact-font-style);font-weight:var(--kbq-typography-text-compact-font-weight);line-height:var(--kbq-typography-text-compact-line-height);font-family:var(--kbq-typography-text-compact-font-family);text-transform:var(--kbq-typography-text-compact-text-transform);font-feature-settings:var(--kbq-typography-text-compact-font-feature-settings);letter-spacing:var(--kbq-typography-text-compact-letter-spacing)}\n", ".kbq-tree,.kbq-tree-selection{--kbq-tree-size-indent-level: var(--kbq-size-xxl);--kbq-tree-size-container-padding-right: var(--kbq-size-s);--kbq-tree-size-container-padding-vertical: var(--kbq-size-xxs);--kbq-tree-size-container-content-gap-horizontal: var(--kbq-size-s);--kbq-tree-size-container-focus-outline-width: var(--kbq-size-3xs);--kbq-tree-size-text-padding-vertical: var(--kbq-size-3xs);--kbq-tree-option-border-radius: var(--kbq-size-border-radius);--kbq-tree-default-container-background: transparent;--kbq-tree-default-text-color: var(--kbq-foreground-contrast);--kbq-tree-default-icon-color: var(--kbq-icon-contrast);--kbq-tree-default-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-default-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-hover-container-background: var(--kbq-states-background-transparent-hover);--kbq-tree-states-active-container-background: var(--kbq-states-background-transparent-active);--kbq-tree-states-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-focused-focus-outline-color: var(--kbq-states-line-focus-theme);--kbq-tree-states-selected-container-background: var(--kbq-background-theme-less);--kbq-tree-multiple-states-selected-container-background: var(--kbq-background-contrast-less);--kbq-tree-states-selected-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-selected-hover-container-background: var(--kbq-states-background-theme-less-hover);--kbq-tree-states-selected-active-container-background: var(--kbq-states-background-theme-less-active);--kbq-tree-multiple-states-selected-hover-container-background: var(--kbq-states-background-contrast-less-hover);--kbq-tree-multiple-states-selected-active-container-background: var(--kbq-states-background-contrast-less-active);--kbq-tree-states-selected-hover-text-color: var(--kbq-foreground-contrast);--kbq-tree-states-selected-hover-icon-color: var(--kbq-icon-contrast);--kbq-tree-states-selected-hover-tree-toggle-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-action-button-color: var(--kbq-icon-contrast-fade);--kbq-tree-states-selected-hover-caption-color: var(--kbq-foreground-contrast-secondary);--kbq-tree-states-disabled-container-background: transparent;--kbq-tree-states-disabled-text-color: var(--kbq-states-foreground-disabled);--kbq-tree-states-disabled-icon-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-tree-toggle-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-action-button-color: var(--kbq-states-icon-disabled);--kbq-tree-states-disabled-caption-color: var(--kbq-states-foreground-disabled)}\n"] }]
3211
+ }], ctorParameters: () => [], propDecorators: { ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-label", required: false }] }], ariaLabelledby: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-labelledby", required: false }] }], selectAllOption: [{ type: i0.ViewChild, args: [i0.forwardRef(() => KbqTreeOption), { isSignal: true }] }], unorderedOptionsQuery: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => KbqTreeOption), { isSignal: true }] }], navigationChange: [{ type: i0.Output, args: ["navigationChange"] }], selectionChangeOutput: [{ type: i0.Output, args: ["selectionChange"] }], selectAllChange: [{ type: i0.Output, args: ["selectAllChange"] }], onSelectAll: [{ type: i0.Output, args: ["onSelectAll"] }], copyChangeOutput: [{ type: i0.Output, args: ["copyChange"] }], onCopyOutput: [{ type: i0.Output, args: ["onCopy"] }], autoSelectInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoSelect", required: false }] }], multipleInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], noUnselectLastInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "noUnselectLast", required: false }] }], typeAheadInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "typeAhead", required: false }] }], selectAllToggle: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectAllToggle", required: false }] }], selectAllInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectAll", required: false }] }], disabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], tabIndexInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabIndex", required: false }] }], selectAllHandlerInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectAllHandler", required: false }] }] } });
2129
3212
 
2130
3213
  const KBQ_TREE_DIRECTIVES = [
2131
3214
  KbqTreeNodeOutlet,
@@ -2139,8 +3222,8 @@ const KBQ_TREE_DIRECTIVES = [
2139
3222
  KbqTreeNodeToggleDirective
2140
3223
  ];
2141
3224
  class KbqTreeModule {
2142
- /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqTreeModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
2143
- /** @nocollapse */ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.30", ngImport: i0, type: KbqTreeModule, imports: [KbqPseudoCheckboxModule,
3225
+ /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqTreeModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
3226
+ /** @nocollapse */ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.25", ngImport: i0, type: KbqTreeModule, imports: [KbqPseudoCheckboxModule,
2144
3227
  KbqIconModule,
2145
3228
  KbqActionContainer, KbqTreeNodeOutlet,
2146
3229
  KbqTreeNodeDef,
@@ -2159,13 +3242,13 @@ class KbqTreeModule {
2159
3242
  KbqTreeOption,
2160
3243
  KbqTreeNodeToggleComponent,
2161
3244
  KbqTreeNodeToggleDirective] }); }
2162
- /** @nocollapse */ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqTreeModule, providers: [{ provide: AsyncScheduler, useValue: asyncScheduler }], imports: [KbqPseudoCheckboxModule,
3245
+ /** @nocollapse */ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqTreeModule, providers: [{ provide: AsyncScheduler, useValue: asyncScheduler }], imports: [KbqPseudoCheckboxModule,
2163
3246
  KbqIconModule,
2164
3247
  KbqActionContainer, KbqTreeSelection,
2165
3248
  KbqTreeOption,
2166
3249
  KbqTreeNodeToggleComponent] }); }
2167
3250
  }
2168
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqTreeModule, decorators: [{
3251
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqTreeModule, decorators: [{
2169
3252
  type: NgModule,
2170
3253
  args: [{
2171
3254
  imports: [