@koobiq/components 21.0.0 → 21.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (378) hide show
  1. package/badge/_badge-theme.scss +31 -0
  2. package/breadcrumbs/breadcrumbs.scss +5 -1
  3. package/checkbox/_checkbox-theme.scss +0 -17
  4. package/checkbox/checkbox-tokens.scss +0 -4
  5. package/code-block/_code-block-theme.scss +7 -6
  6. package/code-block/code-block-tokens.scss +8 -4
  7. package/code-block/code-block.scss +54 -32
  8. package/content-panel/content-panel-header.scss +2 -3
  9. package/content-panel/content-panel.scss +3 -0
  10. package/core/selection/pseudo-checkbox/pseudo-checkbox-tokens.scss +0 -2
  11. package/fesm2022/koobiq-components-accordion.mjs +4 -4
  12. package/fesm2022/koobiq-components-accordion.mjs.map +1 -1
  13. package/fesm2022/koobiq-components-actions-panel.mjs +10 -2
  14. package/fesm2022/koobiq-components-actions-panel.mjs.map +1 -1
  15. package/fesm2022/koobiq-components-app-switcher.mjs +1 -1
  16. package/fesm2022/koobiq-components-app-switcher.mjs.map +1 -1
  17. package/fesm2022/koobiq-components-badge.mjs +2 -2
  18. package/fesm2022/koobiq-components-badge.mjs.map +1 -1
  19. package/fesm2022/koobiq-components-breadcrumbs.mjs +2 -2
  20. package/fesm2022/koobiq-components-breadcrumbs.mjs.map +1 -1
  21. package/fesm2022/koobiq-components-button-toggle.mjs +1 -1
  22. package/fesm2022/koobiq-components-button-toggle.mjs.map +1 -1
  23. package/fesm2022/koobiq-components-checkbox.mjs +18 -8
  24. package/fesm2022/koobiq-components-checkbox.mjs.map +1 -1
  25. package/fesm2022/koobiq-components-clamped-text.mjs +78 -10
  26. package/fesm2022/koobiq-components-clamped-text.mjs.map +1 -1
  27. package/fesm2022/koobiq-components-code-block.mjs +106 -394
  28. package/fesm2022/koobiq-components-code-block.mjs.map +1 -1
  29. package/fesm2022/koobiq-components-content-panel.mjs +4 -4
  30. package/fesm2022/koobiq-components-content-panel.mjs.map +1 -1
  31. package/fesm2022/koobiq-components-core.mjs +300 -37
  32. package/fesm2022/koobiq-components-core.mjs.map +1 -1
  33. package/fesm2022/koobiq-components-datepicker.mjs +151 -60
  34. package/fesm2022/koobiq-components-datepicker.mjs.map +1 -1
  35. package/fesm2022/koobiq-components-divider.mjs +3 -3
  36. package/fesm2022/koobiq-components-divider.mjs.map +1 -1
  37. package/fesm2022/koobiq-components-dropdown.mjs +3 -3
  38. package/fesm2022/koobiq-components-dropdown.mjs.map +1 -1
  39. package/fesm2022/koobiq-components-file-upload.mjs +17 -8
  40. package/fesm2022/koobiq-components-file-upload.mjs.map +1 -1
  41. package/fesm2022/koobiq-components-filter-bar.mjs +124 -41
  42. package/fesm2022/koobiq-components-filter-bar.mjs.map +1 -1
  43. package/fesm2022/koobiq-components-flag.mjs +3 -3
  44. package/fesm2022/koobiq-components-flag.mjs.map +1 -1
  45. package/fesm2022/koobiq-components-form-field.mjs +90 -27
  46. package/fesm2022/koobiq-components-form-field.mjs.map +1 -1
  47. package/fesm2022/koobiq-components-icon.mjs +38 -17
  48. package/fesm2022/koobiq-components-icon.mjs.map +1 -1
  49. package/fesm2022/koobiq-components-inline-edit.mjs +19 -2
  50. package/fesm2022/koobiq-components-inline-edit.mjs.map +1 -1
  51. package/fesm2022/koobiq-components-input.mjs +76 -17
  52. package/fesm2022/koobiq-components-input.mjs.map +1 -1
  53. package/fesm2022/koobiq-components-list.mjs +1 -1
  54. package/fesm2022/koobiq-components-list.mjs.map +1 -1
  55. package/fesm2022/koobiq-components-modal.mjs +3 -3
  56. package/fesm2022/koobiq-components-modal.mjs.map +1 -1
  57. package/fesm2022/koobiq-components-navbar.mjs +86 -25
  58. package/fesm2022/koobiq-components-navbar.mjs.map +1 -1
  59. package/fesm2022/koobiq-components-notification-center.mjs +4 -4
  60. package/fesm2022/koobiq-components-notification-center.mjs.map +1 -1
  61. package/fesm2022/koobiq-components-overflow-items.mjs +116 -38
  62. package/fesm2022/koobiq-components-overflow-items.mjs.map +1 -1
  63. package/fesm2022/koobiq-components-popover.mjs +86 -7
  64. package/fesm2022/koobiq-components-popover.mjs.map +1 -1
  65. package/fesm2022/koobiq-components-radio.mjs +41 -19
  66. package/fesm2022/koobiq-components-radio.mjs.map +1 -1
  67. package/fesm2022/koobiq-components-search-expandable.mjs +29 -17
  68. package/fesm2022/koobiq-components-search-expandable.mjs.map +1 -1
  69. package/fesm2022/koobiq-components-select.mjs +49 -12
  70. package/fesm2022/koobiq-components-select.mjs.map +1 -1
  71. package/fesm2022/koobiq-components-sidepanel.mjs +198 -186
  72. package/fesm2022/koobiq-components-sidepanel.mjs.map +1 -1
  73. package/fesm2022/koobiq-components-splitter.mjs +49 -25
  74. package/fesm2022/koobiq-components-splitter.mjs.map +1 -1
  75. package/fesm2022/koobiq-components-tabs.mjs +30 -11
  76. package/fesm2022/koobiq-components-tabs.mjs.map +1 -1
  77. package/fesm2022/koobiq-components-tags.mjs +1 -1
  78. package/fesm2022/koobiq-components-tags.mjs.map +1 -1
  79. package/fesm2022/koobiq-components-textarea.mjs +28 -11
  80. package/fesm2022/koobiq-components-textarea.mjs.map +1 -1
  81. package/fesm2022/koobiq-components-time-range.mjs +2 -2
  82. package/fesm2022/koobiq-components-time-range.mjs.map +1 -1
  83. package/fesm2022/koobiq-components-timepicker.mjs +71 -16
  84. package/fesm2022/koobiq-components-timepicker.mjs.map +1 -1
  85. package/fesm2022/koobiq-components-timezone.mjs +2 -2
  86. package/fesm2022/koobiq-components-timezone.mjs.map +1 -1
  87. package/fesm2022/koobiq-components-toast.mjs +2 -2
  88. package/fesm2022/koobiq-components-toast.mjs.map +1 -1
  89. package/fesm2022/koobiq-components-toggle.mjs +25 -9
  90. package/fesm2022/koobiq-components-toggle.mjs.map +1 -1
  91. package/fesm2022/koobiq-components-tooltip.mjs +90 -17
  92. package/fesm2022/koobiq-components-tooltip.mjs.map +1 -1
  93. package/fesm2022/koobiq-components-top-bar.mjs +27 -7
  94. package/fesm2022/koobiq-components-top-bar.mjs.map +1 -1
  95. package/fesm2022/koobiq-components-tree-select.mjs +24 -9
  96. package/fesm2022/koobiq-components-tree-select.mjs.map +1 -1
  97. package/fesm2022/koobiq-components-tree.mjs +288 -109
  98. package/fesm2022/koobiq-components-tree.mjs.map +1 -1
  99. package/file-upload/_file-upload-theme.scss +0 -12
  100. package/file-upload/file-upload-tokens.scss +0 -1
  101. package/file-upload/file-upload.scss +0 -1
  102. package/filter-bar/_filter-bar-theme.scss +7 -8
  103. package/filter-bar/filter-bar.scss +0 -1
  104. package/filter-bar/pipes/base-pipe.scss +36 -2
  105. package/filter-bar/pipes/pipe-multi-tree-select.scss +27 -0
  106. package/form-field/_fieldset-theme.scss +2 -7
  107. package/form-field/_form-field-theme.scss +9 -22
  108. package/form-field/_hint-theme.scss +20 -0
  109. package/form-field/fieldset-tokens.scss +0 -1
  110. package/form-field/fieldset.scss +0 -3
  111. package/form-field/form-field-tokens.scss +1 -1
  112. package/form-field/form-field.scss +9 -0
  113. package/form-field/hint-tokens.scss +3 -0
  114. package/modal/modal.scss +2 -0
  115. package/navbar/_navbar-item_vertical.scss +48 -2
  116. package/navbar/_navbar-theme.scss +11 -3
  117. package/navbar/navbar-item.scss +17 -0
  118. package/navbar/navbar-tokens.scss +3 -0
  119. package/package.json +4 -4
  120. package/popover/popover.scss +1 -1
  121. package/radio/_radio-theme.scss +0 -30
  122. package/radio/radio-tokens.scss +0 -2
  123. package/schematics/collection.json +94 -89
  124. package/schematics/migrations/accordion-state-saving-default/{index.js → index.cjs} +5 -4
  125. package/schematics/migrations/actions-panel-overlay-container/{index.js → index.cjs} +5 -4
  126. package/schematics/migrations/alert-signals/{index.js → index.cjs} +14 -13
  127. package/schematics/migrations/angular-animations-removal/index.cjs +21 -0
  128. package/schematics/migrations/app-switcher-signals/{index.js → index.cjs} +7 -6
  129. package/schematics/migrations/autocomplete-panel-width-auto/{index.js → index.cjs} +6 -5
  130. package/schematics/migrations/autocomplete-signals/{index.js → index.cjs} +7 -6
  131. package/schematics/migrations/badge-signals/{index.js → index.cjs} +7 -6
  132. package/schematics/migrations/button-state-and-styles/{index.js → index.cjs} +7 -6
  133. package/schematics/migrations/button-supported-colors/{index.js → index.cjs} +7 -6
  134. package/schematics/migrations/button-toggle-signals-and-aria/{index.js → index.cjs} +7 -6
  135. package/schematics/migrations/button-truncation/{index.js → index.cjs} +7 -6
  136. package/schematics/migrations/checkbox-signals/{index.js → index.cjs} +9 -8
  137. package/schematics/migrations/clamped-text-disclosure/{index.js → index.cjs} +5 -4
  138. package/schematics/migrations/code-block-highlight-js-core/README.md +53 -0
  139. package/schematics/migrations/code-block-highlight-js-core/data.cjs +64 -0
  140. package/schematics/migrations/code-block-highlight-js-core/index.cjs +319 -0
  141. package/schematics/migrations/code-block-highlight-js-core/schema.json +20 -0
  142. package/schematics/migrations/code-block-signals/{index.js → index.cjs} +7 -6
  143. package/schematics/migrations/color-signals/index.cjs +20 -0
  144. package/schematics/migrations/core-mixins-removal/index.cjs +18 -0
  145. package/schematics/migrations/css-selectors/{index.js → index.cjs} +4 -3
  146. package/schematics/migrations/datepicker-signals/index.cjs +18 -0
  147. package/schematics/migrations/deprecated-icons/README.md +21 -5
  148. package/schematics/migrations/deprecated-icons/{index.js → index.cjs} +15 -28
  149. package/schematics/migrations/deprecated-icons/schema.json +1 -1
  150. package/schematics/migrations/design-tokens-v4/{index.js → index.cjs} +3 -2
  151. package/schematics/migrations/divider-signals-and-aria/{index.js → index.cjs} +5 -4
  152. package/schematics/migrations/dl-attribute-coercion/{index.js → index.cjs} +7 -6
  153. package/schematics/migrations/dl-standalone-names/{index.js → index.cjs} +11 -10
  154. package/schematics/migrations/dropdown-demote-overlay/{index.js → index.cjs} +7 -6
  155. package/schematics/migrations/dropdown-signals/index.cjs +20 -0
  156. package/schematics/migrations/empty-state-error-color/{index.js → index.cjs} +5 -4
  157. package/schematics/migrations/empty-state-size-attr/{index.js → index.cjs} +6 -5
  158. package/schematics/migrations/file-upload-cva-and-primitives/{index.js → index.cjs} +5 -4
  159. package/schematics/migrations/file-upload-deprecated-outputs/{index.js → index.cjs} +5 -4
  160. package/schematics/migrations/filter-bar-rename-action/{index.js → index.cjs} +5 -4
  161. package/schematics/migrations/filter-bar-signals/{index.js → index.cjs} +16 -15
  162. package/schematics/migrations/filter-bar-state-saving-default/{index.js → index.cjs} +5 -4
  163. package/schematics/migrations/flag-inner-html/{index.js → index.cjs} +5 -4
  164. package/schematics/migrations/form-field-signals/{index.js → index.cjs} +18 -17
  165. package/schematics/migrations/icon-semantics-and-api/{data.js → data.cjs} +4 -4
  166. package/schematics/migrations/icon-semantics-and-api/{index.js → index.cjs} +6 -5
  167. package/schematics/migrations/icons-replacement/README.md +16 -2
  168. package/schematics/migrations/icons-replacement/{index.js → index.cjs} +21 -18
  169. package/schematics/migrations/icons-replacement/schema.json +12 -3
  170. package/schematics/migrations/inline-edit-a11y-and-types/{index.js → index.cjs} +5 -4
  171. package/schematics/migrations/input-number-surface/{index.js → index.cjs} +5 -4
  172. package/schematics/migrations/input-signals/index.cjs +18 -0
  173. package/schematics/migrations/link-deprecated-path/{index.js → index.cjs} +4 -3
  174. package/schematics/migrations/link-signals/{index.js → index.cjs} +5 -4
  175. package/schematics/migrations/list-signals/index.cjs +18 -0
  176. package/schematics/migrations/list-tree-multiple-input/{index.js → index.cjs} +7 -6
  177. package/schematics/migrations/loader-overlay-signals/{index.js → index.cjs} +7 -6
  178. package/schematics/migrations/loader-overlay-size-attr/{index.js → index.cjs} +6 -5
  179. package/schematics/migrations/locale-configuration-providers/{index.js → index.cjs} +5 -4
  180. package/schematics/migrations/mandatory-peer-dependencies/{index.js → index.cjs} +3 -2
  181. package/schematics/migrations/markdown-signals/{index.js → index.cjs} +7 -6
  182. package/schematics/migrations/modal-dialog-semantics/{index.js → index.cjs} +5 -4
  183. package/schematics/migrations/modal-signals/index.cjs +20 -0
  184. package/schematics/migrations/navbar-signals-and-aria/{index.js → index.cjs} +7 -6
  185. package/schematics/migrations/new-icons-pack/README.md +37 -25
  186. package/schematics/migrations/new-icons-pack/{index.js → index.cjs} +29 -38
  187. package/schematics/migrations/new-icons-pack/replacement.json +2 -14
  188. package/schematics/migrations/new-icons-pack/schema.json +3 -3
  189. package/schematics/migrations/notification-center-signals/{index.js → index.cjs} +5 -4
  190. package/schematics/migrations/option-signals/index.cjs +20 -0
  191. package/schematics/migrations/popover-leave-delay/{index.js → index.cjs} +5 -4
  192. package/schematics/migrations/progress-bar-percentage-and-aria/{index.js → index.cjs} +5 -4
  193. package/schematics/migrations/progress-spinner-signals/{index.js → index.cjs} +7 -6
  194. package/schematics/migrations/query-list-signals/index.cjs +18 -0
  195. package/schematics/migrations/radio-signals-and-aria/{index.js → index.cjs} +9 -8
  196. package/schematics/migrations/read-state-dwell-handlers/{index.js → index.cjs} +5 -4
  197. package/schematics/migrations/scrollbar-deprecated-path/{index.js → index.cjs} +4 -3
  198. package/schematics/migrations/select-signal-inputs/{index.js → index.cjs} +5 -4
  199. package/schematics/migrations/sidepanel-non-modal-behavior/{index.js → index.cjs} +5 -4
  200. package/schematics/migrations/signal-inputs-subclasses/index.cjs +18 -0
  201. package/schematics/migrations/split-button-optional-disabled/{index.js → index.cjs} +5 -4
  202. package/schematics/migrations/splitter-deprecated-path/{index.js → index.cjs} +4 -3
  203. package/schematics/migrations/state-saving-default/{index.js → index.cjs} +5 -4
  204. package/schematics/migrations/table-cell-content/{index.js → index.cjs} +5 -4
  205. package/schematics/migrations/tabs-signals-and-aria/{index.js → index.cjs} +5 -4
  206. package/schematics/migrations/tag-list-cleaner/{index.js → index.cjs} +7 -6
  207. package/schematics/migrations/tag-slots/{index.js → index.cjs} +6 -5
  208. package/schematics/migrations/tags-signals/{index.js → index.cjs} +7 -6
  209. package/schematics/migrations/textarea-signals/{index.js → index.cjs} +7 -6
  210. package/schematics/migrations/time-range-title-for/{index.js → index.cjs} +5 -4
  211. package/schematics/migrations/timepicker-signals/{index.js → index.cjs} +7 -6
  212. package/schematics/migrations/timezone-grouping-utils/{index.js → index.cjs} +5 -4
  213. package/schematics/migrations/title-encapsulation/{index.js → index.cjs} +5 -4
  214. package/schematics/migrations/toast-stack-and-defaults/{index.js → index.cjs} +5 -4
  215. package/schematics/migrations/tooltip-pointer-events-and-types/{index.js → index.cjs} +5 -4
  216. package/schematics/migrations/top-bar-container-selectors/{index.js → index.cjs} +5 -4
  217. package/schematics/migrations/tree-select-signals/{index.js → index.cjs} +5 -4
  218. package/schematics/migrations/tree-signals/{index.js → index.cjs} +5 -4
  219. package/schematics/migrations/tree-state-saving-default/{index.js → index.cjs} +5 -4
  220. package/schematics/migrations/username-pipe-injection/{index.js → index.cjs} +5 -4
  221. package/schematics/migrations/v20-upgrade/{data.js → data.cjs} +7 -7
  222. package/schematics/migrations/v20-upgrade/index.cjs +19 -0
  223. package/schematics/migrations/v21-upgrade/{data.js → data.cjs} +22 -22
  224. package/schematics/migrations/v21-upgrade/{index.js → index.cjs} +11 -10
  225. package/schematics/migrations/zoneless-change-detection/index.cjs +21 -0
  226. package/schematics/migrations.json +87 -82
  227. package/schematics/ng-add/{index.js → index.cjs} +15 -289
  228. package/schematics/utils/{angular-parsing.js → angular-parsing.cjs} +2 -2
  229. package/schematics/utils/custom-data.cjs +64 -0
  230. package/schematics/utils/{deprecated-path-migration.js → deprecated-path-migration.cjs} +4 -3
  231. package/schematics/utils/html-config.cjs +148 -0
  232. package/schematics/utils/{icon-migration.js → icon-migration.cjs} +11 -5
  233. package/schematics/utils/list-item-pattern.cjs +16 -0
  234. package/schematics/utils/{messages.js → messages.cjs} +4 -0
  235. package/schematics/utils/package-config.cjs +99 -0
  236. package/schematics/utils/project-files.cjs +25 -0
  237. package/schematics/utils/replacement-driver.cjs +337 -0
  238. package/schematics/utils/safe-rule.cjs +23 -0
  239. package/schematics/utils/signal-members-migration.cjs +779 -0
  240. package/schematics/utils/tag-patterns.cjs +21 -0
  241. package/schematics/utils/template-ref-access.cjs +155 -0
  242. package/schematics/utils/{typescript.js → typescript.cjs} +1 -1
  243. package/schematics/utils/warn-only-migration.cjs +52 -0
  244. package/schematics/utils/workspace-styles.cjs +123 -0
  245. package/select/select.scss +7 -0
  246. package/tabs/_tabs-common.scss +23 -0
  247. package/textarea/textarea-tokens.scss +4 -1
  248. package/toast/toast.component.scss +1 -0
  249. package/toggle/_toggle-theme.scss +0 -17
  250. package/tooltip/tooltip.scss +1 -1
  251. package/top-bar/top-bar-tokens.scss +1 -0
  252. package/top-bar/top-bar.scss +10 -0
  253. package/types/koobiq-components-accordion.d.ts +25 -0
  254. package/types/koobiq-components-button-toggle.d.ts +6 -0
  255. package/types/koobiq-components-checkbox.d.ts +30 -0
  256. package/types/koobiq-components-clamped-text.d.ts +16 -3
  257. package/types/koobiq-components-code-block.d.ts +55 -14
  258. package/types/koobiq-components-core.d.ts +226 -13
  259. package/types/koobiq-components-datepicker.d.ts +28 -1
  260. package/types/koobiq-components-divider.d.ts +28 -10
  261. package/types/koobiq-components-dropdown.d.ts +19 -0
  262. package/types/koobiq-components-filter-bar.d.ts +79 -6
  263. package/types/koobiq-components-flag.d.ts +18 -0
  264. package/types/koobiq-components-form-field.d.ts +87 -6
  265. package/types/koobiq-components-icon.d.ts +15 -0
  266. package/types/koobiq-components-inline-edit.d.ts +8 -1
  267. package/types/koobiq-components-input.d.ts +22 -3
  268. package/types/koobiq-components-list.d.ts +6 -0
  269. package/types/koobiq-components-modal.d.ts +7 -0
  270. package/types/koobiq-components-navbar.d.ts +71 -7
  271. package/types/koobiq-components-notification-center.d.ts +13 -0
  272. package/types/koobiq-components-overflow-items.d.ts +26 -2
  273. package/types/koobiq-components-popover.d.ts +38 -3
  274. package/types/koobiq-components-radio.d.ts +30 -0
  275. package/types/koobiq-components-search-expandable.d.ts +10 -0
  276. package/types/koobiq-components-select.d.ts +36 -4
  277. package/types/koobiq-components-sidepanel.d.ts +52 -1
  278. package/types/koobiq-components-splitter.d.ts +13 -4
  279. package/types/koobiq-components-tabs.d.ts +4 -0
  280. package/types/koobiq-components-tags.d.ts +6 -0
  281. package/types/koobiq-components-textarea.d.ts +9 -2
  282. package/types/koobiq-components-timepicker.d.ts +15 -0
  283. package/types/koobiq-components-toggle.d.ts +30 -0
  284. package/types/koobiq-components-tooltip.d.ts +55 -10
  285. package/types/koobiq-components-top-bar.d.ts +11 -3
  286. package/types/koobiq-components-tree-select.d.ts +23 -8
  287. package/types/koobiq-components-tree.d.ts +144 -60
  288. package/schematics/migrations/angular-animations-removal/index.js +0 -20
  289. package/schematics/migrations/color-signals/index.js +0 -19
  290. package/schematics/migrations/core-mixins-removal/index.js +0 -17
  291. package/schematics/migrations/datepicker-signals/index.js +0 -17
  292. package/schematics/migrations/dropdown-signals/index.js +0 -19
  293. package/schematics/migrations/input-signals/index.js +0 -17
  294. package/schematics/migrations/list-signals/index.js +0 -17
  295. package/schematics/migrations/modal-signals/index.js +0 -19
  296. package/schematics/migrations/option-signals/index.js +0 -19
  297. package/schematics/migrations/query-list-signals/index.js +0 -17
  298. package/schematics/migrations/signal-inputs-subclasses/index.js +0 -17
  299. package/schematics/migrations/v20-upgrade/index.js +0 -18
  300. package/schematics/migrations/zoneless-change-detection/index.js +0 -20
  301. package/schematics/utils/package-config.js +0 -13
  302. /package/schematics/migrations/accordion-state-saving-default/{data.js → data.cjs} +0 -0
  303. /package/schematics/migrations/actions-panel-overlay-container/{data.js → data.cjs} +0 -0
  304. /package/schematics/migrations/alert-signals/{data.js → data.cjs} +0 -0
  305. /package/schematics/migrations/angular-animations-removal/{data.js → data.cjs} +0 -0
  306. /package/schematics/migrations/app-switcher-signals/{data.js → data.cjs} +0 -0
  307. /package/schematics/migrations/autocomplete-signals/{data.js → data.cjs} +0 -0
  308. /package/schematics/migrations/badge-signals/{data.js → data.cjs} +0 -0
  309. /package/schematics/migrations/button-state-and-styles/{data.js → data.cjs} +0 -0
  310. /package/schematics/migrations/button-supported-colors/{data.js → data.cjs} +0 -0
  311. /package/schematics/migrations/button-toggle-signals-and-aria/{data.js → data.cjs} +0 -0
  312. /package/schematics/migrations/button-truncation/{data.js → data.cjs} +0 -0
  313. /package/schematics/migrations/checkbox-signals/{data.js → data.cjs} +0 -0
  314. /package/schematics/migrations/clamped-text-disclosure/{data.js → data.cjs} +0 -0
  315. /package/schematics/migrations/code-block-signals/{data.js → data.cjs} +0 -0
  316. /package/schematics/migrations/color-signals/{data.js → data.cjs} +0 -0
  317. /package/schematics/migrations/core-mixins-removal/{data.js → data.cjs} +0 -0
  318. /package/schematics/migrations/css-selectors/{data.js → data.cjs} +0 -0
  319. /package/schematics/migrations/datepicker-signals/{data.js → data.cjs} +0 -0
  320. /package/schematics/migrations/deprecated-icons/{data.js → data.cjs} +0 -0
  321. /package/schematics/migrations/divider-signals-and-aria/{data.js → data.cjs} +0 -0
  322. /package/schematics/migrations/dl-attribute-coercion/{data.js → data.cjs} +0 -0
  323. /package/schematics/migrations/dl-standalone-names/{data.js → data.cjs} +0 -0
  324. /package/schematics/migrations/dropdown-demote-overlay/{data.js → data.cjs} +0 -0
  325. /package/schematics/migrations/dropdown-signals/{data.js → data.cjs} +0 -0
  326. /package/schematics/migrations/empty-state-error-color/{data.js → data.cjs} +0 -0
  327. /package/schematics/migrations/file-upload-cva-and-primitives/{data.js → data.cjs} +0 -0
  328. /package/schematics/migrations/file-upload-deprecated-outputs/{data.js → data.cjs} +0 -0
  329. /package/schematics/migrations/filter-bar-rename-action/{data.js → data.cjs} +0 -0
  330. /package/schematics/migrations/filter-bar-signals/{data.js → data.cjs} +0 -0
  331. /package/schematics/migrations/filter-bar-state-saving-default/{data.js → data.cjs} +0 -0
  332. /package/schematics/migrations/flag-inner-html/{data.js → data.cjs} +0 -0
  333. /package/schematics/migrations/form-field-signals/{data.js → data.cjs} +0 -0
  334. /package/schematics/migrations/icons-replacement/{data.js → data.cjs} +0 -0
  335. /package/schematics/migrations/inline-edit-a11y-and-types/{data.js → data.cjs} +0 -0
  336. /package/schematics/migrations/input-number-surface/{data.js → data.cjs} +0 -0
  337. /package/schematics/migrations/input-signals/{data.js → data.cjs} +0 -0
  338. /package/schematics/migrations/link-signals/{data.js → data.cjs} +0 -0
  339. /package/schematics/migrations/list-signals/{data.js → data.cjs} +0 -0
  340. /package/schematics/migrations/list-tree-multiple-input/{data.js → data.cjs} +0 -0
  341. /package/schematics/migrations/loader-overlay-signals/{data.js → data.cjs} +0 -0
  342. /package/schematics/migrations/locale-configuration-providers/{data.js → data.cjs} +0 -0
  343. /package/schematics/migrations/markdown-signals/{data.js → data.cjs} +0 -0
  344. /package/schematics/migrations/modal-dialog-semantics/{data.js → data.cjs} +0 -0
  345. /package/schematics/migrations/modal-signals/{data.js → data.cjs} +0 -0
  346. /package/schematics/migrations/navbar-signals-and-aria/{data.js → data.cjs} +0 -0
  347. /package/schematics/migrations/new-icons-pack/{data.js → data.cjs} +0 -0
  348. /package/schematics/migrations/notification-center-signals/{data.js → data.cjs} +0 -0
  349. /package/schematics/migrations/option-signals/{data.js → data.cjs} +0 -0
  350. /package/schematics/migrations/popover-leave-delay/{data.js → data.cjs} +0 -0
  351. /package/schematics/migrations/progress-bar-percentage-and-aria/{data.js → data.cjs} +0 -0
  352. /package/schematics/migrations/progress-spinner-signals/{data.js → data.cjs} +0 -0
  353. /package/schematics/migrations/query-list-signals/{data.js → data.cjs} +0 -0
  354. /package/schematics/migrations/radio-signals-and-aria/{data.js → data.cjs} +0 -0
  355. /package/schematics/migrations/read-state-dwell-handlers/{data.js → data.cjs} +0 -0
  356. /package/schematics/migrations/select-signal-inputs/{data.js → data.cjs} +0 -0
  357. /package/schematics/migrations/sidepanel-non-modal-behavior/{data.js → data.cjs} +0 -0
  358. /package/schematics/migrations/signal-inputs-subclasses/{data.js → data.cjs} +0 -0
  359. /package/schematics/migrations/split-button-optional-disabled/{data.js → data.cjs} +0 -0
  360. /package/schematics/migrations/state-saving-default/{data.js → data.cjs} +0 -0
  361. /package/schematics/migrations/table-cell-content/{data.js → data.cjs} +0 -0
  362. /package/schematics/migrations/tabs-signals-and-aria/{data.js → data.cjs} +0 -0
  363. /package/schematics/migrations/tag-list-cleaner/{data.js → data.cjs} +0 -0
  364. /package/schematics/migrations/tags-signals/{data.js → data.cjs} +0 -0
  365. /package/schematics/migrations/textarea-signals/{data.js → data.cjs} +0 -0
  366. /package/schematics/migrations/time-range-title-for/{data.js → data.cjs} +0 -0
  367. /package/schematics/migrations/timepicker-signals/{data.js → data.cjs} +0 -0
  368. /package/schematics/migrations/timezone-grouping-utils/{data.js → data.cjs} +0 -0
  369. /package/schematics/migrations/title-encapsulation/{data.js → data.cjs} +0 -0
  370. /package/schematics/migrations/toast-stack-and-defaults/{data.js → data.cjs} +0 -0
  371. /package/schematics/migrations/tooltip-pointer-events-and-types/{data.js → data.cjs} +0 -0
  372. /package/schematics/migrations/top-bar-container-selectors/{data.js → data.cjs} +0 -0
  373. /package/schematics/migrations/tree-select-signals/{data.js → data.cjs} +0 -0
  374. /package/schematics/migrations/tree-signals/{data.js → data.cjs} +0 -0
  375. /package/schematics/migrations/tree-state-saving-default/{data.js → data.cjs} +0 -0
  376. /package/schematics/migrations/username-pipe-injection/{data.js → data.cjs} +0 -0
  377. /package/schematics/migrations/zoneless-change-detection/{data.js → data.cjs} +0 -0
  378. /package/schematics/utils/{ast.js → ast.cjs} +0 -0
@@ -2,9 +2,9 @@ import { SelectionModel, DataSource } from '@angular/cdk/collections';
2
2
  import { BehaviorSubject, merge, Observable, of, Subject, asyncScheduler } from 'rxjs';
3
3
  import * as i1 from '@koobiq/components/core';
4
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 } from 'rxjs/operators';
5
+ import { take, map, delay, filter } from 'rxjs/operators';
6
6
  import * as i0 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, contentChild, linkedSignal, output, EventEmitter, afterNextRender, Renderer2, forwardRef, Injector, QueryList, 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';
8
8
  import { Directionality } from '@angular/cdk/bidi';
9
9
  import { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';
10
10
  import { takeUntilDestroyed, toSignal, outputFromObservable } from '@angular/core/rxjs-interop';
@@ -21,39 +21,53 @@ import { AsyncScheduler } from 'rxjs/internal/scheduler/AsyncScheduler';
21
21
  /** Base tree control. It has basic toggle/expand/collapse operations on a single data node. */
22
22
  class BaseTreeControl {
23
23
  constructor() {
24
- /** 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. */
25
25
  this.expansionModel = new SelectionModel(true);
26
26
  this.filterModel = new SelectionModel(true);
27
+ /**
28
+ * Stream with the filter query or result. Published for backward compatibility.
29
+ *
30
+ * @deprecated Use `filterQuery` for the query string and `filterModel` for the filter state. Will be removed in 22.0.0.
31
+ */
27
32
  this.filterValue = new BehaviorSubject('');
33
+ /**
34
+ * The query of the active filter, or `null` when no filter is active. Defaults to `null`.
35
+ * Set by `FlatTreeControl.applyFilter`; stays `null` on controls without filtering, such as `NestedTreeControl`.
36
+ */
37
+ this.filterQuery = null;
38
+ }
39
+ /** Whether a filter is active: the filter model holds at least one node, or a query is set. */
40
+ get hasActiveFilter() {
41
+ return this.filterModel.selected.length > 0 || this.filterQuery != null;
28
42
  }
29
43
  /** Toggles one single data node's expanded/collapsed state. */
30
44
  toggle(dataNode) {
31
- if (this.filterValue.value?.length) {
45
+ if (this.hasActiveFilter) {
32
46
  return;
33
47
  }
34
- this.expansionModel.toggle(dataNode);
48
+ this.expansionModel.toggle(this.expansionKey(dataNode));
35
49
  }
36
50
  /** Expands one single data node. */
37
51
  expand(dataNode) {
38
- if (this.filterValue.value?.length) {
52
+ if (this.hasActiveFilter) {
39
53
  return;
40
54
  }
41
- this.expansionModel.select(dataNode);
55
+ this.expansionModel.select(this.expansionKey(dataNode));
42
56
  }
43
57
  /** Collapses one single data node. */
44
58
  collapse(dataNode) {
45
- if (this.filterValue.value?.length) {
59
+ if (this.hasActiveFilter) {
46
60
  return;
47
61
  }
48
- this.expansionModel.deselect(dataNode);
62
+ this.expansionModel.deselect(this.expansionKey(dataNode));
49
63
  }
50
64
  /** Whether a given data node is expanded or not. Returns true if the data node is expanded. */
51
65
  isExpanded(dataNode) {
52
- return this.expansionModel.isSelected(dataNode);
66
+ return this.expansionModel.isSelected(this.expansionKey(dataNode));
53
67
  }
54
68
  /** Toggles a subtree rooted at `node` recursively. */
55
69
  toggleDescendants(dataNode) {
56
- if (this.expansionModel.isSelected(dataNode)) {
70
+ if (this.isExpanded(dataNode)) {
57
71
  this.collapseDescendants(dataNode);
58
72
  }
59
73
  else {
@@ -68,32 +82,39 @@ class BaseTreeControl {
68
82
  expandDescendants(dataNode) {
69
83
  const toBeProcessed = [dataNode];
70
84
  toBeProcessed.push(...this.getDescendants(dataNode));
71
- this.expansionModel.select(...toBeProcessed);
85
+ this.expansionModel.select(...toBeProcessed.map((node) => this.expansionKey(node)));
72
86
  }
73
87
  /** Collapses a subtree rooted at given data node recursively. */
74
88
  collapseDescendants(dataNode) {
75
89
  const toBeProcessed = [dataNode];
76
90
  toBeProcessed.push(...this.getDescendants(dataNode));
77
- this.expansionModel.deselect(...toBeProcessed);
91
+ this.expansionModel.deselect(...toBeProcessed.map((node) => this.expansionKey(node)));
92
+ }
93
+ /** The key `expansionModel` holds for a data node. */
94
+ expansionKey(dataNode) {
95
+ return this.trackBy ? this.trackBy(dataNode) : dataNode;
78
96
  }
79
97
  }
80
98
 
81
99
  const kbqTreeSelectAllValue = 'selectAll';
82
100
  /**
83
101
  * Default first stage of the filter pipeline: keeps the nodes whose view value matches the query.
102
+ * An optional `matches` predicate keeps a node matched by anything else, e.g. by another field.
84
103
  *
85
104
  * @docs-private
86
105
  */
87
106
  class FilterByViewValue {
88
- constructor(control) {
107
+ constructor(control, matches) {
89
108
  this.control = control;
109
+ this.matches = matches;
90
110
  }
91
111
  handle(value) {
92
112
  const viewValue = value || null;
93
113
  this.result = this.control.dataNodes.filter((node) => {
94
114
  if (node['value'] === kbqTreeSelectAllValue)
95
115
  return true;
96
- return this.control.compareViewValues(this.control.getViewValue(node), viewValue);
116
+ return (this.control.compareViewValues(this.control.getViewValue(node), viewValue) ||
117
+ !!this.matches?.(node, viewValue));
97
118
  });
98
119
  if (this.result.length === 1 && this.result[0]['value'] === kbqTreeSelectAllValue) {
99
120
  this.result.pop();
@@ -161,7 +182,9 @@ class FlatTreeControl extends BaseTreeControl {
161
182
  /** compareValues will be used to comparing values. */
162
183
  compareViewValues = defaultCompareViewValues,
163
184
  /** isDisabled will be used to determine if the node is disabled. */
164
- isDisabled = () => false) {
185
+ isDisabled = () => false,
186
+ /** Further options: the `trackBy` the nodes are expanded by. */
187
+ options) {
165
188
  super();
166
189
  this.getLevel = getLevel;
167
190
  this.isExpandable = isExpandable;
@@ -170,6 +193,11 @@ class FlatTreeControl extends BaseTreeControl {
170
193
  this.compareValues = compareValues;
171
194
  this.compareViewValues = compareViewValues;
172
195
  this.isDisabled = isDisabled;
196
+ this.expandedItemsBeforeFiltration = [];
197
+ // Positions in each `dataNodes` array: a tree looks up every rendered row, and `indexOf` would make that
198
+ // rows × nodes. Keyed weakly by the array, so replacing `dataNodes` releases the old nodes.
199
+ this.nodeIndexes = new WeakMap();
200
+ this.trackBy = options?.trackBy;
173
201
  this.setFilters(new FilterByViewValue(this), new FilterParentsForNodes(this));
174
202
  }
175
203
  // TODO: nothing in the library uses it; kept as public API at the DS-2196 review. Document or deprecate it.
@@ -186,7 +214,7 @@ class FlatTreeControl extends BaseTreeControl {
186
214
  * with correct levels.
187
215
  */
188
216
  getDescendants(dataNode) {
189
- const startIndex = this.dataNodes.indexOf(dataNode);
217
+ const startIndex = this.indexOfNode(dataNode);
190
218
  const results = [];
191
219
  // Goes through flattened tree nodes in the `dataNodes` array, and get all descendants.
192
220
  // The level of descendants of a tree node must be greater than the level of the given
@@ -206,7 +234,7 @@ class FlatTreeControl extends BaseTreeControl {
206
234
  * data nodes of the tree.
207
235
  */
208
236
  expandAll() {
209
- this.expansionModel.select(...this.dataNodes);
237
+ this.expansionModel.select(...this.dataNodes.map((node) => this.expansionKey(node)));
210
238
  }
211
239
  /**
212
240
  * Ancestors of a data node, outermost first.
@@ -220,7 +248,7 @@ class FlatTreeControl extends BaseTreeControl {
220
248
  * an existing array; a fresh one is used when omitted.
221
249
  */
222
250
  getParents(node, result = []) {
223
- const startIndex = this.dataNodes?.indexOf(node) ?? -1;
251
+ const startIndex = this.indexOfNode(node);
224
252
  if (startIndex === -1) {
225
253
  return result;
226
254
  }
@@ -238,33 +266,86 @@ class FlatTreeControl extends BaseTreeControl {
238
266
  hasValue(value) {
239
267
  return this.dataNodes?.find((node) => this.compareValues(this.getValue(node), value));
240
268
  }
241
- filterNodes(value = null) {
269
+ /** Filters nodes by a query and expands the ancestors of every match. An empty string resets the filter. */
270
+ applyFilter(value = null) {
271
+ if (value === '') {
272
+ this.resetFilter();
273
+ return;
274
+ }
242
275
  this.saveExpansionState();
243
276
  let result = [];
244
277
  this.filters.forEach((filter, index, filters) => {
245
278
  const prevFilter = filters[index - 1] || null;
246
279
  result = filter.handle(value, prevFilter);
247
280
  });
248
- this.filterModel.clear();
249
- this.filterModel.select(...result);
250
281
  // set current expansion state according to filtered tree
251
- this.expansionModel.setSelection(...result.filter((node) => this.isExpandable(node)));
252
- this.updateFilterValue(value || result);
282
+ this.expansionModel.setSelection(...result.filter((node) => this.isExpandable(node)).map((node) => this.expansionKey(node)));
283
+ this.filterQuery = value;
284
+ if (!this.filterModel.setSelection(...result)) {
285
+ // CDK does not emit an empty selection diff, but the flat data source must re-render zero-match results.
286
+ this.filterModel.changed.next({ source: this.filterModel, added: [], removed: [] });
287
+ }
288
+ this.updateFilterValue(value);
253
289
  Promise.resolve().then(() => this.restoreExpansionState());
254
290
  }
291
+ /** Clears the active filter and restores the expansion state saved before filtering. */
292
+ resetFilter() {
293
+ if (this.hasActiveFilter) {
294
+ Promise.resolve().then(() => this.restoreExpansionState());
295
+ }
296
+ this.filterQuery = null;
297
+ this.filterModel.clear();
298
+ this.updateFilterValue(null);
299
+ }
300
+ /**
301
+ * Filters nodes by a query and expands the ancestors of every match.
302
+ *
303
+ * @deprecated Use `applyFilter` instead. Will be removed in 22.0.0.
304
+ */
305
+ filterNodes(value = null) {
306
+ this.applyFilter(value);
307
+ }
255
308
  updateFilterValue(value) {
256
309
  Promise.resolve().then(() => this.filterValue.next(value));
257
310
  }
258
311
  saveExpansionState() {
259
- if (!this.filterValue.value?.length) {
312
+ if (!this.hasActiveFilter) {
260
313
  this.expandedItemsBeforeFiltration = this.expansionModel.selected;
261
314
  }
262
315
  }
263
316
  restoreExpansionState() {
264
- if (!this.filterValue.value?.length) {
317
+ if (!this.hasActiveFilter) {
265
318
  this.expansionModel.setSelection(...this.expandedItemsBeforeFiltration);
266
319
  }
267
320
  }
321
+ /**
322
+ * Position of the node in `dataNodes`, constant-time while the index matches the array. With `trackBy` a node
323
+ * rebuilt as a new object since is found by its key, as the expansion methods accept it too.
324
+ */
325
+ indexOfNode(node) {
326
+ const { dataNodes, trackBy } = this;
327
+ if (!dataNodes)
328
+ return -1;
329
+ const cached = this.nodeIndexes.get(dataNodes)?.get(node);
330
+ // Checked against the array: `dataNodes` can be mutated in place.
331
+ if (cached !== undefined && dataNodes[cached] === node)
332
+ return cached;
333
+ const index = dataNodes.indexOf(node);
334
+ // A node that is not there leaves the index as it is.
335
+ if (index === -1) {
336
+ if (!trackBy)
337
+ return index;
338
+ const key = trackBy(node);
339
+ return dataNodes.findIndex((candidate) => trackBy(candidate) === key);
340
+ }
341
+ const positions = new Map();
342
+ dataNodes.forEach((dataNode, position) => {
343
+ if (!positions.has(dataNode))
344
+ positions.set(dataNode, position);
345
+ });
346
+ this.nodeIndexes.set(dataNodes, positions);
347
+ return index;
348
+ }
268
349
  }
269
350
 
270
351
  /** Nested tree control. Able to expand/collapse a subtree recursively for NestedNode type. */
@@ -276,9 +357,10 @@ class NestedTreeControl extends BaseTreeControl {
276
357
  * `getDescendants` walks the tree with `take(1)` and returns as soon as the recursion unwinds, so
277
358
  * an asynchronous source yields an incomplete — usually empty — descendant list.
278
359
  */
279
- constructor(getChildren) {
360
+ constructor(getChildren, options) {
280
361
  super();
281
362
  this.getChildren = getChildren;
363
+ this.trackBy = options?.trackBy;
282
364
  }
283
365
  /**
284
366
  * Expands all dataNodes in the tree.
@@ -289,7 +371,7 @@ class NestedTreeControl extends BaseTreeControl {
289
371
  expandAll() {
290
372
  this.expansionModel.clear();
291
373
  const allNodes = this.dataNodes.reduce((accumulator, dataNode) => [...accumulator, ...this.getDescendants(dataNode), dataNode], []);
292
- this.expansionModel.select(...allNodes);
374
+ this.expansionModel.select(...allNodes.map((node) => this.expansionKey(node)));
293
375
  }
294
376
  /** Gets a list of descendant dataNodes of a subtree rooted at given data node recursively. */
295
377
  getDescendants(dataNode) {
@@ -398,6 +480,8 @@ class KbqTreeFlattener {
398
480
  /**
399
481
  * Expand flattened node with current expansion status.
400
482
  * The returned list may have different length.
483
+ *
484
+ * Reads only `isExpanded` of the tree control, so it takes a control of any key type.
401
485
  */
402
486
  expandFlattenedNodes(nodes, treeControl) {
403
487
  const results = [];
@@ -436,8 +520,10 @@ class KbqTreeFlatDataSource extends DataSource {
436
520
  }
437
521
  set data(value) {
438
522
  this._data.set(value);
439
- this.flattenedData.next(this.treeFlattener.flattenNodes(this.data));
440
- this.treeControl.dataNodes = this.flattenedData.value;
523
+ const flattened = this.treeFlattener.flattenNodes(this.data);
524
+ // Assigned before emitting: the tree renders inside `next`, and its rows look themselves up in `dataNodes`.
525
+ this.treeControl.dataNodes = flattened;
526
+ this.flattenedData.next(flattened);
441
527
  }
442
528
  constructor(treeControl, treeFlattener, initialData = []) {
443
529
  super();
@@ -454,9 +540,9 @@ class KbqTreeFlatDataSource extends DataSource {
454
540
  }
455
541
  }
456
542
  connect(collectionViewer) {
457
- 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) => {
543
+ return merge(collectionViewer.viewChange, this.treeControl.expansionModel.changed.pipe(map((value) => ({ type: KbqTreeDataSourceChangeTypes.Expansion, value }))), this.treeControl.filterModel.changed.pipe(map(() => ({ type: KbqTreeDataSourceChangeTypes.Filter, value: this.treeControl.filterModel.selected }))), this.flattenedData).pipe(map((changeObj) => {
458
544
  if (changeObj.type === KbqTreeDataSourceChangeTypes.Filter) {
459
- if (changeObj.value && changeObj.value.length > 0) {
545
+ if (this.treeControl.hasActiveFilter) {
460
546
  return this.filterHandler();
461
547
  }
462
548
  else {
@@ -611,6 +697,8 @@ const normalizeTreeState = (parsed) => {
611
697
  * ported by hand.
612
698
  *
613
699
  * `C` narrows the tree control a concrete tree accepts, and so the type its `treeControl` binding is checked against.
700
+ * The bound leaves out `expansionModel` and `trackBy`, the members typed by the control's key, so that it admits
701
+ * a control of any key type: the model makes a control invariant in that type.
614
702
  */
615
703
  class KbqTreeBase {
616
704
  /** Controls the expanded state and holds the data nodes of the tree. */
@@ -652,6 +740,8 @@ class KbqTreeBase {
652
740
  *
653
741
  * Views are reused for nodes the function reports as unchanged, which a data source that rebuilds
654
742
  * its node objects on every emission — a flattener among them — otherwise cannot get.
743
+ *
744
+ * Defaults to the `trackBy` of the tree control, read when the tree initializes and when the data source changes.
655
745
  */
656
746
  this.trackBy = input(undefined, ...(ngDevMode ? [{ debugName: "trackBy" }] : /* istanbul ignore next */ []));
657
747
  this.nodeOutletQuery = viewChild(KbqTreeNodeOutlet, ...(ngDevMode ? [{ debugName: "nodeOutletQuery" }] : /* istanbul ignore next */ []));
@@ -763,7 +853,7 @@ class KbqTreeBase {
763
853
  // Untracked, as in `clearSavedState()`: called from a consumer's `effect()`, the inputs read on the way would
764
854
  // make the effect run again whenever they change.
765
855
  untracked(() => {
766
- if (!this.persists || this.treeControl.filterValue.value?.length)
856
+ if (!this.persists || this.treeControl.hasActiveFilter)
767
857
  return;
768
858
  this.stateSaving.write(this.expandedValues());
769
859
  });
@@ -948,7 +1038,9 @@ class KbqTreeBase {
948
1038
  // Straight at the model rather than through `expand()`, which is a no-op while a filter is
949
1039
  // active — restoring must not depend on what the user happens to be searching for.
950
1040
  if (found.length) {
951
- this.stateSaving.applying(() => treeControl.expansionModel.select(...found));
1041
+ const { trackBy } = treeControl;
1042
+ const keys = trackBy ? found.map((node) => trackBy(node)) : found;
1043
+ this.stateSaving.applying(() => treeControl.expansionModel.select(...keys));
952
1044
  }
953
1045
  }
954
1046
  /** The values of the nodes that are currently expanded, plus the ones still waiting to appear. */
@@ -956,7 +1048,11 @@ class KbqTreeBase {
956
1048
  const treeControl = this.flatTreeControl;
957
1049
  const expanded = [];
958
1050
  let skipped = false;
959
- for (const node of treeControl.expansionModel.selected) {
1051
+ // With `trackBy` the model holds keys, which have no value: only the current nodes map back to them.
1052
+ const expandedNodes = treeControl.trackBy
1053
+ ? (treeControl.dataNodes ?? []).filter((node) => treeControl.isExpanded(node))
1054
+ : treeControl.expansionModel.selected;
1055
+ for (const node of expandedNodes) {
960
1056
  const value = treeControl.getValue(node);
961
1057
  if (typeof value === 'string') {
962
1058
  expanded.push(value);
@@ -1039,7 +1135,10 @@ class KbqTreeBase {
1039
1135
  }
1040
1136
  }
1041
1137
  createDataDiffer() {
1042
- return this.differs.find([]).create(this.trackBy());
1138
+ // The bound of `C` leaves `trackBy` out; the key type is the control's own, so it is read as `unknown` here.
1139
+ const controlTrackBy = this.treeControl?.trackBy;
1140
+ const trackBy = this.trackBy() ?? (controlTrackBy && ((_, node) => controlTrackBy(node)));
1141
+ return this.differs.find([]).create(trackBy);
1043
1142
  }
1044
1143
  /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqTreeBase, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1045
1144
  /** @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 }); }
@@ -1134,14 +1233,16 @@ class KbqTreeNodeToggleBaseDirective {
1134
1233
  */
1135
1234
  this.disabledInput = input(false, { ...(ngDevMode ? { debugName: "disabledInput" } : /* istanbul ignore next */ {}), alias: 'disabled', transform: booleanAttribute });
1136
1235
  /** Set while a filter is active: filtering already decides what is expanded. */
1137
- this.filterDisabled = toSignal(this.tree.treeControl.filterValue.pipe(map((value) => !!value?.length)), { initialValue: false });
1236
+ this.filterDisabled = toSignal(this.tree.treeControl.filterModel.changed.pipe(map(() => this.tree.treeControl.hasActiveFilter)), { initialValue: false });
1138
1237
  this.disabledState = computed(() => this.disabledInput() || this.filterDisabled(), ...(ngDevMode ? [{ debugName: "disabledState" }] : /* istanbul ignore next */ []));
1139
1238
  }
1140
1239
  get disabled() {
1141
1240
  return this.disabledState();
1142
1241
  }
1143
1242
  get iconState() {
1144
- return this.tree.treeControl.isExpanded(this.node());
1243
+ // The node `toggle()` acts on when `node` is not bound: an unbound `node` would reach the control's
1244
+ // `trackBy` as `undefined`.
1245
+ return this.tree.treeControl.isExpanded(this.node() ?? this.treeNode.data);
1145
1246
  }
1146
1247
  toggle(event) {
1147
1248
  if (this.disabled)
@@ -1268,9 +1369,9 @@ class KbqTreeOption extends KbqTreeNode {
1268
1369
  get id() {
1269
1370
  return this._id;
1270
1371
  }
1372
+ /** The displayed value used by type-ahead. Falls back to the text of the option. */
1271
1373
  get viewValue() {
1272
- // TODO: Add input property alternative for node envs.
1273
- return (this.getHostElement().textContent || '').trim();
1374
+ return this.viewValueInput() || (this.getHostElement().textContent || '').trim();
1274
1375
  }
1275
1376
  get hasFocus() {
1276
1377
  return this.focused();
@@ -1332,6 +1433,8 @@ class KbqTreeOption extends KbqTreeNode {
1332
1433
  this.changeDetectorRef = inject(ChangeDetectorRef);
1333
1434
  this.environmentInjector = inject(EnvironmentInjector);
1334
1435
  this.destroyRef = inject(DestroyRef);
1436
+ this.ngZone = inject(NgZone);
1437
+ this.renderer = inject(Renderer2);
1335
1438
  this.focusEvents = new Subject();
1336
1439
  this.blurEvents = new Subject();
1337
1440
  /** Emits when the option takes focus. */
@@ -1348,6 +1451,8 @@ class KbqTreeOption extends KbqTreeNode {
1348
1451
  this.dropdownTriggerQuery = contentChild(KbqDropdownTrigger, ...(ngDevMode ? [{ debugName: "dropdownTriggerQuery" }] : /* istanbul ignore next */ []));
1349
1452
  this.checkboxThirdState = input(false, ...(ngDevMode ? [{ debugName: "checkboxThirdState" }] : /* istanbul ignore next */ []));
1350
1453
  /** @docs-private */
1454
+ this.viewValueInput = input(undefined, { ...(ngDevMode ? { debugName: "viewValueInput" } : /* istanbul ignore next */ {}), alias: 'viewValue' });
1455
+ /** @docs-private */
1351
1456
  this.disabledInput = input(false, { ...(ngDevMode ? { debugName: "disabledInput" } : /* istanbul ignore next */ {}), alias: 'disabled',
1352
1457
  transform: booleanAttribute });
1353
1458
  /**
@@ -1396,6 +1501,9 @@ class KbqTreeOption extends KbqTreeNode {
1396
1501
  this.selectedState = signal(false, ...(ngDevMode ? [{ debugName: "selectedState" }] : /* istanbul ignore next */ []));
1397
1502
  this._id = `kbq-tree-option-${uniqueIdCounter++}`;
1398
1503
  this.focused = signal(false, ...(ngDevMode ? [{ debugName: "focused" }] : /* istanbul ignore next */ []));
1504
+ // Raised from reporting a focus until `hasFocus` is: `kbqFocusAndReveal` fires `focusin` synchronously, and its
1505
+ // listener calls back into `focus()` while `hasFocus` is still false.
1506
+ this.focusReported = false;
1399
1507
  this.checkbox = signal('unchecked', ...(ngDevMode ? [{ debugName: "checkbox" }] : /* istanbul ignore next */ []));
1400
1508
  this.updateCheckboxState = () => {
1401
1509
  if (this.selectAllRow())
@@ -1404,6 +1512,16 @@ class KbqTreeOption extends KbqTreeNode {
1404
1512
  this.updateParentsCheckboxState(this.data);
1405
1513
  };
1406
1514
  this.tree = tree;
1515
+ // Not a host listener: one would check the views on every row the pointer crosses, and only a tree in a select
1516
+ // reacts to it.
1517
+ const unlisten = this.ngZone.runOutsideAngular(() => this.renderer.listen(this.elementRef.nativeElement, 'mouseenter', () => this.onMouseenter()));
1518
+ this.destroyRef.onDestroy(unlisten);
1519
+ }
1520
+ ngOnInit() {
1521
+ // Selected from its first check: the tree's sweep reaches a new row a macrotask later, and a row it marked
1522
+ // would render unselected first and then report a selection nobody made.
1523
+ if (!this.selectAllRow())
1524
+ this.selectedState.set(!!this.tree.selectionModel?.isSelected(this.data));
1407
1525
  }
1408
1526
  ngDoCheck() {
1409
1527
  // Asked once per check, for a predicate reading plain state; a set to an equal value does nothing.
@@ -1497,11 +1615,16 @@ class KbqTreeOption extends KbqTreeNode {
1497
1615
  return;
1498
1616
  // With the pointer already on this node, revealing it would shift the tree out from under it.
1499
1617
  kbqFocusAndReveal(this.elementRef.nativeElement, focusOrigin === 'mouse');
1500
- if (!this.hasFocus) {
1501
- this.focusEvents.next({ option: this });
1618
+ if (!this.hasFocus && !this.focusReported) {
1619
+ const event = { option: this };
1620
+ this.focusReported = true;
1621
+ this.focusEvents.next(event);
1622
+ this.tree.reportOptionFocus?.(event);
1502
1623
  Promise.resolve().then(() => {
1624
+ this.focusReported = false;
1503
1625
  this.hasFocus = true;
1504
- this.markForCheck();
1626
+ // The view only: focus changes no checkbox state.
1627
+ this.changeDetectorRef.markForCheck();
1505
1628
  });
1506
1629
  }
1507
1630
  });
@@ -1522,7 +1645,9 @@ class KbqTreeOption extends KbqTreeNode {
1522
1645
  return;
1523
1646
  }
1524
1647
  this.hasFocus = false;
1525
- this.blurEvents.next({ option: this });
1648
+ const event = { option: this };
1649
+ this.blurEvents.next(event);
1650
+ this.tree.reportOptionBlur?.(event);
1526
1651
  },
1527
1652
  // The environment injector, not the option's: an option removed while focused is blurred as its view is
1528
1653
  // destroyed, and the tree still has to hear about it to move focus.
@@ -1552,7 +1677,8 @@ class KbqTreeOption extends KbqTreeNode {
1552
1677
  if (setFocus && !this.hasFocus) {
1553
1678
  this.focus();
1554
1679
  }
1555
- this.updateCheckboxState();
1680
+ // Its own state only: an ancestor's reads the selection model, which this leaves as it is.
1681
+ this.syncCheckboxState();
1556
1682
  this.emitSelectionChangeEvent();
1557
1683
  });
1558
1684
  }
@@ -1562,7 +1688,8 @@ class KbqTreeOption extends KbqTreeNode {
1562
1688
  return;
1563
1689
  }
1564
1690
  this.selectedState.set(false);
1565
- this.updateCheckboxState();
1691
+ // Its own state only, as in `select`.
1692
+ this.syncCheckboxState();
1566
1693
  this.emitSelectionChangeEvent();
1567
1694
  });
1568
1695
  }
@@ -1594,8 +1721,9 @@ class KbqTreeOption extends KbqTreeNode {
1594
1721
  }
1595
1722
  markForCheck() {
1596
1723
  this.changeDetectorRef.markForCheck();
1597
- // Its own state only: after a selection, data or mode change the tree calls this on every option.
1598
- if (this.showCheckbox) {
1724
+ // Its own state only: after a selection, data or mode change the tree calls this on every option. A projected
1725
+ // checkbox shows the state while the tree's own is hidden.
1726
+ if (this.showCheckbox || this.externalPseudoCheckbox) {
1599
1727
  this.syncCheckboxState();
1600
1728
  }
1601
1729
  }
@@ -1603,15 +1731,18 @@ class KbqTreeOption extends KbqTreeNode {
1603
1731
  onMouseenter() {
1604
1732
  if (this.disabled || !this.tree.inSelect)
1605
1733
  return;
1606
- this.focus('mouse');
1734
+ // Focusing the option it already holds would only run change detection.
1735
+ if (this.hasFocus && _getFocusedElementPierceShadowDom() === this.elementRef.nativeElement)
1736
+ return;
1737
+ this.ngZone.run(() => this.focus('mouse'));
1607
1738
  }
1608
1739
  /** Recomputes the option's own checkbox state, leaving its ancestors as they are. */
1609
1740
  syncCheckboxState() {
1610
1741
  if (this.selectAllRow())
1611
1742
  return;
1612
1743
  if (this.checkboxThirdState() && this.isExpandable) {
1613
- // One descendant walk, not two: `getDescendants` is a linear scan of the whole data set, and
1614
- // the roll-up runs this method for every ancestor.
1744
+ // One descendant walk, not two: each walk covers the whole subtree, and the roll-up runs this method for
1745
+ // every ancestor.
1615
1746
  const descendants = this.tree.treeControl.getDescendants(this.data);
1616
1747
  const selectedCount = descendants.filter((child) => this.tree.selectionModel.isSelected(child)).length;
1617
1748
  if (selectedCount === descendants.length) {
@@ -1636,7 +1767,7 @@ class KbqTreeOption extends KbqTreeNode {
1636
1767
  return { disabled: this.disabled, expanded: branch ? this.isExpanded : null };
1637
1768
  }
1638
1769
  /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqTreeOption, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1639
- /** @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()", "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": "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: [
1770
+ /** @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 }, viewValueInput: { classPropertyName: "viewValueInput", publicName: "viewValue", 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: [
1640
1771
  { provide: KbqTreeNode, useExisting: KbqTreeOption },
1641
1772
  { provide: KBQ_TITLE_TEXT_REF, useExisting: KbqTreeOption },
1642
1773
  { provide: KBQ_OPTION_ACTION_PARENT, useExisting: KbqTreeOption }
@@ -1669,12 +1800,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImpo
1669
1800
  '[attr.aria-checked]': 'ariaChecked',
1670
1801
  '[attr.aria-selected]': 'ariaSelected',
1671
1802
  '(focusin)': 'focus()',
1672
- '(mouseenter)': 'onMouseenter()',
1673
1803
  '(blur)': 'blur()',
1674
1804
  '(click)': 'selectViaInteraction($event)',
1675
1805
  '(keydown)': 'onKeydown($event)'
1676
1806
  }, 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"] }]
1677
- }], 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"] }] } });
1807
+ }], 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 }] }], viewValueInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewValue", 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"] }] } });
1678
1808
 
1679
1809
  /** Regex used to split a string on its CSS units. */
1680
1810
  const cssUnitPattern = /([A-Za-z%]+)$/;
@@ -1861,11 +1991,13 @@ class KbqTreeSelection extends KbqTreeBase {
1861
1991
  set autoSelect(value) {
1862
1992
  this.autoSelectState.set(coerceBooleanProperty(value));
1863
1993
  }
1994
+ /** Emits when an option of the tree takes focus. */
1864
1995
  get optionFocusChanges() {
1865
- return merge(...this.renderedOptions.map((option) => option.onFocus));
1996
+ return this.optionFocusEvents.asObservable();
1866
1997
  }
1998
+ /** Emits when an option of the tree loses focus. */
1867
1999
  get optionBlurChanges() {
1868
- return merge(...this.renderedOptions.map((option) => option.onBlur));
2000
+ return this.optionBlurEvents.asObservable();
1869
2001
  }
1870
2002
  /**
1871
2003
  * Selection mode of the tree.
@@ -1965,16 +2097,16 @@ class KbqTreeSelection extends KbqTreeBase {
1965
2097
  if (!this.treeControl) {
1966
2098
  return [];
1967
2099
  }
1968
- const nonSelectableDataNodes = this.renderedOptions
2100
+ const nonSelectableDataNodes = new Set(this.renderedOptions
1969
2101
  .filter((option) => option.disabled || !option.selectable())
1970
- .map((option) => option.data);
1971
- const candidates = this.treeControl.filterValue.value?.length
2102
+ .map((option) => option.data));
2103
+ const candidates = this.treeControl.hasActiveFilter
1972
2104
  ? this.renderedOptions.map((option) => option.data)
1973
2105
  : (this.treeControl.dataNodes ?? []);
1974
- // The `includes` check comes first on purpose: the "select all" row is itself a non-selectable
2106
+ // The `has` check comes first on purpose: the "select all" row is itself a non-selectable
1975
2107
  // rendered option with no `data`, and `isDisabled` belongs to the consumer — it must never be
1976
2108
  // handed a node their data source has never seen.
1977
- return candidates.filter((node) => !nonSelectableDataNodes.includes(node) && !this.treeControl.isDisabled(node));
2109
+ return candidates.filter((node) => !nonSelectableDataNodes.has(node) && !this.treeControl.isDisabled(node));
1978
2110
  }
1979
2111
  /** Adapter shared by the master checkbox and the Ctrl/Cmd + A handler, so the two cannot drift apart. */
1980
2112
  get selectAllAdapter() {
@@ -2084,6 +2216,9 @@ class KbqTreeSelection extends KbqTreeBase {
2084
2216
  transform: booleanAttribute });
2085
2217
  /** `undefined` while the value is derived from the mode. Written by `KbqTreeSelect` as well. */
2086
2218
  this.autoSelectState = linkedSignal(() => this.autoSelectInput(), ...(ngDevMode ? [{ debugName: "autoSelectState" }] : /* istanbul ignore next */ []));
2219
+ // Options report here, so a subscriber also hears the rows rendered after it subscribed.
2220
+ this.optionFocusEvents = new Subject();
2221
+ this.optionBlurEvents = new Subject();
2087
2222
  /** @docs-private */
2088
2223
  this.multipleInput = input(undefined, { ...(ngDevMode ? { debugName: "multipleInput" } : /* istanbul ignore next */ {}), alias: 'multiple' });
2089
2224
  /**
@@ -2117,6 +2252,9 @@ class KbqTreeSelection extends KbqTreeBase {
2117
2252
  transform: kbqOptionalNumberAttribute });
2118
2253
  this.tabIndexState = signal(0, ...(ngDevMode ? [{ debugName: "tabIndexState" }] : /* istanbul ignore next */ []));
2119
2254
  this.selectionModelSubscription = null;
2255
+ // A selection change asks for a sweep here, not through `renderedOptions.changes`: the key manager and an
2256
+ // embedding select listen to that, and no row changed.
2257
+ this.selectionSweeps = new Subject();
2120
2258
  /** Whether a value report is queued for the end of the current tick. Cleared by `writeValue` to cancel it. */
2121
2259
  this.pendingValueReport = false;
2122
2260
  /** Backs {@link syncingSelection}: a change of the selection made by code is no change to report back. */
@@ -2153,18 +2291,29 @@ class KbqTreeSelection extends KbqTreeBase {
2153
2291
  if (selectAllOption) {
2154
2292
  orderedOptions.push(selectAllOption);
2155
2293
  }
2294
+ // Indexed once per render, as a search per node is quadratic in the rows. The first option wins in both maps.
2295
+ const optionsByNode = new Map();
2296
+ const optionsByValue = new Map();
2297
+ this.unorderedOptions.forEach((option) => {
2298
+ if (!optionsByNode.has(option.data))
2299
+ optionsByNode.set(option.data, option);
2300
+ if (!optionsByValue.has(option.value))
2301
+ optionsByValue.set(option.value, option);
2302
+ });
2156
2303
  this.sortedNodes.forEach((node) => {
2157
2304
  // By node first: nodes do not have to carry distinct values, and a value match would hand every node with
2158
2305
  // the same value the first option holding it.
2159
- const found = this.unorderedOptions.find((option) => option.data === node) ??
2160
- this.unorderedOptions.find((option) => option.value === this.treeControl.getValue(node));
2306
+ const found = optionsByNode.get(node) ?? optionsByValue.get(this.treeControl.getValue(node));
2161
2307
  if (found) {
2162
2308
  orderedOptions.push(found);
2163
2309
  }
2164
2310
  });
2165
2311
  this.renderedOptions.reset(orderedOptions);
2166
2312
  this.renderedOptions.notifyOnChanges();
2167
- this.updateScrollSize();
2313
+ // The list above is for the server too: an embedding `KbqTreeSelect` reads it for the tags it renders.
2314
+ if (this.platform.isBrowser) {
2315
+ this.updateScrollSize();
2316
+ }
2168
2317
  };
2169
2318
  this.destroyRef.onDestroy(() => (this.destroyed = true));
2170
2319
  // Single selection until the `multiple` input says otherwise. A model has to exist this early
@@ -2330,18 +2479,14 @@ class KbqTreeSelection extends KbqTreeBase {
2330
2479
  if (!this.writingValue) {
2331
2480
  this.reportValue();
2332
2481
  }
2333
- this.renderedOptions.notifyOnChanges();
2482
+ this.selectionSweeps.next();
2334
2483
  // The "select all" row renders the selection state.
2335
2484
  this.changeDetectorRef.markForCheck();
2336
2485
  });
2337
2486
  }
2338
2487
  ngAfterContentInit() {
2339
2488
  super.ngAfterContentInit();
2340
- if (this.platform.isBrowser) {
2341
- this.unorderedOptions.changes
2342
- .pipe(takeUntilDestroyed(this.destroyRef))
2343
- .subscribe(this.updateRenderedOptions);
2344
- }
2489
+ this.unorderedOptions.changes.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(this.updateRenderedOptions);
2345
2490
  this.keyManager = new FocusKeyManager(this.renderedOptions)
2346
2491
  .withVerticalOrientation(true)
2347
2492
  .withHorizontalOrientation(null);
@@ -2360,16 +2505,20 @@ class KbqTreeSelection extends KbqTreeBase {
2360
2505
  });
2361
2506
  kbqLeaveTabOrderOnTabOut(this.keyManager.tabOut, this.elementRef.nativeElement, () => this.tabIndex, this.destroyRef);
2362
2507
  this.bindSelectionModel();
2363
- this.renderedOptions.changes
2364
- .pipe(delay(0, this.scheduler), takeUntilDestroyed(this.destroyRef))
2365
- .subscribe((options) => {
2366
- this.resetOptions();
2508
+ this.listenToOptionsFocus();
2509
+ // A render and the selection changes of one task each notify, each with its own timer: the first to fire sweeps
2510
+ // for all of them and the rest are dropped. `auditTime` would tie the later ones to the first one's timer.
2511
+ let sweeps = 0;
2512
+ merge(this.renderedOptions.changes, this.selectionSweeps)
2513
+ .pipe(map(() => sweeps), delay(0, this.scheduler), filter((sweepsWhenNotified) => sweepsWhenNotified === sweeps), takeUntilDestroyed(this.destroyRef))
2514
+ .subscribe(() => {
2515
+ sweeps++;
2367
2516
  // Check to see if we need to update our tab index
2368
2517
  this.updateTabIndex();
2369
2518
  this.syncSelectionModelToDataNodes();
2370
- const selectedValues = this.multiple ? this.getSelectedValues() : [this.getSelectedValues()];
2371
- options.forEach((option) => {
2372
- if (selectedValues.includes(option.value)) {
2519
+ this.renderedOptions.forEach((option) => {
2520
+ // By node rather than by value: rows may share a value.
2521
+ if (this.selectionModel.isSelected(option.data)) {
2373
2522
  option.select(false);
2374
2523
  }
2375
2524
  else {
@@ -2410,7 +2559,8 @@ class KbqTreeSelection extends KbqTreeBase {
2410
2559
  }
2411
2560
  ngOnDestroy() {
2412
2561
  super.ngOnDestroy();
2413
- this.dropSubscriptions();
2562
+ this.optionFocusEvents.complete();
2563
+ this.optionBlurEvents.complete();
2414
2564
  this.focusMonitor.stopMonitoring(this.elementRef);
2415
2565
  }
2416
2566
  focus($event) {
@@ -2576,6 +2726,14 @@ class KbqTreeSelection extends KbqTreeBase {
2576
2726
  }
2577
2727
  }
2578
2728
  /** @docs-private */
2729
+ reportOptionFocus(event) {
2730
+ this.optionFocusEvents.next(event);
2731
+ }
2732
+ /** @docs-private */
2733
+ reportOptionBlur(event) {
2734
+ this.optionBlurEvents.next(event);
2735
+ }
2736
+ /** @docs-private */
2579
2737
  setSelectedOptionsByClick(option, shiftKey, ctrlKey) {
2580
2738
  if (option.disabled || !option.selectable()) {
2581
2739
  return;
@@ -2607,7 +2765,8 @@ class KbqTreeSelection extends KbqTreeBase {
2607
2765
  const options = this.renderedOptions.toArray();
2608
2766
  let fromIndex = this.keyManager.previousActiveItemIndex;
2609
2767
  let toIndex = (this.keyManager.previousActiveItemIndex = this.keyManager.activeItemIndex);
2610
- const selectedOptionState = options[fromIndex]?.selected;
2768
+ // Asked of the model: an option's own state lags it until the next sweep.
2769
+ const selectedOptionState = this.selectionModel.isSelected(options[fromIndex]?.data);
2611
2770
  if (toIndex === fromIndex || fromIndex === -1) {
2612
2771
  if (options[toIndex]?.selectable()) {
2613
2772
  options[toIndex].toggle();
@@ -2617,15 +2776,21 @@ class KbqTreeSelection extends KbqTreeBase {
2617
2776
  if (fromIndex > toIndex) {
2618
2777
  [fromIndex, toIndex] = [toIndex, fromIndex];
2619
2778
  }
2620
- options
2779
+ const nodes = options
2621
2780
  .slice(fromIndex, toIndex + 1)
2622
2781
  .filter((item) => !item.disabled && item.selectable())
2623
- .forEach((renderedOption) => {
2624
- if (!selectedOptionState && this.noUnselectLast && this.selectionModel.selected.length === 1) {
2625
- return;
2626
- }
2627
- renderedOption.setSelected(selectedOptionState);
2628
- });
2782
+ .map((item) => item.data);
2783
+ // One write for the range, so the selection changes once rather than once per row.
2784
+ if (selectedOptionState) {
2785
+ this.selectionModel.select(...nodes);
2786
+ return;
2787
+ }
2788
+ const selected = nodes.filter((node) => this.selectionModel.isSelected(node));
2789
+ // With `noUnselectLast` the last selected node stays, the range giving up its own in order until then.
2790
+ const released = this.noUnselectLast
2791
+ ? Math.max(0, Math.min(selected.length, this.selectionModel.selected.length - 1))
2792
+ : selected.length;
2793
+ this.selectionModel.deselect(...selected.slice(0, released));
2629
2794
  }
2630
2795
  /** @docs-private */
2631
2796
  toggleFocusedOption() {
@@ -2651,12 +2816,16 @@ class KbqTreeSelection extends KbqTreeBase {
2651
2816
  const changed = this.applyNodeChanges(data, dataDiffer, viewContainer, parentData);
2652
2817
  this.sortedNodes = this.getSortedNodes(viewContainer);
2653
2818
  this.changeDetectorRef.detectChanges();
2819
+ // The options query lists the options in the order their views were created, not in the order of the rows, so
2820
+ // rows that only moved (reused through `trackBy`) never make it emit.
2821
+ if (changed && this.renderedOptionsOutOfOrder())
2822
+ this.updateRenderedOptions();
2654
2823
  this.scheduleCheckboxSync(false);
2655
2824
  // The "select all" row is rendered ahead of what its state reads: new rows bind their inputs after it and join
2656
- // `renderedOptions` only once bound, and `KbqTreeFlatDataSource` assigns `dataNodes` after it emits. Nothing
2657
- // else in the tree reads that state but the checkbox sync above, so a tree without the row is done in this one
2658
- // pass. Marked for check, which reaches the views above too: a template reading `allOptionsSelected` by
2659
- // reference reads the same state.
2825
+ // `renderedOptions` only once bound, and a consumer's data source can assign `dataNodes` after it emits.
2826
+ // Nothing else in the tree reads that state but the checkbox sync above, so a tree without the row is done in
2827
+ // this one pass. Marked for check, which reaches the views above too: a template reading `allOptionsSelected`
2828
+ // by reference reads the same state.
2660
2829
  if (!this.showSelectAll)
2661
2830
  return;
2662
2831
  const dataNodes = this.treeControl.dataNodes;
@@ -2668,7 +2837,7 @@ class KbqTreeSelection extends KbqTreeBase {
2668
2837
  /**
2669
2838
  * Recomputes every option's checkbox state where no selection change follows to do it: after `dataNodes` is
2670
2839
  * replaced, which moves the descendants a branch counts, and once a hidden checkbox appears. A microtask later, as
2671
- * a flat data source assigns `dataNodes` only after it emits.
2840
+ * a consumer's data source can assign `dataNodes` after it emits.
2672
2841
  */
2673
2842
  scheduleCheckboxSync(force) {
2674
2843
  Promise.resolve().then(() => {
@@ -2711,11 +2880,23 @@ class KbqTreeSelection extends KbqTreeBase {
2711
2880
  // Selection is applied at the data-node level (incl. collapsed/non-rendered nodes unless a filter
2712
2881
  // is active), while the emitted events carry the selectable rendered options.
2713
2882
  const selectableOptions = this.renderedOptions.filter((option) => !option.disabled && option.selectable());
2883
+ // A multiple selection takes the nodes in one write, so it changes once rather than once per node. A single
2884
+ // one cannot hold them, and keeps the node-by-node writes it always had.
2885
+ const batched = this.selectionModel.isMultipleSelection();
2886
+ const adapter = this.selectAllAdapter;
2714
2887
  // `toggleSelectAll` returns the data nodes whose selection actually flipped — the source of
2715
2888
  // truth, unlike the cached `option.selected` which lags until change detection.
2716
- const changed = toggleSelectAll(this.selectAllAdapter, {
2889
+ const changed = toggleSelectAll(batched ? { ...adapter, setSelected: () => { } } : adapter, {
2717
2890
  allowDeselect: allowDeselect ?? (this.selectAll || this.selectAllToggle())
2718
2891
  });
2892
+ if (batched && changed.length) {
2893
+ if (this.selectionModel.isSelected(changed[0])) {
2894
+ this.selectionModel.deselect(...changed);
2895
+ }
2896
+ else {
2897
+ this.selectionModel.select(...changed);
2898
+ }
2899
+ }
2719
2900
  const changedData = new Set(changed);
2720
2901
  const changedOptions = selectableOptions.filter((option) => changedData.has(option.data));
2721
2902
  // Skip `selectionChange` on a no-op (e.g. Ctrl+A while everything is already selected and
@@ -2924,6 +3105,17 @@ class KbqTreeSelection extends KbqTreeBase {
2924
3105
  updateTabIndex() {
2925
3106
  this.tabIndexState.set(this.userTabIndex || (this.renderedOptions.length === 0 ? -1 : 0));
2926
3107
  }
3108
+ /**
3109
+ * Whether the same options as before now stand for the rows in another order. A different count means rows were
3110
+ * added or removed, which the options query reports itself.
3111
+ */
3112
+ renderedOptionsOutOfOrder() {
3113
+ const options = this.renderedOptions.toArray();
3114
+ const offset = this.selectAllOption() ? 1 : 0;
3115
+ if (options.length - offset !== this.sortedNodes.length)
3116
+ return false;
3117
+ return this.sortedNodes.some((node, index) => options[index + offset].data !== node);
3118
+ }
2927
3119
  getSortedNodes(viewContainer) {
2928
3120
  const array = [];
2929
3121
  for (let i = 0; i < viewContainer.length; i++) {
@@ -2932,22 +3124,9 @@ class KbqTreeSelection extends KbqTreeBase {
2932
3124
  }
2933
3125
  return array;
2934
3126
  }
2935
- resetOptions() {
2936
- this.dropSubscriptions();
2937
- this.listenToOptionsFocus();
2938
- }
2939
- dropSubscriptions() {
2940
- if (this.optionFocusSubscription) {
2941
- this.optionFocusSubscription.unsubscribe();
2942
- this.optionFocusSubscription = null;
2943
- }
2944
- if (this.optionBlurSubscription) {
2945
- this.optionBlurSubscription.unsubscribe();
2946
- this.optionBlurSubscription = null;
2947
- }
2948
- }
2949
3127
  listenToOptionsFocus() {
2950
- this.optionFocusSubscription = this.optionFocusChanges.subscribe((event) => {
3128
+ // Both streams complete with the tree.
3129
+ this.optionFocusEvents.subscribe((event) => {
2951
3130
  const index = this.renderedOptions.toArray().indexOf(event.option);
2952
3131
  this.renderedOptions.filter((option) => option.hasFocus).forEach((option) => (option.hasFocus = false));
2953
3132
  if (this.isValidIndex(index)) {
@@ -2959,7 +3138,7 @@ class KbqTreeSelection extends KbqTreeBase {
2959
3138
  // set, because `KbqTreeOption.hasFocus` is cleared synchronously but only raised a microtask later, so
2960
3139
  // `hasFocusedOption()` reports nothing focused for the whole move. Only a blur of the option the
2961
3140
  // key manager still points at is the focus actually leaving the options.
2962
- this.optionBlurSubscription = this.optionBlurChanges.subscribe(({ option }) => {
3141
+ this.optionBlurEvents.subscribe(({ option }) => {
2963
3142
  if (option === this.keyManager.activeItem && !this.hasFocusedOption() && this.resetFocusedItemOnBlur) {
2964
3143
  this.keyManager.setActiveItem(-1);
2965
3144
  }
@@ -3018,7 +3197,7 @@ class KbqTreeSelection extends KbqTreeBase {
3018
3197
  </kbq-tree-option>
3019
3198
  }
3020
3199
  <ng-container kbqTreeNodeOutlet />
3021
- `, 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 }); }
3200
+ `, 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", "viewValue", "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 }); }
3022
3201
  }
3023
3202
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqTreeSelection, decorators: [{
3024
3203
  type: Component,