ngwr 14.8.0 → 14.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (447) hide show
  1. package/README.md +66 -332
  2. package/alert/styles/_index.scss +10 -0
  3. package/avatar/styles/_index.scss +18 -7
  4. package/badge/styles/_index.scss +7 -0
  5. package/badge/styles/_tag.scss +7 -1
  6. package/button/styles/_index.scss +6 -0
  7. package/cascader/styles/_rules.scss +1 -1
  8. package/checkbox/styles/_index.scss +4 -0
  9. package/command-palette/styles/_index.scss +1 -1
  10. package/divider/styles/_index.scss +2 -0
  11. package/editor/styles/_index.scss +441 -0
  12. package/fesm2022/ngwr-action-sheet-testing.mjs.map +1 -1
  13. package/fesm2022/ngwr-action-sheet.mjs +3 -3
  14. package/fesm2022/ngwr-action-sheet.mjs.map +1 -1
  15. package/fesm2022/ngwr-affix.mjs +3 -3
  16. package/fesm2022/ngwr-affix.mjs.map +1 -1
  17. package/fesm2022/ngwr-alert.mjs +3 -3
  18. package/fesm2022/ngwr-alert.mjs.map +1 -1
  19. package/fesm2022/ngwr-anchor.mjs +3 -3
  20. package/fesm2022/ngwr-anchor.mjs.map +1 -1
  21. package/fesm2022/ngwr-aurora.mjs +3 -3
  22. package/fesm2022/ngwr-aurora.mjs.map +1 -1
  23. package/fesm2022/ngwr-avatar.mjs +3 -3
  24. package/fesm2022/ngwr-avatar.mjs.map +1 -1
  25. package/fesm2022/ngwr-back-top.mjs +3 -3
  26. package/fesm2022/ngwr-back-top.mjs.map +1 -1
  27. package/fesm2022/ngwr-badge.mjs +28 -13
  28. package/fesm2022/ngwr-badge.mjs.map +1 -1
  29. package/fesm2022/ngwr-bar-chart-testing.mjs.map +1 -1
  30. package/fesm2022/ngwr-bar-chart.mjs +3 -3
  31. package/fesm2022/ngwr-bar-chart.mjs.map +1 -1
  32. package/fesm2022/ngwr-blur-text-testing.mjs.map +1 -1
  33. package/fesm2022/ngwr-blur-text.mjs +3 -3
  34. package/fesm2022/ngwr-blur-text.mjs.map +1 -1
  35. package/fesm2022/ngwr-border-glow-testing.mjs.map +1 -1
  36. package/fesm2022/ngwr-border-glow.mjs +3 -3
  37. package/fesm2022/ngwr-border-glow.mjs.map +1 -1
  38. package/fesm2022/ngwr-breadcrumbs.mjs +6 -6
  39. package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
  40. package/fesm2022/ngwr-burger.mjs +3 -3
  41. package/fesm2022/ngwr-burger.mjs.map +1 -1
  42. package/fesm2022/ngwr-button-testing.mjs.map +1 -1
  43. package/fesm2022/ngwr-button.mjs +6 -6
  44. package/fesm2022/ngwr-button.mjs.map +1 -1
  45. package/fesm2022/ngwr-calendar-heatmap-testing.mjs.map +1 -1
  46. package/fesm2022/ngwr-calendar-heatmap.mjs +3 -3
  47. package/fesm2022/ngwr-calendar-heatmap.mjs.map +1 -1
  48. package/fesm2022/ngwr-calendar-testing.mjs.map +1 -1
  49. package/fesm2022/ngwr-calendar.mjs +3 -3
  50. package/fesm2022/ngwr-calendar.mjs.map +1 -1
  51. package/fesm2022/ngwr-card.mjs +9 -9
  52. package/fesm2022/ngwr-card.mjs.map +1 -1
  53. package/fesm2022/ngwr-carousel-testing.mjs.map +1 -1
  54. package/fesm2022/ngwr-carousel.mjs +6 -6
  55. package/fesm2022/ngwr-carousel.mjs.map +1 -1
  56. package/fesm2022/ngwr-cascader-testing.mjs.map +1 -1
  57. package/fesm2022/ngwr-cascader.mjs +4 -4
  58. package/fesm2022/ngwr-cascader.mjs.map +1 -1
  59. package/fesm2022/ngwr-checkbox-testing.mjs.map +1 -1
  60. package/fesm2022/ngwr-checkbox.mjs +6 -6
  61. package/fesm2022/ngwr-checkbox.mjs.map +1 -1
  62. package/fesm2022/ngwr-circular-text-testing.mjs.map +1 -1
  63. package/fesm2022/ngwr-circular-text.mjs +3 -3
  64. package/fesm2022/ngwr-circular-text.mjs.map +1 -1
  65. package/fesm2022/ngwr-click-spark.mjs +3 -3
  66. package/fesm2022/ngwr-click-spark.mjs.map +1 -1
  67. package/fesm2022/ngwr-clipboard.mjs +3 -3
  68. package/fesm2022/ngwr-clipboard.mjs.map +1 -1
  69. package/fesm2022/ngwr-collapse-testing.mjs.map +1 -1
  70. package/fesm2022/ngwr-collapse.mjs +9 -9
  71. package/fesm2022/ngwr-collapse.mjs.map +1 -1
  72. package/fesm2022/ngwr-color-picker-testing.mjs.map +1 -1
  73. package/fesm2022/ngwr-color-picker.mjs +6 -6
  74. package/fesm2022/ngwr-color-picker.mjs.map +1 -1
  75. package/fesm2022/ngwr-command-palette-testing.mjs.map +1 -1
  76. package/fesm2022/ngwr-command-palette.mjs +3 -3
  77. package/fesm2022/ngwr-command-palette.mjs.map +1 -1
  78. package/fesm2022/ngwr-compare.mjs +3 -3
  79. package/fesm2022/ngwr-compare.mjs.map +1 -1
  80. package/fesm2022/ngwr-confetti.mjs +3 -3
  81. package/fesm2022/ngwr-confetti.mjs.map +1 -1
  82. package/fesm2022/ngwr-config.mjs.map +1 -1
  83. package/fesm2022/ngwr-context-menu-testing.mjs.map +1 -1
  84. package/fesm2022/ngwr-context-menu.mjs +12 -12
  85. package/fesm2022/ngwr-context-menu.mjs.map +1 -1
  86. package/fesm2022/ngwr-cookie.mjs +3 -3
  87. package/fesm2022/ngwr-cookie.mjs.map +1 -1
  88. package/fesm2022/ngwr-counter.mjs +6 -6
  89. package/fesm2022/ngwr-counter.mjs.map +1 -1
  90. package/fesm2022/ngwr-date-adapters-fns.mjs +3 -3
  91. package/fesm2022/ngwr-date-adapters-fns.mjs.map +1 -1
  92. package/fesm2022/ngwr-date-adapters-luxon.mjs +3 -3
  93. package/fesm2022/ngwr-date-adapters-luxon.mjs.map +1 -1
  94. package/fesm2022/ngwr-date-picker-testing.mjs.map +1 -1
  95. package/fesm2022/ngwr-date-picker.mjs +21 -21
  96. package/fesm2022/ngwr-date-picker.mjs.map +1 -1
  97. package/fesm2022/ngwr-date.mjs +3 -3
  98. package/fesm2022/ngwr-date.mjs.map +1 -1
  99. package/fesm2022/ngwr-decrypt-text-testing.mjs.map +1 -1
  100. package/fesm2022/ngwr-decrypt-text.mjs +3 -3
  101. package/fesm2022/ngwr-decrypt-text.mjs.map +1 -1
  102. package/fesm2022/ngwr-density.mjs +6 -6
  103. package/fesm2022/ngwr-density.mjs.map +1 -1
  104. package/fesm2022/ngwr-descriptions.mjs +6 -6
  105. package/fesm2022/ngwr-descriptions.mjs.map +1 -1
  106. package/fesm2022/ngwr-dialog-testing.mjs.map +1 -1
  107. package/fesm2022/ngwr-dialog.mjs +15 -15
  108. package/fesm2022/ngwr-dialog.mjs.map +1 -1
  109. package/fesm2022/ngwr-directives.mjs +12 -12
  110. package/fesm2022/ngwr-directives.mjs.map +1 -1
  111. package/fesm2022/ngwr-divider.mjs +3 -3
  112. package/fesm2022/ngwr-divider.mjs.map +1 -1
  113. package/fesm2022/ngwr-donut-chart-testing.mjs.map +1 -1
  114. package/fesm2022/ngwr-donut-chart.mjs +3 -3
  115. package/fesm2022/ngwr-donut-chart.mjs.map +1 -1
  116. package/fesm2022/ngwr-drag-drop.mjs +6 -6
  117. package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
  118. package/fesm2022/ngwr-drawer-testing.mjs.map +1 -1
  119. package/fesm2022/ngwr-drawer.mjs +18 -18
  120. package/fesm2022/ngwr-drawer.mjs.map +1 -1
  121. package/fesm2022/ngwr-dropdown-testing.mjs.map +1 -1
  122. package/fesm2022/ngwr-dropdown.mjs +9 -9
  123. package/fesm2022/ngwr-dropdown.mjs.map +1 -1
  124. package/fesm2022/ngwr-editor-testing.mjs +568 -0
  125. package/fesm2022/ngwr-editor-testing.mjs.map +1 -0
  126. package/fesm2022/ngwr-editor.mjs +2601 -0
  127. package/fesm2022/ngwr-editor.mjs.map +1 -0
  128. package/fesm2022/ngwr-empty.mjs +3 -3
  129. package/fesm2022/ngwr-empty.mjs.map +1 -1
  130. package/fesm2022/ngwr-event-calendar-testing.mjs.map +1 -1
  131. package/fesm2022/ngwr-event-calendar.mjs +6 -6
  132. package/fesm2022/ngwr-event-calendar.mjs.map +1 -1
  133. package/fesm2022/ngwr-falling-text-testing.mjs.map +1 -1
  134. package/fesm2022/ngwr-falling-text.mjs +3 -3
  135. package/fesm2022/ngwr-falling-text.mjs.map +1 -1
  136. package/fesm2022/ngwr-file-upload-testing.mjs.map +1 -1
  137. package/fesm2022/ngwr-file-upload.mjs +3 -3
  138. package/fesm2022/ngwr-file-upload.mjs.map +1 -1
  139. package/fesm2022/ngwr-form-testing.mjs.map +1 -1
  140. package/fesm2022/ngwr-form.mjs +9 -9
  141. package/fesm2022/ngwr-form.mjs.map +1 -1
  142. package/fesm2022/ngwr-fuzzy-text-testing.mjs.map +1 -1
  143. package/fesm2022/ngwr-fuzzy-text.mjs +3 -3
  144. package/fesm2022/ngwr-fuzzy-text.mjs.map +1 -1
  145. package/fesm2022/ngwr-gauge-testing.mjs.map +1 -1
  146. package/fesm2022/ngwr-gauge.mjs +3 -3
  147. package/fesm2022/ngwr-gauge.mjs.map +1 -1
  148. package/fesm2022/ngwr-glitch-text-testing.mjs.map +1 -1
  149. package/fesm2022/ngwr-glitch-text.mjs +3 -3
  150. package/fesm2022/ngwr-glitch-text.mjs.map +1 -1
  151. package/fesm2022/ngwr-gradient-text-testing.mjs.map +1 -1
  152. package/fesm2022/ngwr-gradient-text.mjs +3 -3
  153. package/fesm2022/ngwr-gradient-text.mjs.map +1 -1
  154. package/fesm2022/ngwr-graph-testing.mjs.map +1 -1
  155. package/fesm2022/ngwr-graph.mjs +6 -6
  156. package/fesm2022/ngwr-graph.mjs.map +1 -1
  157. package/fesm2022/ngwr-hotkey.mjs +6 -6
  158. package/fesm2022/ngwr-hotkey.mjs.map +1 -1
  159. package/fesm2022/ngwr-i18n-ar.mjs +29 -0
  160. package/fesm2022/ngwr-i18n-ar.mjs.map +1 -1
  161. package/fesm2022/ngwr-i18n-cs.mjs +29 -0
  162. package/fesm2022/ngwr-i18n-cs.mjs.map +1 -1
  163. package/fesm2022/ngwr-i18n-de.mjs +29 -0
  164. package/fesm2022/ngwr-i18n-de.mjs.map +1 -1
  165. package/fesm2022/ngwr-i18n-en.mjs +34 -0
  166. package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
  167. package/fesm2022/ngwr-i18n-es.mjs +29 -0
  168. package/fesm2022/ngwr-i18n-es.mjs.map +1 -1
  169. package/fesm2022/ngwr-i18n-fr.mjs +29 -0
  170. package/fesm2022/ngwr-i18n-fr.mjs.map +1 -1
  171. package/fesm2022/ngwr-i18n-he.mjs +29 -0
  172. package/fesm2022/ngwr-i18n-he.mjs.map +1 -1
  173. package/fesm2022/ngwr-i18n-hi.mjs +29 -0
  174. package/fesm2022/ngwr-i18n-hi.mjs.map +1 -1
  175. package/fesm2022/ngwr-i18n-id.mjs +29 -0
  176. package/fesm2022/ngwr-i18n-id.mjs.map +1 -1
  177. package/fesm2022/ngwr-i18n-it.mjs +29 -0
  178. package/fesm2022/ngwr-i18n-it.mjs.map +1 -1
  179. package/fesm2022/ngwr-i18n-ja.mjs +29 -0
  180. package/fesm2022/ngwr-i18n-ja.mjs.map +1 -1
  181. package/fesm2022/ngwr-i18n-ko.mjs +29 -0
  182. package/fesm2022/ngwr-i18n-ko.mjs.map +1 -1
  183. package/fesm2022/ngwr-i18n-nl.mjs +29 -0
  184. package/fesm2022/ngwr-i18n-nl.mjs.map +1 -1
  185. package/fesm2022/ngwr-i18n-pl.mjs +29 -0
  186. package/fesm2022/ngwr-i18n-pl.mjs.map +1 -1
  187. package/fesm2022/ngwr-i18n-pt.mjs +29 -0
  188. package/fesm2022/ngwr-i18n-pt.mjs.map +1 -1
  189. package/fesm2022/ngwr-i18n-ru.mjs +29 -0
  190. package/fesm2022/ngwr-i18n-ru.mjs.map +1 -1
  191. package/fesm2022/ngwr-i18n-sv.mjs +29 -0
  192. package/fesm2022/ngwr-i18n-sv.mjs.map +1 -1
  193. package/fesm2022/ngwr-i18n-tr.mjs +29 -0
  194. package/fesm2022/ngwr-i18n-tr.mjs.map +1 -1
  195. package/fesm2022/ngwr-i18n-uk.mjs +29 -0
  196. package/fesm2022/ngwr-i18n-uk.mjs.map +1 -1
  197. package/fesm2022/ngwr-i18n-vi.mjs +29 -0
  198. package/fesm2022/ngwr-i18n-vi.mjs.map +1 -1
  199. package/fesm2022/ngwr-i18n-zh-TW.mjs +29 -0
  200. package/fesm2022/ngwr-i18n-zh-TW.mjs.map +1 -1
  201. package/fesm2022/ngwr-i18n-zh.mjs +29 -0
  202. package/fesm2022/ngwr-i18n-zh.mjs.map +1 -1
  203. package/fesm2022/ngwr-i18n.mjs +9 -9
  204. package/fesm2022/ngwr-i18n.mjs.map +1 -1
  205. package/fesm2022/ngwr-icon-adapters-feather.mjs.map +1 -1
  206. package/fesm2022/ngwr-icon-adapters-lucide.mjs.map +1 -1
  207. package/fesm2022/ngwr-icon.mjs +6 -6
  208. package/fesm2022/ngwr-icon.mjs.map +1 -1
  209. package/fesm2022/ngwr-image-cropper-testing.mjs.map +1 -1
  210. package/fesm2022/ngwr-image-cropper.mjs +3 -3
  211. package/fesm2022/ngwr-image-cropper.mjs.map +1 -1
  212. package/fesm2022/ngwr-input-number-testing.mjs.map +1 -1
  213. package/fesm2022/ngwr-input-number.mjs +3 -3
  214. package/fesm2022/ngwr-input-number.mjs.map +1 -1
  215. package/fesm2022/ngwr-input-otp-testing.mjs.map +1 -1
  216. package/fesm2022/ngwr-input-otp.mjs +3 -3
  217. package/fesm2022/ngwr-input-otp.mjs.map +1 -1
  218. package/fesm2022/ngwr-input-testing.mjs.map +1 -1
  219. package/fesm2022/ngwr-input.mjs +15 -15
  220. package/fesm2022/ngwr-input.mjs.map +1 -1
  221. package/fesm2022/ngwr-keyboard.mjs +3 -3
  222. package/fesm2022/ngwr-keyboard.mjs.map +1 -1
  223. package/fesm2022/ngwr-knob-testing.mjs.map +1 -1
  224. package/fesm2022/ngwr-knob.mjs +3 -3
  225. package/fesm2022/ngwr-knob.mjs.map +1 -1
  226. package/fesm2022/ngwr-layout.mjs +15 -15
  227. package/fesm2022/ngwr-layout.mjs.map +1 -1
  228. package/fesm2022/ngwr-lightbox-testing.mjs.map +1 -1
  229. package/fesm2022/ngwr-lightbox.mjs +3 -3
  230. package/fesm2022/ngwr-lightbox.mjs.map +1 -1
  231. package/fesm2022/ngwr-line-chart-testing.mjs.map +1 -1
  232. package/fesm2022/ngwr-line-chart.mjs +3 -3
  233. package/fesm2022/ngwr-line-chart.mjs.map +1 -1
  234. package/fesm2022/ngwr-list.mjs +6 -6
  235. package/fesm2022/ngwr-list.mjs.map +1 -1
  236. package/fesm2022/ngwr-loading-bar-router.mjs.map +1 -1
  237. package/fesm2022/ngwr-loading-bar.mjs +6 -6
  238. package/fesm2022/ngwr-loading-bar.mjs.map +1 -1
  239. package/fesm2022/ngwr-markdown-testing.mjs.map +1 -1
  240. package/fesm2022/ngwr-markdown.mjs +798 -17
  241. package/fesm2022/ngwr-markdown.mjs.map +1 -1
  242. package/fesm2022/ngwr-marquee-testing.mjs.map +1 -1
  243. package/fesm2022/ngwr-marquee.mjs +3 -3
  244. package/fesm2022/ngwr-marquee.mjs.map +1 -1
  245. package/fesm2022/ngwr-media.mjs +3 -3
  246. package/fesm2022/ngwr-media.mjs.map +1 -1
  247. package/fesm2022/ngwr-mention-testing.mjs.map +1 -1
  248. package/fesm2022/ngwr-mention.mjs +6 -6
  249. package/fesm2022/ngwr-mention.mjs.map +1 -1
  250. package/fesm2022/ngwr-meta.mjs +6 -6
  251. package/fesm2022/ngwr-meta.mjs.map +1 -1
  252. package/fesm2022/ngwr-meter-group-testing.mjs.map +1 -1
  253. package/fesm2022/ngwr-meter-group.mjs +3 -3
  254. package/fesm2022/ngwr-meter-group.mjs.map +1 -1
  255. package/fesm2022/ngwr-overlay.mjs +6 -6
  256. package/fesm2022/ngwr-overlay.mjs.map +1 -1
  257. package/fesm2022/ngwr-page-header.mjs +3 -3
  258. package/fesm2022/ngwr-page-header.mjs.map +1 -1
  259. package/fesm2022/ngwr-pagination-testing.mjs.map +1 -1
  260. package/fesm2022/ngwr-pagination.mjs +3 -3
  261. package/fesm2022/ngwr-pagination.mjs.map +1 -1
  262. package/fesm2022/ngwr-pipes.mjs +21 -21
  263. package/fesm2022/ngwr-pipes.mjs.map +1 -1
  264. package/fesm2022/ngwr-platform.mjs +9 -9
  265. package/fesm2022/ngwr-platform.mjs.map +1 -1
  266. package/fesm2022/ngwr-popconfirm-testing.mjs.map +1 -1
  267. package/fesm2022/ngwr-popconfirm.mjs +6 -6
  268. package/fesm2022/ngwr-popconfirm.mjs.map +1 -1
  269. package/fesm2022/ngwr-popover-testing.mjs.map +1 -1
  270. package/fesm2022/ngwr-popover.mjs +12 -12
  271. package/fesm2022/ngwr-popover.mjs.map +1 -1
  272. package/fesm2022/ngwr-progress.mjs +3 -3
  273. package/fesm2022/ngwr-progress.mjs.map +1 -1
  274. package/fesm2022/ngwr-pull-to-refresh.mjs +3 -3
  275. package/fesm2022/ngwr-pull-to-refresh.mjs.map +1 -1
  276. package/fesm2022/ngwr-qr.mjs +3 -3
  277. package/fesm2022/ngwr-qr.mjs.map +1 -1
  278. package/fesm2022/ngwr-radio-testing.mjs.map +1 -1
  279. package/fesm2022/ngwr-radio.mjs +6 -6
  280. package/fesm2022/ngwr-radio.mjs.map +1 -1
  281. package/fesm2022/ngwr-rating-testing.mjs.map +1 -1
  282. package/fesm2022/ngwr-rating.mjs +3 -3
  283. package/fesm2022/ngwr-rating.mjs.map +1 -1
  284. package/fesm2022/ngwr-result.mjs +12 -12
  285. package/fesm2022/ngwr-result.mjs.map +1 -1
  286. package/fesm2022/ngwr-rotating-text-testing.mjs.map +1 -1
  287. package/fesm2022/ngwr-rotating-text.mjs +3 -3
  288. package/fesm2022/ngwr-rotating-text.mjs.map +1 -1
  289. package/fesm2022/ngwr-schema-form.mjs +3 -3
  290. package/fesm2022/ngwr-schema-form.mjs.map +1 -1
  291. package/fesm2022/ngwr-scroll.mjs +3 -3
  292. package/fesm2022/ngwr-scroll.mjs.map +1 -1
  293. package/fesm2022/ngwr-segmented-testing.mjs.map +1 -1
  294. package/fesm2022/ngwr-segmented.mjs +3 -3
  295. package/fesm2022/ngwr-segmented.mjs.map +1 -1
  296. package/fesm2022/ngwr-select-testing.mjs.map +1 -1
  297. package/fesm2022/ngwr-select.mjs +12 -12
  298. package/fesm2022/ngwr-select.mjs.map +1 -1
  299. package/fesm2022/ngwr-shiny-text-testing.mjs.map +1 -1
  300. package/fesm2022/ngwr-shiny-text.mjs +6 -6
  301. package/fesm2022/ngwr-shiny-text.mjs.map +1 -1
  302. package/fesm2022/ngwr-sidebar.mjs +3 -3
  303. package/fesm2022/ngwr-sidebar.mjs.map +1 -1
  304. package/fesm2022/ngwr-skeleton.mjs +3 -3
  305. package/fesm2022/ngwr-skeleton.mjs.map +1 -1
  306. package/fesm2022/ngwr-slider-testing.mjs.map +1 -1
  307. package/fesm2022/ngwr-slider.mjs +3 -3
  308. package/fesm2022/ngwr-slider.mjs.map +1 -1
  309. package/fesm2022/ngwr-sparkline-testing.mjs.map +1 -1
  310. package/fesm2022/ngwr-sparkline.mjs +3 -3
  311. package/fesm2022/ngwr-sparkline.mjs.map +1 -1
  312. package/fesm2022/ngwr-speed-dial-testing.mjs.map +1 -1
  313. package/fesm2022/ngwr-speed-dial.mjs +3 -3
  314. package/fesm2022/ngwr-speed-dial.mjs.map +1 -1
  315. package/fesm2022/ngwr-spinner.mjs +3 -3
  316. package/fesm2022/ngwr-spinner.mjs.map +1 -1
  317. package/fesm2022/ngwr-splash-cursor-testing.mjs.map +1 -1
  318. package/fesm2022/ngwr-splash-cursor.mjs +3 -3
  319. package/fesm2022/ngwr-splash-cursor.mjs.map +1 -1
  320. package/fesm2022/ngwr-split-text-testing.mjs.map +1 -1
  321. package/fesm2022/ngwr-split-text.mjs +3 -3
  322. package/fesm2022/ngwr-split-text.mjs.map +1 -1
  323. package/fesm2022/ngwr-splitter-testing.mjs.map +1 -1
  324. package/fesm2022/ngwr-splitter.mjs +3 -3
  325. package/fesm2022/ngwr-splitter.mjs.map +1 -1
  326. package/fesm2022/ngwr-spotlight-card-testing.mjs.map +1 -1
  327. package/fesm2022/ngwr-spotlight-card.mjs +6 -6
  328. package/fesm2022/ngwr-spotlight-card.mjs.map +1 -1
  329. package/fesm2022/ngwr-squircle.mjs +6 -6
  330. package/fesm2022/ngwr-squircle.mjs.map +1 -1
  331. package/fesm2022/ngwr-star-border-testing.mjs.map +1 -1
  332. package/fesm2022/ngwr-star-border.mjs +3 -3
  333. package/fesm2022/ngwr-star-border.mjs.map +1 -1
  334. package/fesm2022/ngwr-statistic.mjs +9 -9
  335. package/fesm2022/ngwr-statistic.mjs.map +1 -1
  336. package/fesm2022/ngwr-stepper-testing.mjs.map +1 -1
  337. package/fesm2022/ngwr-stepper.mjs +6 -6
  338. package/fesm2022/ngwr-stepper.mjs.map +1 -1
  339. package/fesm2022/ngwr-storage.mjs +3 -3
  340. package/fesm2022/ngwr-storage.mjs.map +1 -1
  341. package/fesm2022/ngwr-switch-testing.mjs.map +1 -1
  342. package/fesm2022/ngwr-switch.mjs +3 -3
  343. package/fesm2022/ngwr-switch.mjs.map +1 -1
  344. package/fesm2022/ngwr-table-testing.mjs.map +1 -1
  345. package/fesm2022/ngwr-table.mjs +18 -18
  346. package/fesm2022/ngwr-table.mjs.map +1 -1
  347. package/fesm2022/ngwr-tabs-router.mjs +3 -3
  348. package/fesm2022/ngwr-tabs-router.mjs.map +1 -1
  349. package/fesm2022/ngwr-tabs-testing.mjs.map +1 -1
  350. package/fesm2022/ngwr-tabs.mjs +6 -6
  351. package/fesm2022/ngwr-tabs.mjs.map +1 -1
  352. package/fesm2022/ngwr-textarea-testing.mjs.map +1 -1
  353. package/fesm2022/ngwr-textarea.mjs +3 -3
  354. package/fesm2022/ngwr-textarea.mjs.map +1 -1
  355. package/fesm2022/ngwr-theme.mjs +3 -3
  356. package/fesm2022/ngwr-theme.mjs.map +1 -1
  357. package/fesm2022/ngwr-tilt-card-testing.mjs.map +1 -1
  358. package/fesm2022/ngwr-tilt-card.mjs +6 -6
  359. package/fesm2022/ngwr-tilt-card.mjs.map +1 -1
  360. package/fesm2022/ngwr-timeline.mjs +6 -6
  361. package/fesm2022/ngwr-timeline.mjs.map +1 -1
  362. package/fesm2022/ngwr-toast-testing.mjs.map +1 -1
  363. package/fesm2022/ngwr-toast.mjs +9 -9
  364. package/fesm2022/ngwr-toast.mjs.map +1 -1
  365. package/fesm2022/ngwr-toolbar.mjs +3 -3
  366. package/fesm2022/ngwr-toolbar.mjs.map +1 -1
  367. package/fesm2022/ngwr-tour-testing.mjs.map +1 -1
  368. package/fesm2022/ngwr-tour.mjs +6 -6
  369. package/fesm2022/ngwr-tour.mjs.map +1 -1
  370. package/fesm2022/ngwr-transfer-testing.mjs.map +1 -1
  371. package/fesm2022/ngwr-transfer.mjs +3 -3
  372. package/fesm2022/ngwr-transfer.mjs.map +1 -1
  373. package/fesm2022/ngwr-tree-testing.mjs.map +1 -1
  374. package/fesm2022/ngwr-tree.mjs +3 -3
  375. package/fesm2022/ngwr-tree.mjs.map +1 -1
  376. package/fesm2022/ngwr-typewriter-testing.mjs.map +1 -1
  377. package/fesm2022/ngwr-typewriter.mjs +3 -3
  378. package/fesm2022/ngwr-typewriter.mjs.map +1 -1
  379. package/fesm2022/ngwr-typography.mjs +7 -3
  380. package/fesm2022/ngwr-typography.mjs.map +1 -1
  381. package/fesm2022/ngwr-utils.mjs.map +1 -1
  382. package/fesm2022/ngwr-validators.mjs.map +1 -1
  383. package/fesm2022/ngwr-version.mjs +1 -1
  384. package/fesm2022/ngwr-version.mjs.map +1 -1
  385. package/fesm2022/ngwr-virtual-scroll.mjs +3 -3
  386. package/fesm2022/ngwr-virtual-scroll.mjs.map +1 -1
  387. package/fesm2022/ngwr-waves-testing.mjs.map +1 -1
  388. package/fesm2022/ngwr-waves.mjs +3 -3
  389. package/fesm2022/ngwr-waves.mjs.map +1 -1
  390. package/fesm2022/ngwr-window-testing.mjs.map +1 -1
  391. package/fesm2022/ngwr-window.mjs +12 -12
  392. package/fesm2022/ngwr-window.mjs.map +1 -1
  393. package/form/styles/_index.scss +5 -0
  394. package/i18n/ar.json +29 -0
  395. package/i18n/cs.json +29 -0
  396. package/i18n/de.json +29 -0
  397. package/i18n/en.json +29 -0
  398. package/i18n/es.json +29 -0
  399. package/i18n/fr.json +29 -0
  400. package/i18n/he.json +29 -0
  401. package/i18n/hi.json +29 -0
  402. package/i18n/id.json +29 -0
  403. package/i18n/it.json +29 -0
  404. package/i18n/ja.json +29 -0
  405. package/i18n/ko.json +29 -0
  406. package/i18n/nl.json +29 -0
  407. package/i18n/pl.json +29 -0
  408. package/i18n/pt.json +29 -0
  409. package/i18n/ru.json +29 -0
  410. package/i18n/sv.json +29 -0
  411. package/i18n/tr.json +29 -0
  412. package/i18n/uk.json +29 -0
  413. package/i18n/vi.json +29 -0
  414. package/i18n/zh-TW.json +29 -0
  415. package/i18n/zh.json +29 -0
  416. package/input/styles/_index.scss +5 -1
  417. package/input-otp/styles/_index.scss +5 -5
  418. package/llms-full.txt +11 -1
  419. package/llms.txt +188 -132
  420. package/mcp/providers.js +2 -2
  421. package/mcp/server.js +1 -1
  422. package/overlay/styles/_arrow.scss +3 -0
  423. package/package.json +43 -2
  424. package/progress/styles/_index.scss +4 -0
  425. package/radio/styles/_index.scss +4 -1
  426. package/schematics/use/symbol-map.json +1 -0
  427. package/select/styles/_index.scss +3 -3
  428. package/sidebar/styles/_index.scss +10 -0
  429. package/skeleton/styles/_index.scss +3 -0
  430. package/skills/ngwr/SKILL.md +5 -5
  431. package/skills/ngwr/references/catalog.md +2 -0
  432. package/skills/ngwr/references/setup.md +3 -3
  433. package/styles.scss +1 -0
  434. package/table/styles/_index.scss +7 -0
  435. package/textarea/styles/_index.scss +12 -3
  436. package/theme/styles/_colors.scss +39 -13
  437. package/theme/styles/_contrast.scss +9 -7
  438. package/toast/styles/_index.scss +4 -0
  439. package/tree/styles/_index.scss +1 -1
  440. package/types/ngwr-badge.d.ts +22 -7
  441. package/types/ngwr-config.d.ts +12 -0
  442. package/types/ngwr-editor-testing.d.ts +378 -0
  443. package/types/ngwr-editor.d.ts +449 -0
  444. package/types/ngwr-markdown.d.ts +61 -2
  445. package/types/ngwr-typography.d.ts +4 -0
  446. package/types/ngwr-version.d.ts +1 -1
  447. package/typography/styles/_index.scss +16 -0
@@ -1 +1 @@
1
- {"version":3,"file":"ngwr-tree-testing.mjs","sources":["../../../projects/lib/tree/testing/wr-tree-node-harness.ts","../../../projects/lib/tree/testing/wr-tree-harness.ts","../../../projects/lib/tree/testing/ngwr-tree-testing.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { ComponentHarness, HarnessPredicate, type TestElement } from '@angular/cdk/testing';\n\nimport type { WrTreeNodeHarnessFilters } from './interfaces';\n\n/**\n * Test harness for one node of a `<wr-tree>` — a `role=\"treeitem\"` row.\n *\n * Everything about a tree's shape that a screen reader gets lives on these rows:\n * the list itself is FLAT, with no `role=\"group\"` and no nesting, so `aria-level`,\n * `aria-posinset` and `aria-setsize` are the only place the hierarchy exists. The\n * indent is decoration.\n *\n * @example\n * ```ts\n * const src = await tree.getNode({ label: 'src' });\n *\n * await src.expand();\n * expect(await src.getLevel()).toBe(1);\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrTreeNodeHarness extends ComponentHarness {\n /**\n * The row, and nothing else the list can hold.\n *\n * A windowed tree pads its list with `<li class=\"wr-tree__spacer\" role=\"presentation\">`\n * at each end, so `li` would hand back up to two \"nodes\" with no label and no\n * state. `[role=\"treeitem\"]` selects exactly the same set as this class.\n */\n static hostSelector = '.wr-tree__row';\n\n /** Build a predicate that narrows the query. */\n static with(options: WrTreeNodeHarnessFilters = {}): HarnessPredicate<WrTreeNodeHarness> {\n return new HarnessPredicate(WrTreeNodeHarness, options)\n .addOption('label', options.label, (harness, label) => HarnessPredicate.stringMatches(harness.getLabel(), label))\n .addOption('selected', options.selected, async (harness, selected) => (await harness.isSelected()) === selected)\n .addOption('disabled', options.disabled, async (harness, disabled) => (await harness.isDisabled()) === disabled)\n .addOption(\n 'expanded',\n options.expanded,\n // A leaf is not a closed branch: it announces no `aria-expanded` at all, so\n // it matches neither value rather than answering `false` and turning\n // `{ expanded: false }` into \"every row that is not open\".\n async (harness, expanded) => (await harness.isExpandable()) && (await harness.isExpanded()) === expanded\n )\n .addOption('level', options.level, async (harness, level) => (await harness.getLevel()) === level);\n }\n\n /**\n * The node's label.\n *\n * Read from `.wr-tree__label` rather than from the row's text, so the answer stays\n * the label alone however the row is decorated around it.\n */\n async getLabel(): Promise<string> {\n return (await this.locatorFor('.wr-tree__label')()).text();\n }\n\n /** The node's 1-based depth, as the row announces it (`aria-level`). */\n async getLevel(): Promise<number> {\n return this.announcedNumber('aria-level');\n }\n\n /**\n * The node's 1-based position within its SIBLING GROUP (`aria-posinset`) — not its\n * position in the flat list of visible rows.\n *\n * `src`'s first child is `posinset` 1 even though it is the second row on screen.\n * That is what ARIA asks for, and the whole reason the attribute is needed here:\n * the rendered list cannot express the nesting on its own.\n */\n async getPosInSet(): Promise<number> {\n return this.announcedNumber('aria-posinset');\n }\n\n /** How many nodes are in this node's sibling group, itself included (`aria-setsize`). */\n async getSetSize(): Promise<number> {\n return this.announcedNumber('aria-setsize');\n }\n\n /**\n * The node's index in the full list of VISIBLE nodes — every rendered row plus the\n * ones a window left out, in the order the tree would show them.\n *\n * It is the index the tree's own keyboard code addresses rows by, and while the\n * tree is windowed it is the only way to place a row: DOM order then says nothing,\n * because the rows in the DOM are a slice.\n */\n async getIndex(): Promise<number> {\n return this.announcedNumber('data-tree-index');\n }\n\n /**\n * The row's DOM id, or `null`.\n *\n * Only a windowed tree gives its rows ids, because that is the shape where the\n * list keeps focus and names the cursor row with `aria-activedescendant` — the id\n * exists to be pointed at.\n */\n async getId(): Promise<string | null> {\n return (await this.host()).getAttribute('id');\n }\n\n /**\n * Whether the node is a branch — it has children, whether or not they are showing.\n *\n * From `aria-expanded`: only a branch carries it, and a branch that does not is\n * announced as a leaf, so the user never learns there is anything underneath. The\n * toggle element cannot answer this — a leaf renders a `<span>` with the same\n * `.wr-tree__toggle` class purely to hold the indent.\n */\n async isExpandable(): Promise<boolean> {\n return (await (await this.host()).getAttribute('aria-expanded')) !== null;\n }\n\n /** Whether the branch is open. A leaf is never expanded. */\n async isExpanded(): Promise<boolean> {\n return (await (await this.host()).getAttribute('aria-expanded')) === 'true';\n }\n\n /** Open the branch. Already-open branches are left alone; a leaf throws. */\n async expand(): Promise<void> {\n if (await this.isExpanded()) return;\n await this.toggleExpand();\n\n if (!(await this.isExpanded())) {\n throw new Error(\n `WrTreeNodeHarness.expand(): \"${await this.getLabel()}\" did not open. A disabled node ignores its ` +\n 'own toggle, and so does every node of a disabled tree.'\n );\n }\n }\n\n /** Close the branch. Already-closed branches are left alone; a leaf throws. */\n async collapse(): Promise<void> {\n if (!(await this.isExpanded())) {\n // A closed branch is fine to ask twice; a leaf is a mistake worth naming.\n await this.toggleElement();\n return;\n }\n await this.toggleExpand();\n\n if (await this.isExpanded()) {\n throw new Error(\n `WrTreeNodeHarness.collapse(): \"${await this.getLabel()}\" did not close. A disabled node ignores ` +\n 'its own toggle, and so does every node of a disabled tree.'\n );\n }\n }\n\n /**\n * Click the branch's expand toggle.\n *\n * Expanding is the TOGGLE's job and not the row's: a click anywhere else in the row\n * selects instead, which is the one thing a spec driving this by hand tends to get\n * wrong.\n */\n async toggleExpand(): Promise<void> {\n await (await this.toggleElement()).click();\n }\n\n /**\n * Whether the node is selected.\n *\n * From `aria-selected` rather than the `--selected` modifier: both are public, but\n * the attribute is what a screen reader acts on, and a row that looks selected\n * without saying so is the bug worth catching.\n */\n async isSelected(): Promise<boolean> {\n return (await (await this.host()).getAttribute('aria-selected')) === 'true';\n }\n\n /**\n * Whether the tree offers selection at all.\n *\n * A `selectionMode=\"none\"` tree announces NO `aria-selected` on its rows, which is\n * how an unselectable node differs from one that is merely unselected — the two\n * look identical otherwise.\n */\n async isSelectable(): Promise<boolean> {\n return (await (await this.host()).getAttribute('aria-selected')) !== null;\n }\n\n /**\n * Whether the node refuses interaction (`aria-disabled`).\n *\n * True for EVERY node while the whole tree is disabled, not just for the ones the\n * data marks — the row announces the effective state, which is the one a user runs\n * into.\n */\n async isDisabled(): Promise<boolean> {\n return (await (await this.host()).getAttribute('aria-disabled')) === 'true';\n }\n\n /**\n * Whether the node is where the keyboard cursor sits.\n *\n * The two patterns publish the cursor differently, and this covers both: a tree\n * that renders every row hands the single tab stop to the cursor row (roving\n * tabindex), while a windowed one keeps focus on the list and marks the row with\n * the `--active` modifier plus the list's `aria-activedescendant`.\n * `WrTreeHarness.getActiveNodeLabel()` reads that reference itself.\n */\n async isActive(): Promise<boolean> {\n const host = await this.host();\n return (await host.getAttribute('tabindex')) === '0' || host.hasClass('wr-tree__row--active');\n }\n\n /**\n * Whether the row holds real DOM focus.\n *\n * Deliberately separate from {@link isActive}: in a windowed tree the two DIVERGE\n * by design — focus stays on the `role=\"tree\"` list and only the announced cursor\n * moves — so a spec asserting that a key press moved focus needs to know which of\n * the two it is asking about.\n */\n async isFocused(): Promise<boolean> {\n return (await this.host()).isFocused();\n }\n\n /**\n * Click the node — which SELECTS it. A disabled node, and any node of a\n * `selectionMode=\"none\"` tree, ignores the click.\n *\n * In multi mode a plain click REPLACES the selection rather than adding to it (the\n * component's deliberate choice: one selected node clicked again clears it, and any\n * other click starts over from that node). {@link ctrlClick} is how a selection is\n * accumulated.\n */\n async click(): Promise<void> {\n return (await this.host()).click();\n }\n\n /**\n * Ctrl-click the node — ADDS it to the selection, or removes it, in multi mode.\n *\n * The component takes Cmd as well as Ctrl; the harness sends Ctrl because a unit\n * test has no platform. In single mode it behaves exactly like {@link click}.\n */\n async ctrlClick(): Promise<void> {\n return (await this.host()).click({ control: true });\n }\n\n /** The branch's toggle button, or a failure that says this row is a leaf. */\n private async toggleElement(): Promise<TestElement> {\n // `button` is load-bearing: a leaf renders a `<span>` with the same\n // `.wr-tree__toggle` class to hold the indent, and taking that for a control\n // would report every leaf as a branch that refused to open.\n const toggle = await this.locatorForOptional('button.wr-tree__toggle')();\n if (!toggle) {\n throw new Error(`WrTreeNodeHarness: \"${await this.getLabel()}\" is a leaf — there is no branch to open or close.`);\n }\n return toggle;\n }\n\n /** A numeric attribute every row carries, or a failure that says the row is broken. */\n private async announcedNumber(attribute: string): Promise<number> {\n const value = await (await this.host()).getAttribute(attribute);\n if (value === null) {\n throw new Error(\n `WrTreeNodeHarness: this row announces no \\`${attribute}\\`. Every row of a \\`<wr-tree>\\` carries ` +\n 'one, so a missing value is a rendering fault rather than a state worth reporting as null.'\n );\n }\n return Number.parseInt(value, 10);\n }\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport {\n ContentContainerComponentHarness,\n type HarnessLoader,\n HarnessPredicate,\n TestKey,\n type TestElement,\n} from '@angular/cdk/testing';\n\nimport type { WrTreeHarnessFilters, WrTreeNodeHarnessFilters } from './interfaces';\nimport { WrTreeNodeHarness } from './wr-tree-node-harness';\n\n/** How many levels {@link WrTreeHarness.expandAll} is willing to walk. */\nconst MAX_EXPAND_PASSES = 20;\n\n/**\n * Test harness for `<wr-tree>`, with {@link WrTreeNodeHarness} for one row.\n *\n * The component has two render shapes and this harness covers both:\n * - `openOn=\"inline\"` (default) — the rows live in the host, and the tree is always\n * showing them.\n * - `openOn=\"overlay\"` — a `role=\"combobox\"` trigger opens a panel that is a template\n * portal in the shared overlay container, a sibling of the whole app. Nothing in it\n * is a descendant of the host, so every row is read through the document root,\n * SCOPED by the `aria-controls` id the trigger publishes — which is what keeps two\n * trees on one page from answering with each other's nodes.\n *\n * A tree is data-driven and projects nothing, so the scoped loader exists to point the\n * node queries at the right shape rather than to reach a consumer's own components: the\n * inherited `getHarness(…)` resolves wherever THIS tree's rows are, and there is nothing\n * else in there.\n *\n * Two things the harness cannot do, both jsdom rather than the component:\n * - it never clicks a row by coordinate, and it drives the cursor with the KEYBOARD,\n * which is the accessible path anyway. There is no layout in a unit test, so a\n * hit test would answer with nothing.\n * - it offers no SCROLL for a windowed tree. jsdom does remember a `scrollTop` write,\n * but it fires no `scroll` event for it, so the tree — which learns its offset from\n * that event — would not move until the caller also dispatched one and waited a\n * frame: a scroll gesture that only works because the test faked the notification.\n * The keyboard moves the window honestly instead — see {@link focusLast}. (jsdom has\n * no `Element.scrollTo` at all, which the tree calls while windowed, so a spec for\n * that shape has to stub it.)\n *\n * @example\n * ```ts\n * const tree = await loader.getHarness(WrTreeHarness);\n *\n * await (await tree.getNode({ label: 'src' })).expand();\n * await tree.selectNode({ label: 'main.ts' });\n *\n * expect(await tree.getSelectedLabels()).toEqual(['main.ts']);\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrTreeHarness extends ContentContainerComponentHarness {\n static hostSelector = 'wr-tree';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrTreeHarnessFilters = {}): HarnessPredicate<WrTreeHarness> {\n return new HarnessPredicate(WrTreeHarness, options)\n .addOption('text', options.text, (harness, text) =>\n HarnessPredicate.stringMatches(harness.triggerTextIfAny(), text)\n )\n .addOption('nodeLabel', options.nodeLabel, async (harness, label) => {\n for (const shown of await harness.nodeLabelsIfShowing()) {\n if (await HarnessPredicate.stringMatches(shown, label)) return true;\n }\n return false;\n })\n .addOption('disabled', options.disabled, async (harness, disabled) => (await harness.isDisabled()) === disabled)\n .addOption('open', options.open, async (harness, open) => (await harness.isOpen()) === open);\n }\n\n /** Whether this tree is the combobox shape (`openOn=\"overlay\"`) rather than inline. */\n async isOverlay(): Promise<boolean> {\n return (await this.host()).hasClass('wr-tree--combobox');\n }\n\n /**\n * Whether the rows are showing.\n *\n * From the trigger's `aria-expanded` rather than the `--open` modifier: both are\n * public, but that attribute is the promise the combobox makes to a screen reader.\n * An inline tree is always open — its rows are part of the host and there is\n * nothing to open or close.\n */\n async isOpen(): Promise<boolean> {\n if (!(await this.isOverlay())) return true;\n return (await (await this.trigger()).getAttribute('aria-expanded')) === 'true';\n }\n\n /**\n * Open the panel. An already-open tree — and every inline one — is left alone.\n *\n * Note for a spec with two overlay trees: this clicks, and a click is an outside\n * pointer event for every other open overlay, so it closes any panel already up.\n * There is no second gesture to swap in: the trigger is opened by its `click`\n * handler, and while a real keyboard user reaches that through a `<button>`'s native\n * activation, a SYNTHETIC Enter / Space never produces a click — so a harness cannot\n * open a panel any other way.\n */\n async open(): Promise<void> {\n if (await this.isOpen()) return;\n\n await (await this.trigger()).click();\n if (await this.isOpen()) return;\n\n throw new Error(\n 'WrTreeHarness.open(): the panel did not open. A disabled tree refuses the trigger and closes any ' +\n 'panel that was up, so check `disabled` first.'\n );\n }\n\n /** Close the panel with Escape. An already-closed tree is left alone. */\n async close(): Promise<void> {\n // Not a no-op for an inline tree: asking to close one means the spec believes it\n // has a panel, and it does not.\n const trigger = await this.trigger();\n if (!(await this.isOpen())) return;\n\n // Escape reaches the tree through the CDK's keyboard dispatcher, which hands it to\n // the top-most overlay — so it does not matter that focus may be on a row inside.\n await trigger.sendKeys(TestKey.ESCAPE);\n }\n\n /**\n * Whether the tree refuses interaction.\n *\n * The host modifier is the only answer both shapes carry: an inline tree has no\n * control of its own to mark `disabled`, and a closed overlay tree has no rows to\n * read `aria-disabled` from. The rows do announce it — see\n * {@link WrTreeNodeHarness.isDisabled}.\n */\n async isDisabled(): Promise<boolean> {\n return (await this.host()).hasClass('wr-tree--disabled');\n }\n\n /**\n * Whether the tree takes more than one selected node.\n *\n * From the list's `aria-multiselectable`, which is what a screen reader acts on. The\n * list does not exist while an overlay panel is closed, so the host modifier answers\n * then — it is only painted in the combobox shape, which is exactly the shape that\n * can be asked while closed.\n */\n async isMultiple(): Promise<boolean> {\n if (await this.isOpen()) {\n return (await (await this.list()).getAttribute('aria-multiselectable')) === 'true';\n }\n return (await this.host()).hasClass('wr-tree--multi');\n }\n\n /**\n * How much the tree lets you select.\n *\n * `'none'` is not \"nothing selected\": it is a tree whose rows announce no\n * `aria-selected` at all, and telling that from `'single'` needs a row — so an empty\n * tree throws rather than guessing.\n */\n async getSelectionMode(): Promise<'none' | 'single' | 'multi'> {\n if (await this.isMultiple()) return 'multi';\n\n const [first] = await this.getNodes();\n if (!first) {\n throw new Error(\n 'WrTreeHarness.getSelectionMode(): this tree renders no nodes, and single vs none is only visible ' +\n 'on a row — `selectionMode=\"none\"` is the absence of `aria-selected`, so there is nothing to read.'\n );\n }\n return (await first.isSelectable()) ? 'single' : 'none';\n }\n\n /**\n * Whether the list is WINDOWED right now.\n *\n * Read from the list's modifier rather than from the input, and that is the point:\n * `virtualScroll` only takes effect when there is something to window, so an empty\n * tree renders the plain shape however the input is set.\n */\n async isVirtual(): Promise<boolean> {\n return (await this.list()).hasClass('wr-tree__list--virtual');\n }\n\n /**\n * The role the list announces — `tree`.\n *\n * Worth asking: rendered without it, the rows are a bag of names, identical on\n * screen and structureless to anyone not looking at it.\n */\n async getRole(): Promise<string | null> {\n return (await this.list()).getAttribute('role');\n }\n\n /**\n * What the trigger shows as the selection: the chip labels joined by `', '` in multi\n * mode, the label in single mode, and `''` when nothing is selected (the placeholder\n * is showing). The `+N more` chip a `maxTagCount` produces is NOT part of it — it is\n * a count rather than a selection, and {@link getOverflowText} reads it. Inline trees\n * have no trigger and throw.\n */\n async getValueText(): Promise<string> {\n await this.trigger();\n\n const chips = await this.getChipLabels();\n if (chips.length > 0) return chips.join(', ');\n\n const value = await this.locatorForOptional('.wr-tree__value')();\n return value ? value.text() : '';\n }\n\n /** The placeholder, or `null` when a selection is hiding it. */\n async getPlaceholder(): Promise<string | null> {\n await this.trigger();\n\n const placeholder = await this.locatorForOptional('.wr-tree__placeholder')();\n return placeholder ? placeholder.text() : null;\n }\n\n /**\n * The chip labels on the trigger, in order (multi mode).\n *\n * The `+N more` overflow chip is not one of them — it is a count, not a selection.\n * {@link getOverflowText} reads it.\n */\n async getChipLabels(): Promise<string[]> {\n await this.trigger();\n\n const labels = await this.locatorForAll('.wr-tree__chip-label')();\n return Promise.all(labels.map(label => label.text()));\n }\n\n /**\n * The `+N more` chip's text, or `null` when every selected node has a chip of its\n * own. Only a `maxTagCount` below the number selected produces one.\n */\n async getOverflowText(): Promise<string | null> {\n await this.trigger();\n\n const more = await this.locatorForOptional('.wr-tree__chip--more')();\n return more ? more.text() : null;\n }\n\n /** Remove one chip by its label. */\n async removeChip(label: string): Promise<void> {\n const labels = await this.getChipLabels();\n const index = labels.indexOf(label);\n if (index < 0) {\n throw new Error(\n `WrTreeHarness.removeChip(): no chip labelled \"${label}\". The trigger shows [${labels.join(', ')}] — ` +\n 'a selection past `maxTagCount` has no chip to remove.'\n );\n }\n\n // Label and remove control are emitted once per chip by the same loop, so the two\n // lists line up by index.\n const removes = await this.locatorForAll('.wr-tree__chip-remove')();\n await removes[index].click();\n }\n\n /** Click the clear (×) control on the trigger. */\n async clear(): Promise<void> {\n await this.trigger();\n\n const clear = await this.locatorForOptional('.wr-tree__clear')();\n if (!clear) {\n throw new Error(\n 'WrTreeHarness.clear(): this trigger has no clear control — `clearable` is off, nothing is ' +\n 'selected, or the tree is disabled.'\n );\n }\n await clear.click();\n }\n\n /**\n * Backspace on the closed overlay trigger — the keyboard route to the ×.\n *\n * In single mode it clears (only while `clearable` is on); in multi mode it\n * drops the LAST chip, one per call, whatever `clearable` says. Both ×\n * controls are `tabindex=\"-1\"` spans inside the trigger, so a key can never\n * reach them directly. In single mode this is the ONLY keyboard route back to\n * no selection; in multi mode a keyboard user can also toggle a row off in the\n * panel ({@link selectNode} with `additive`). {@link clear} / {@link removeChip}\n * prove the pointer path and nothing more.\n *\n * The key is honoured only on the CLOSED trigger, so an open panel is closed\n * first with Escape — the step a keyboard user takes too, since focus sits in\n * the panel while it is up.\n *\n * Does nothing, rather than throwing, where the component does nothing —\n * nothing selected, disabled or read-only — so a spec asserts the outcome on\n * the value.\n */\n async clearByKeyboard(): Promise<void> {\n if (await this.isOpen()) await this.close();\n await (await this.trigger()).sendKeys(TestKey.BACKSPACE);\n }\n\n /**\n * The nodes currently rendered, in the order they are shown.\n *\n * A collapsed branch's children are not rendered at all, so this is the VISIBLE\n * tree — expand first to reach deeper.\n *\n * While {@link isVirtual} is true it is narrower still: the list holds only the\n * window around the scroll offset — padded by a spacer at whichever end has rows\n * outside it, so a window resting at the top has one and a window in the middle has\n * two — and this returns the WINDOW, not the dataset. Nothing in the DOM carries a\n * total —\n * `aria-setsize` counts a SIBLING GROUP, not the flat list — so the harness cannot\n * offer one; {@link WrTreeNodeHarness.getIndex} places each row in the full visible\n * list, and the `[nodes]` data is where the total actually lives.\n *\n * Throws while an overlay panel is closed: the rows do not exist anywhere until it\n * opens, and an empty array reads like a tree that rendered nothing.\n */\n async getNodes(filters: WrTreeNodeHarnessFilters = {}): Promise<WrTreeNodeHarness[]> {\n return this.getAllHarnesses(WrTreeNodeHarness.with(filters));\n }\n\n /** The labels of the nodes currently rendered, in order. */\n async getNodeLabels(): Promise<string[]> {\n const nodes = await this.getNodes();\n return Promise.all(nodes.map(node => node.getLabel()));\n }\n\n /** The first node matching the filters, or a failure that says what is showing. */\n async getNode(filters: WrTreeNodeHarnessFilters): Promise<WrTreeNodeHarness> {\n const [node] = await this.getNodes(filters);\n if (!node) {\n const showing = await this.getNodeLabels();\n throw new Error(\n `WrTreeHarness.getNode(): no node matched ${JSON.stringify(filters)}. The tree is showing ` +\n `[${showing.join(', ')}] — a node inside a collapsed branch is not rendered at all, and a ` +\n 'windowed tree only renders its window.'\n );\n }\n return node;\n }\n\n /**\n * Open the panel if needed, then select the first node matching the filters.\n *\n * `additive` ctrl-clicks instead, which is how a multi-mode selection is built up: a\n * plain click there REPLACES the selection, by the component's own choice.\n *\n * Throws rather than clicking into the void on a disabled node or a\n * `selectionMode=\"none\"` tree — both ignore the click, and the silence turns into a\n * confusing failure at the next assertion. Reach for `getNode().click()` when\n * proving exactly that.\n */\n async selectNode(filters: WrTreeNodeHarnessFilters, options: { additive?: boolean } = {}): Promise<void> {\n await this.open();\n\n const node = await this.getNode(filters);\n const label = await node.getLabel();\n\n if (!(await node.isSelectable())) {\n throw new Error(\n `WrTreeHarness.selectNode(): \"${label}\" announces no selected state, so this tree is in ` +\n 'selectionMode=\"none\" — clicking it cannot select anything.'\n );\n }\n if (await node.isDisabled()) {\n throw new Error(\n `WrTreeHarness.selectNode(): \"${label}\" is disabled and the tree ignores the click. A disabled ` +\n 'TREE disables every node — check isDisabled() on the tree too.'\n );\n }\n\n await (options.additive === true ? node.ctrlClick() : node.click());\n }\n\n /**\n * The labels of the selected nodes, in row order.\n *\n * Only among the rows that are RENDERED: a selected node inside a collapsed branch,\n * or outside a window, is not here. The `[(selected)]` model is the whole set.\n */\n async getSelectedLabels(): Promise<string[]> {\n const nodes = await this.getNodes({ selected: true });\n return Promise.all(nodes.map(node => node.getLabel()));\n }\n\n /**\n * Open every branch, level by level — each pass reveals the next one down.\n *\n * Refuses on a windowed tree instead of half-doing it: only the window is rendered,\n * so the branches outside it cannot be reached from the DOM at all. Write the\n * `[(expanded)]` model there.\n */\n async expandAll(): Promise<void> {\n if (await this.isVirtual()) {\n throw new Error(\n 'WrTreeHarness.expandAll(): a windowed tree renders only its window, so this cannot reach the ' +\n 'branches outside it. Set the `[(expanded)]` model instead.'\n );\n }\n\n for (let pass = 0; pass < MAX_EXPAND_PASSES; pass++) {\n const collapsed = await this.getNodes({ expanded: false });\n if (collapsed.length === 0) return;\n for (const node of collapsed) await node.expand();\n }\n\n throw new Error(\n `WrTreeHarness.expandAll(): still finding closed branches after ${MAX_EXPAND_PASSES} levels — is the ` +\n 'node data recursive?'\n );\n }\n\n /**\n * The label of the node the keyboard cursor is on, or `null`.\n *\n * Read the way the shape publishes it: a windowed tree keeps focus on the list and\n * names the row with `aria-activedescendant` (which goes `null` while the cursor has\n * been scrolled out of the window, so the reference never dangles at a row that was\n * removed), while a plain one hands the single tab stop to the cursor row.\n */\n async getActiveNodeLabel(): Promise<string | null> {\n const nodes = await this.getNodes();\n\n if (await this.isVirtual()) {\n const active = await (await this.list()).getAttribute('aria-activedescendant');\n if (!active) return null;\n for (const node of nodes) {\n if ((await node.getId()) === active) return node.getLabel();\n }\n return null;\n }\n\n for (const node of nodes) {\n if (await node.isActive()) return node.getLabel();\n }\n return null;\n }\n\n /** Move the cursor down one row — ArrowDown. Stops at the last row. */\n async focusNext(): Promise<void> {\n await this.press(TestKey.DOWN_ARROW);\n }\n\n /** Move the cursor up one row — ArrowUp. Stops at the first row. */\n async focusPrevious(): Promise<void> {\n await this.press(TestKey.UP_ARROW);\n }\n\n /** Move the cursor to the first row — Home. */\n async focusFirst(): Promise<void> {\n await this.press(TestKey.HOME);\n }\n\n /**\n * Move the cursor to the last row — End.\n *\n * On a windowed tree this also moves the WINDOW: the tree writes its scroll offset\n * synchronously so the row it is about to point at exists in the same change\n * detection pass. It is the honest way to reach the far end of a window in a unit\n * test — jsdom keeps a `scrollTop` write but never fires the `scroll` event the tree\n * listens for, so a scroll gesture would move the window only for a test that also\n * dispatched the notification itself.\n */\n async focusLast(): Promise<void> {\n await this.press(TestKey.END);\n }\n\n /**\n * ArrowRight on the cursor row — the APG's one key with two jobs: it OPENS a closed\n * branch, and on an already-open one it steps into the first child. A leaf ignores\n * it.\n *\n * These two send the PHYSICAL key, because that is what a keyboard has. Under\n * `dir=\"rtl\"` the tree follows the indent and swaps the pair, so a spec exercising\n * an RTL tree opens with {@link collapseActive} and closes with this one. The\n * names describe the LTR job, which is the one worth naming.\n */\n async expandActive(): Promise<void> {\n await this.press(TestKey.RIGHT_ARROW);\n }\n\n /**\n * ArrowLeft on the cursor row — CLOSES an open branch, and on anything else steps\n * out to the parent row. A root-level leaf ignores it.\n *\n * Physical, and mirrored by the component under `dir=\"rtl\"` — see\n * {@link expandActive}.\n */\n async collapseActive(): Promise<void> {\n await this.press(TestKey.LEFT_ARROW);\n }\n\n /**\n * Select the cursor row from the keyboard — Enter.\n *\n * `additive` holds Ctrl, the keyboard twin of {@link WrTreeNodeHarness.ctrlClick}:\n * in multi mode a plain Enter replaces the selection, Ctrl-Enter adds to it. A\n * disabled row is skipped by the component, silently — assert the model.\n */\n async selectActive(options: { additive?: boolean } = {}): Promise<void> {\n const list = await this.list();\n if (options.additive === true) {\n await list.sendKeys({ control: true }, TestKey.ENTER);\n return;\n }\n await list.sendKeys(TestKey.ENTER);\n }\n\n /**\n * The loader every node query runs through — the host inline, THIS tree's overlay\n * panel otherwise.\n *\n * Scoped by the published panel id rather than by `.wr-tree-panel`: the overlay\n * container is shared, so a bare class query would answer with whichever tree\n * happened to open first.\n */\n protected override async getRootHarnessLoader(): Promise<HarnessLoader> {\n if (!(await this.isOverlay())) return super.getRootHarnessLoader();\n return this.documentRootLocatorFactory().harnessLoaderFor(`#${await this.panelId()}`);\n }\n\n /**\n * Send a key to the `role=\"tree\"` list.\n *\n * The list owns the keydown handler in both patterns — the roving-tabindex one\n * focuses a row, whose event bubbles to exactly here — so this is the honest target\n * either way, and the one that works when jsdom has left real focus on `<body>`.\n */\n private async press(key: TestKey): Promise<void> {\n await (await this.list()).sendKeys(key);\n }\n\n /**\n * The `<ul role=\"tree\">` of THIS tree — in the host inline, in this tree's own\n * overlay panel otherwise.\n */\n private async list(): Promise<TestElement> {\n if (!(await this.isOverlay())) return this.locatorFor('.wr-tree__list')();\n return this.documentRootLocatorFactory().locatorFor(`#${await this.panelId()} .wr-tree__list`)();\n }\n\n /** The combobox trigger, or a failure that says this tree renders inline. */\n private async trigger(): Promise<TestElement> {\n const trigger = await this.locatorForOptional('.wr-tree__trigger')();\n if (!trigger) {\n throw new Error(\n 'WrTreeHarness: this tree renders inline, so it has no trigger, no chips and no panel — its rows ' +\n 'are part of the host. `openOn=\"overlay\"` is the combobox shape.'\n );\n }\n return trigger;\n }\n\n /** The id the trigger publishes as `aria-controls`, which its panel carries. */\n private async panelId(): Promise<string> {\n const id = await (await this.trigger()).getAttribute('aria-controls');\n if (!id) {\n throw new Error(\n 'WrTreeHarness: the trigger publishes no `aria-controls` id, so its panel cannot be told apart ' +\n \"from another tree's.\"\n );\n }\n if (!(await this.isOpen())) {\n throw new Error('WrTreeHarness: the panel is closed — call open() first. A closed tree renders no rows.');\n }\n return id;\n }\n\n /** The trigger's text for the `text` filter, or `null` for an inline tree (which never matches). */\n private async triggerTextIfAny(): Promise<string | null> {\n const trigger = await this.locatorForOptional('.wr-tree__trigger')();\n return trigger ? this.getValueText() : null;\n }\n\n /** The rendered labels for the `nodeLabel` filter — a closed tree matches nothing rather than failing. */\n private async nodeLabelsIfShowing(): Promise<string[]> {\n if (!(await this.isOpen())) return [];\n return this.getNodeLabels();\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ngwr-tree-testing.mjs","sources":["../../../projects/lib/tree/testing/wr-tree-node-harness.ts","../../../projects/lib/tree/testing/wr-tree-harness.ts","../../../projects/lib/tree/testing/ngwr-tree-testing.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { ComponentHarness, HarnessPredicate, type TestElement } from '@angular/cdk/testing';\n\nimport type { WrTreeNodeHarnessFilters } from './interfaces';\n\n/**\n * Test harness for one node of a `<wr-tree>` — a `role=\"treeitem\"` row.\n *\n * Everything about a tree's shape that a screen reader gets lives on these rows:\n * the list itself is FLAT, with no `role=\"group\"` and no nesting, so `aria-level`,\n * `aria-posinset` and `aria-setsize` are the only place the hierarchy exists. The\n * indent is decoration.\n *\n * @example\n * ```ts\n * const src = await tree.getNode({ label: 'src' });\n *\n * await src.expand();\n * expect(await src.getLevel()).toBe(1);\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrTreeNodeHarness extends ComponentHarness {\n /**\n * The row, and nothing else the list can hold.\n *\n * A windowed tree pads its list with `<li class=\"wr-tree__spacer\" role=\"presentation\">`\n * at each end, so `li` would hand back up to two \"nodes\" with no label and no\n * state. `[role=\"treeitem\"]` selects exactly the same set as this class.\n */\n static hostSelector = '.wr-tree__row';\n\n /** Build a predicate that narrows the query. */\n static with(options: WrTreeNodeHarnessFilters = {}): HarnessPredicate<WrTreeNodeHarness> {\n return new HarnessPredicate(WrTreeNodeHarness, options)\n .addOption('label', options.label, (harness, label) => HarnessPredicate.stringMatches(harness.getLabel(), label))\n .addOption('selected', options.selected, async (harness, selected) => (await harness.isSelected()) === selected)\n .addOption('disabled', options.disabled, async (harness, disabled) => (await harness.isDisabled()) === disabled)\n .addOption(\n 'expanded',\n options.expanded,\n // A leaf is not a closed branch: it announces no `aria-expanded` at all, so\n // it matches neither value rather than answering `false` and turning\n // `{ expanded: false }` into \"every row that is not open\".\n async (harness, expanded) => (await harness.isExpandable()) && (await harness.isExpanded()) === expanded\n )\n .addOption('level', options.level, async (harness, level) => (await harness.getLevel()) === level);\n }\n\n /**\n * The node's label.\n *\n * Read from `.wr-tree__label` rather than from the row's text, so the answer stays\n * the label alone however the row is decorated around it.\n */\n async getLabel(): Promise<string> {\n return (await this.locatorFor('.wr-tree__label')()).text();\n }\n\n /** The node's 1-based depth, as the row announces it (`aria-level`). */\n async getLevel(): Promise<number> {\n return this.announcedNumber('aria-level');\n }\n\n /**\n * The node's 1-based position within its SIBLING GROUP (`aria-posinset`) — not its\n * position in the flat list of visible rows.\n *\n * `src`'s first child is `posinset` 1 even though it is the second row on screen.\n * That is what ARIA asks for, and the whole reason the attribute is needed here:\n * the rendered list cannot express the nesting on its own.\n */\n async getPosInSet(): Promise<number> {\n return this.announcedNumber('aria-posinset');\n }\n\n /** How many nodes are in this node's sibling group, itself included (`aria-setsize`). */\n async getSetSize(): Promise<number> {\n return this.announcedNumber('aria-setsize');\n }\n\n /**\n * The node's index in the full list of VISIBLE nodes — every rendered row plus the\n * ones a window left out, in the order the tree would show them.\n *\n * It is the index the tree's own keyboard code addresses rows by, and while the\n * tree is windowed it is the only way to place a row: DOM order then says nothing,\n * because the rows in the DOM are a slice.\n */\n async getIndex(): Promise<number> {\n return this.announcedNumber('data-tree-index');\n }\n\n /**\n * The row's DOM id, or `null`.\n *\n * Only a windowed tree gives its rows ids, because that is the shape where the\n * list keeps focus and names the cursor row with `aria-activedescendant` — the id\n * exists to be pointed at.\n */\n async getId(): Promise<string | null> {\n return (await this.host()).getAttribute('id');\n }\n\n /**\n * Whether the node is a branch — it has children, whether or not they are showing.\n *\n * From `aria-expanded`: only a branch carries it, and a branch that does not is\n * announced as a leaf, so the user never learns there is anything underneath. The\n * toggle element cannot answer this — a leaf renders a `<span>` with the same\n * `.wr-tree__toggle` class purely to hold the indent.\n */\n async isExpandable(): Promise<boolean> {\n return (await (await this.host()).getAttribute('aria-expanded')) !== null;\n }\n\n /** Whether the branch is open. A leaf is never expanded. */\n async isExpanded(): Promise<boolean> {\n return (await (await this.host()).getAttribute('aria-expanded')) === 'true';\n }\n\n /** Open the branch. Already-open branches are left alone; a leaf throws. */\n async expand(): Promise<void> {\n if (await this.isExpanded()) return;\n await this.toggleExpand();\n\n if (!(await this.isExpanded())) {\n throw new Error(\n `WrTreeNodeHarness.expand(): \"${await this.getLabel()}\" did not open. A disabled node ignores its ` +\n 'own toggle, and so does every node of a disabled tree.'\n );\n }\n }\n\n /** Close the branch. Already-closed branches are left alone; a leaf throws. */\n async collapse(): Promise<void> {\n if (!(await this.isExpanded())) {\n // A closed branch is fine to ask twice; a leaf is a mistake worth naming.\n await this.toggleElement();\n return;\n }\n await this.toggleExpand();\n\n if (await this.isExpanded()) {\n throw new Error(\n `WrTreeNodeHarness.collapse(): \"${await this.getLabel()}\" did not close. A disabled node ignores ` +\n 'its own toggle, and so does every node of a disabled tree.'\n );\n }\n }\n\n /**\n * Click the branch's expand toggle.\n *\n * Expanding is the TOGGLE's job and not the row's: a click anywhere else in the row\n * selects instead, which is the one thing a spec driving this by hand tends to get\n * wrong.\n */\n async toggleExpand(): Promise<void> {\n await (await this.toggleElement()).click();\n }\n\n /**\n * Whether the node is selected.\n *\n * From `aria-selected` rather than the `--selected` modifier: both are public, but\n * the attribute is what a screen reader acts on, and a row that looks selected\n * without saying so is the bug worth catching.\n */\n async isSelected(): Promise<boolean> {\n return (await (await this.host()).getAttribute('aria-selected')) === 'true';\n }\n\n /**\n * Whether the tree offers selection at all.\n *\n * A `selectionMode=\"none\"` tree announces NO `aria-selected` on its rows, which is\n * how an unselectable node differs from one that is merely unselected — the two\n * look identical otherwise.\n */\n async isSelectable(): Promise<boolean> {\n return (await (await this.host()).getAttribute('aria-selected')) !== null;\n }\n\n /**\n * Whether the node refuses interaction (`aria-disabled`).\n *\n * True for EVERY node while the whole tree is disabled, not just for the ones the\n * data marks — the row announces the effective state, which is the one a user runs\n * into.\n */\n async isDisabled(): Promise<boolean> {\n return (await (await this.host()).getAttribute('aria-disabled')) === 'true';\n }\n\n /**\n * Whether the node is where the keyboard cursor sits.\n *\n * The two patterns publish the cursor differently, and this covers both: a tree\n * that renders every row hands the single tab stop to the cursor row (roving\n * tabindex), while a windowed one keeps focus on the list and marks the row with\n * the `--active` modifier plus the list's `aria-activedescendant`.\n * `WrTreeHarness.getActiveNodeLabel()` reads that reference itself.\n */\n async isActive(): Promise<boolean> {\n const host = await this.host();\n return (await host.getAttribute('tabindex')) === '0' || host.hasClass('wr-tree__row--active');\n }\n\n /**\n * Whether the row holds real DOM focus.\n *\n * Deliberately separate from {@link isActive}: in a windowed tree the two DIVERGE\n * by design — focus stays on the `role=\"tree\"` list and only the announced cursor\n * moves — so a spec asserting that a key press moved focus needs to know which of\n * the two it is asking about.\n */\n async isFocused(): Promise<boolean> {\n return (await this.host()).isFocused();\n }\n\n /**\n * Click the node — which SELECTS it. A disabled node, and any node of a\n * `selectionMode=\"none\"` tree, ignores the click.\n *\n * In multi mode a plain click REPLACES the selection rather than adding to it (the\n * component's deliberate choice: one selected node clicked again clears it, and any\n * other click starts over from that node). {@link ctrlClick} is how a selection is\n * accumulated.\n */\n async click(): Promise<void> {\n return (await this.host()).click();\n }\n\n /**\n * Ctrl-click the node — ADDS it to the selection, or removes it, in multi mode.\n *\n * The component takes Cmd as well as Ctrl; the harness sends Ctrl because a unit\n * test has no platform. In single mode it behaves exactly like {@link click}.\n */\n async ctrlClick(): Promise<void> {\n return (await this.host()).click({ control: true });\n }\n\n /** The branch's toggle button, or a failure that says this row is a leaf. */\n private async toggleElement(): Promise<TestElement> {\n // `button` is load-bearing: a leaf renders a `<span>` with the same\n // `.wr-tree__toggle` class to hold the indent, and taking that for a control\n // would report every leaf as a branch that refused to open.\n const toggle = await this.locatorForOptional('button.wr-tree__toggle')();\n if (!toggle) {\n throw new Error(`WrTreeNodeHarness: \"${await this.getLabel()}\" is a leaf — there is no branch to open or close.`);\n }\n return toggle;\n }\n\n /** A numeric attribute every row carries, or a failure that says the row is broken. */\n private async announcedNumber(attribute: string): Promise<number> {\n const value = await (await this.host()).getAttribute(attribute);\n if (value === null) {\n throw new Error(\n `WrTreeNodeHarness: this row announces no \\`${attribute}\\`. Every row of a \\`<wr-tree>\\` carries ` +\n 'one, so a missing value is a rendering fault rather than a state worth reporting as null.'\n );\n }\n return Number.parseInt(value, 10);\n }\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport {\n ContentContainerComponentHarness,\n type HarnessLoader,\n HarnessPredicate,\n TestKey,\n type TestElement,\n} from '@angular/cdk/testing';\n\nimport type { WrTreeHarnessFilters, WrTreeNodeHarnessFilters } from './interfaces';\nimport { WrTreeNodeHarness } from './wr-tree-node-harness';\n\n/** How many levels {@link WrTreeHarness.expandAll} is willing to walk. */\nconst MAX_EXPAND_PASSES = 20;\n\n/**\n * Test harness for `<wr-tree>`, with {@link WrTreeNodeHarness} for one row.\n *\n * The component has two render shapes and this harness covers both:\n * - `openOn=\"inline\"` (default) — the rows live in the host, and the tree is always\n * showing them.\n * - `openOn=\"overlay\"` — a `role=\"combobox\"` trigger opens a panel that is a template\n * portal in the shared overlay container, a sibling of the whole app. Nothing in it\n * is a descendant of the host, so every row is read through the document root,\n * SCOPED by the `aria-controls` id the trigger publishes — which is what keeps two\n * trees on one page from answering with each other's nodes.\n *\n * A tree is data-driven and projects nothing, so the scoped loader exists to point the\n * node queries at the right shape rather than to reach a consumer's own components: the\n * inherited `getHarness(…)` resolves wherever THIS tree's rows are, and there is nothing\n * else in there.\n *\n * Two things the harness cannot do, both jsdom rather than the component:\n * - it never clicks a row by coordinate, and it drives the cursor with the KEYBOARD,\n * which is the accessible path anyway. There is no layout in a unit test, so a\n * hit test would answer with nothing.\n * - it offers no SCROLL for a windowed tree. jsdom does remember a `scrollTop` write,\n * but it fires no `scroll` event for it, so the tree — which learns its offset from\n * that event — would not move until the caller also dispatched one and waited a\n * frame: a scroll gesture that only works because the test faked the notification.\n * The keyboard moves the window honestly instead — see {@link focusLast}. (jsdom has\n * no `Element.scrollTo` at all, which the tree calls while windowed, so a spec for\n * that shape has to stub it.)\n *\n * @example\n * ```ts\n * const tree = await loader.getHarness(WrTreeHarness);\n *\n * await (await tree.getNode({ label: 'src' })).expand();\n * await tree.selectNode({ label: 'main.ts' });\n *\n * expect(await tree.getSelectedLabels()).toEqual(['main.ts']);\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrTreeHarness extends ContentContainerComponentHarness {\n static hostSelector = 'wr-tree';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrTreeHarnessFilters = {}): HarnessPredicate<WrTreeHarness> {\n return new HarnessPredicate(WrTreeHarness, options)\n .addOption('text', options.text, (harness, text) =>\n HarnessPredicate.stringMatches(harness.triggerTextIfAny(), text)\n )\n .addOption('nodeLabel', options.nodeLabel, async (harness, label) => {\n for (const shown of await harness.nodeLabelsIfShowing()) {\n if (await HarnessPredicate.stringMatches(shown, label)) return true;\n }\n return false;\n })\n .addOption('disabled', options.disabled, async (harness, disabled) => (await harness.isDisabled()) === disabled)\n .addOption('open', options.open, async (harness, open) => (await harness.isOpen()) === open);\n }\n\n /** Whether this tree is the combobox shape (`openOn=\"overlay\"`) rather than inline. */\n async isOverlay(): Promise<boolean> {\n return (await this.host()).hasClass('wr-tree--combobox');\n }\n\n /**\n * Whether the rows are showing.\n *\n * From the trigger's `aria-expanded` rather than the `--open` modifier: both are\n * public, but that attribute is the promise the combobox makes to a screen reader.\n * An inline tree is always open — its rows are part of the host and there is\n * nothing to open or close.\n */\n async isOpen(): Promise<boolean> {\n if (!(await this.isOverlay())) return true;\n return (await (await this.trigger()).getAttribute('aria-expanded')) === 'true';\n }\n\n /**\n * Open the panel. An already-open tree — and every inline one — is left alone.\n *\n * Note for a spec with two overlay trees: this clicks, and a click is an outside\n * pointer event for every other open overlay, so it closes any panel already up.\n * There is no second gesture to swap in: the trigger is opened by its `click`\n * handler, and while a real keyboard user reaches that through a `<button>`'s native\n * activation, a SYNTHETIC Enter / Space never produces a click — so a harness cannot\n * open a panel any other way.\n */\n async open(): Promise<void> {\n if (await this.isOpen()) return;\n\n await (await this.trigger()).click();\n if (await this.isOpen()) return;\n\n throw new Error(\n 'WrTreeHarness.open(): the panel did not open. A disabled tree refuses the trigger and closes any ' +\n 'panel that was up, so check `disabled` first.'\n );\n }\n\n /** Close the panel with Escape. An already-closed tree is left alone. */\n async close(): Promise<void> {\n // Not a no-op for an inline tree: asking to close one means the spec believes it\n // has a panel, and it does not.\n const trigger = await this.trigger();\n if (!(await this.isOpen())) return;\n\n // Escape reaches the tree through the CDK's keyboard dispatcher, which hands it to\n // the top-most overlay — so it does not matter that focus may be on a row inside.\n await trigger.sendKeys(TestKey.ESCAPE);\n }\n\n /**\n * Whether the tree refuses interaction.\n *\n * The host modifier is the only answer both shapes carry: an inline tree has no\n * control of its own to mark `disabled`, and a closed overlay tree has no rows to\n * read `aria-disabled` from. The rows do announce it — see\n * {@link WrTreeNodeHarness.isDisabled}.\n */\n async isDisabled(): Promise<boolean> {\n return (await this.host()).hasClass('wr-tree--disabled');\n }\n\n /**\n * Whether the tree takes more than one selected node.\n *\n * From the list's `aria-multiselectable`, which is what a screen reader acts on. The\n * list does not exist while an overlay panel is closed, so the host modifier answers\n * then — it is only painted in the combobox shape, which is exactly the shape that\n * can be asked while closed.\n */\n async isMultiple(): Promise<boolean> {\n if (await this.isOpen()) {\n return (await (await this.list()).getAttribute('aria-multiselectable')) === 'true';\n }\n return (await this.host()).hasClass('wr-tree--multi');\n }\n\n /**\n * How much the tree lets you select.\n *\n * `'none'` is not \"nothing selected\": it is a tree whose rows announce no\n * `aria-selected` at all, and telling that from `'single'` needs a row — so an empty\n * tree throws rather than guessing.\n */\n async getSelectionMode(): Promise<'none' | 'single' | 'multi'> {\n if (await this.isMultiple()) return 'multi';\n\n const [first] = await this.getNodes();\n if (!first) {\n throw new Error(\n 'WrTreeHarness.getSelectionMode(): this tree renders no nodes, and single vs none is only visible ' +\n 'on a row — `selectionMode=\"none\"` is the absence of `aria-selected`, so there is nothing to read.'\n );\n }\n return (await first.isSelectable()) ? 'single' : 'none';\n }\n\n /**\n * Whether the list is WINDOWED right now.\n *\n * Read from the list's modifier rather than from the input, and that is the point:\n * `virtualScroll` only takes effect when there is something to window, so an empty\n * tree renders the plain shape however the input is set.\n */\n async isVirtual(): Promise<boolean> {\n return (await this.list()).hasClass('wr-tree__list--virtual');\n }\n\n /**\n * The role the list announces — `tree`.\n *\n * Worth asking: rendered without it, the rows are a bag of names, identical on\n * screen and structureless to anyone not looking at it.\n */\n async getRole(): Promise<string | null> {\n return (await this.list()).getAttribute('role');\n }\n\n /**\n * What the trigger shows as the selection: the chip labels joined by `', '` in multi\n * mode, the label in single mode, and `''` when nothing is selected (the placeholder\n * is showing). The `+N more` chip a `maxTagCount` produces is NOT part of it — it is\n * a count rather than a selection, and {@link getOverflowText} reads it. Inline trees\n * have no trigger and throw.\n */\n async getValueText(): Promise<string> {\n await this.trigger();\n\n const chips = await this.getChipLabels();\n if (chips.length > 0) return chips.join(', ');\n\n const value = await this.locatorForOptional('.wr-tree__value')();\n return value ? value.text() : '';\n }\n\n /** The placeholder, or `null` when a selection is hiding it. */\n async getPlaceholder(): Promise<string | null> {\n await this.trigger();\n\n const placeholder = await this.locatorForOptional('.wr-tree__placeholder')();\n return placeholder ? placeholder.text() : null;\n }\n\n /**\n * The chip labels on the trigger, in order (multi mode).\n *\n * The `+N more` overflow chip is not one of them — it is a count, not a selection.\n * {@link getOverflowText} reads it.\n */\n async getChipLabels(): Promise<string[]> {\n await this.trigger();\n\n const labels = await this.locatorForAll('.wr-tree__chip-label')();\n return Promise.all(labels.map(label => label.text()));\n }\n\n /**\n * The `+N more` chip's text, or `null` when every selected node has a chip of its\n * own. Only a `maxTagCount` below the number selected produces one.\n */\n async getOverflowText(): Promise<string | null> {\n await this.trigger();\n\n const more = await this.locatorForOptional('.wr-tree__chip--more')();\n return more ? more.text() : null;\n }\n\n /** Remove one chip by its label. */\n async removeChip(label: string): Promise<void> {\n const labels = await this.getChipLabels();\n const index = labels.indexOf(label);\n if (index < 0) {\n throw new Error(\n `WrTreeHarness.removeChip(): no chip labelled \"${label}\". The trigger shows [${labels.join(', ')}] — ` +\n 'a selection past `maxTagCount` has no chip to remove.'\n );\n }\n\n // Label and remove control are emitted once per chip by the same loop, so the two\n // lists line up by index.\n const removes = await this.locatorForAll('.wr-tree__chip-remove')();\n await removes[index].click();\n }\n\n /** Click the clear (×) control on the trigger. */\n async clear(): Promise<void> {\n await this.trigger();\n\n const clear = await this.locatorForOptional('.wr-tree__clear')();\n if (!clear) {\n throw new Error(\n 'WrTreeHarness.clear(): this trigger has no clear control — `clearable` is off, nothing is ' +\n 'selected, or the tree is disabled.'\n );\n }\n await clear.click();\n }\n\n /**\n * Backspace on the closed overlay trigger — the keyboard route to the ×.\n *\n * In single mode it clears (only while `clearable` is on); in multi mode it\n * drops the LAST chip, one per call, whatever `clearable` says. Both ×\n * controls are `tabindex=\"-1\"` spans inside the trigger, so a key can never\n * reach them directly. In single mode this is the ONLY keyboard route back to\n * no selection; in multi mode a keyboard user can also toggle a row off in the\n * panel ({@link selectNode} with `additive`). {@link clear} / {@link removeChip}\n * prove the pointer path and nothing more.\n *\n * The key is honoured only on the CLOSED trigger, so an open panel is closed\n * first with Escape — the step a keyboard user takes too, since focus sits in\n * the panel while it is up.\n *\n * Does nothing, rather than throwing, where the component does nothing —\n * nothing selected, disabled or read-only — so a spec asserts the outcome on\n * the value.\n */\n async clearByKeyboard(): Promise<void> {\n if (await this.isOpen()) await this.close();\n await (await this.trigger()).sendKeys(TestKey.BACKSPACE);\n }\n\n /**\n * The nodes currently rendered, in the order they are shown.\n *\n * A collapsed branch's children are not rendered at all, so this is the VISIBLE\n * tree — expand first to reach deeper.\n *\n * While {@link isVirtual} is true it is narrower still: the list holds only the\n * window around the scroll offset — padded by a spacer at whichever end has rows\n * outside it, so a window resting at the top has one and a window in the middle has\n * two — and this returns the WINDOW, not the dataset. Nothing in the DOM carries a\n * total —\n * `aria-setsize` counts a SIBLING GROUP, not the flat list — so the harness cannot\n * offer one; {@link WrTreeNodeHarness.getIndex} places each row in the full visible\n * list, and the `[nodes]` data is where the total actually lives.\n *\n * Throws while an overlay panel is closed: the rows do not exist anywhere until it\n * opens, and an empty array reads like a tree that rendered nothing.\n */\n async getNodes(filters: WrTreeNodeHarnessFilters = {}): Promise<WrTreeNodeHarness[]> {\n return this.getAllHarnesses(WrTreeNodeHarness.with(filters));\n }\n\n /** The labels of the nodes currently rendered, in order. */\n async getNodeLabels(): Promise<string[]> {\n const nodes = await this.getNodes();\n return Promise.all(nodes.map(node => node.getLabel()));\n }\n\n /** The first node matching the filters, or a failure that says what is showing. */\n async getNode(filters: WrTreeNodeHarnessFilters): Promise<WrTreeNodeHarness> {\n const [node] = await this.getNodes(filters);\n if (!node) {\n const showing = await this.getNodeLabels();\n throw new Error(\n `WrTreeHarness.getNode(): no node matched ${JSON.stringify(filters)}. The tree is showing ` +\n `[${showing.join(', ')}] — a node inside a collapsed branch is not rendered at all, and a ` +\n 'windowed tree only renders its window.'\n );\n }\n return node;\n }\n\n /**\n * Open the panel if needed, then select the first node matching the filters.\n *\n * `additive` ctrl-clicks instead, which is how a multi-mode selection is built up: a\n * plain click there REPLACES the selection, by the component's own choice.\n *\n * Throws rather than clicking into the void on a disabled node or a\n * `selectionMode=\"none\"` tree — both ignore the click, and the silence turns into a\n * confusing failure at the next assertion. Reach for `getNode().click()` when\n * proving exactly that.\n */\n async selectNode(filters: WrTreeNodeHarnessFilters, options: { additive?: boolean } = {}): Promise<void> {\n await this.open();\n\n const node = await this.getNode(filters);\n const label = await node.getLabel();\n\n if (!(await node.isSelectable())) {\n throw new Error(\n `WrTreeHarness.selectNode(): \"${label}\" announces no selected state, so this tree is in ` +\n 'selectionMode=\"none\" — clicking it cannot select anything.'\n );\n }\n if (await node.isDisabled()) {\n throw new Error(\n `WrTreeHarness.selectNode(): \"${label}\" is disabled and the tree ignores the click. A disabled ` +\n 'TREE disables every node — check isDisabled() on the tree too.'\n );\n }\n\n await (options.additive === true ? node.ctrlClick() : node.click());\n }\n\n /**\n * The labels of the selected nodes, in row order.\n *\n * Only among the rows that are RENDERED: a selected node inside a collapsed branch,\n * or outside a window, is not here. The `[(selected)]` model is the whole set.\n */\n async getSelectedLabels(): Promise<string[]> {\n const nodes = await this.getNodes({ selected: true });\n return Promise.all(nodes.map(node => node.getLabel()));\n }\n\n /**\n * Open every branch, level by level — each pass reveals the next one down.\n *\n * Refuses on a windowed tree instead of half-doing it: only the window is rendered,\n * so the branches outside it cannot be reached from the DOM at all. Write the\n * `[(expanded)]` model there.\n */\n async expandAll(): Promise<void> {\n if (await this.isVirtual()) {\n throw new Error(\n 'WrTreeHarness.expandAll(): a windowed tree renders only its window, so this cannot reach the ' +\n 'branches outside it. Set the `[(expanded)]` model instead.'\n );\n }\n\n for (let pass = 0; pass < MAX_EXPAND_PASSES; pass++) {\n const collapsed = await this.getNodes({ expanded: false });\n if (collapsed.length === 0) return;\n for (const node of collapsed) await node.expand();\n }\n\n throw new Error(\n `WrTreeHarness.expandAll(): still finding closed branches after ${MAX_EXPAND_PASSES} levels — is the ` +\n 'node data recursive?'\n );\n }\n\n /**\n * The label of the node the keyboard cursor is on, or `null`.\n *\n * Read the way the shape publishes it: a windowed tree keeps focus on the list and\n * names the row with `aria-activedescendant` (which goes `null` while the cursor has\n * been scrolled out of the window, so the reference never dangles at a row that was\n * removed), while a plain one hands the single tab stop to the cursor row.\n */\n async getActiveNodeLabel(): Promise<string | null> {\n const nodes = await this.getNodes();\n\n if (await this.isVirtual()) {\n const active = await (await this.list()).getAttribute('aria-activedescendant');\n if (!active) return null;\n for (const node of nodes) {\n if ((await node.getId()) === active) return node.getLabel();\n }\n return null;\n }\n\n for (const node of nodes) {\n if (await node.isActive()) return node.getLabel();\n }\n return null;\n }\n\n /** Move the cursor down one row — ArrowDown. Stops at the last row. */\n async focusNext(): Promise<void> {\n await this.press(TestKey.DOWN_ARROW);\n }\n\n /** Move the cursor up one row — ArrowUp. Stops at the first row. */\n async focusPrevious(): Promise<void> {\n await this.press(TestKey.UP_ARROW);\n }\n\n /** Move the cursor to the first row — Home. */\n async focusFirst(): Promise<void> {\n await this.press(TestKey.HOME);\n }\n\n /**\n * Move the cursor to the last row — End.\n *\n * On a windowed tree this also moves the WINDOW: the tree writes its scroll offset\n * synchronously so the row it is about to point at exists in the same change\n * detection pass. It is the honest way to reach the far end of a window in a unit\n * test — jsdom keeps a `scrollTop` write but never fires the `scroll` event the tree\n * listens for, so a scroll gesture would move the window only for a test that also\n * dispatched the notification itself.\n */\n async focusLast(): Promise<void> {\n await this.press(TestKey.END);\n }\n\n /**\n * ArrowRight on the cursor row — the APG's one key with two jobs: it OPENS a closed\n * branch, and on an already-open one it steps into the first child. A leaf ignores\n * it.\n *\n * These two send the PHYSICAL key, because that is what a keyboard has. Under\n * `dir=\"rtl\"` the tree follows the indent and swaps the pair, so a spec exercising\n * an RTL tree opens with {@link collapseActive} and closes with this one. The\n * names describe the LTR job, which is the one worth naming.\n */\n async expandActive(): Promise<void> {\n await this.press(TestKey.RIGHT_ARROW);\n }\n\n /**\n * ArrowLeft on the cursor row — CLOSES an open branch, and on anything else steps\n * out to the parent row. A root-level leaf ignores it.\n *\n * Physical, and mirrored by the component under `dir=\"rtl\"` — see\n * {@link expandActive}.\n */\n async collapseActive(): Promise<void> {\n await this.press(TestKey.LEFT_ARROW);\n }\n\n /**\n * Select the cursor row from the keyboard — Enter.\n *\n * `additive` holds Ctrl, the keyboard twin of {@link WrTreeNodeHarness.ctrlClick}:\n * in multi mode a plain Enter replaces the selection, Ctrl-Enter adds to it. A\n * disabled row is skipped by the component, silently — assert the model.\n */\n async selectActive(options: { additive?: boolean } = {}): Promise<void> {\n const list = await this.list();\n if (options.additive === true) {\n await list.sendKeys({ control: true }, TestKey.ENTER);\n return;\n }\n await list.sendKeys(TestKey.ENTER);\n }\n\n /**\n * The loader every node query runs through — the host inline, THIS tree's overlay\n * panel otherwise.\n *\n * Scoped by the published panel id rather than by `.wr-tree-panel`: the overlay\n * container is shared, so a bare class query would answer with whichever tree\n * happened to open first.\n */\n protected override async getRootHarnessLoader(): Promise<HarnessLoader> {\n if (!(await this.isOverlay())) return super.getRootHarnessLoader();\n return this.documentRootLocatorFactory().harnessLoaderFor(`#${await this.panelId()}`);\n }\n\n /**\n * Send a key to the `role=\"tree\"` list.\n *\n * The list owns the keydown handler in both patterns — the roving-tabindex one\n * focuses a row, whose event bubbles to exactly here — so this is the honest target\n * either way, and the one that works when jsdom has left real focus on `<body>`.\n */\n private async press(key: TestKey): Promise<void> {\n await (await this.list()).sendKeys(key);\n }\n\n /**\n * The `<ul role=\"tree\">` of THIS tree — in the host inline, in this tree's own\n * overlay panel otherwise.\n */\n private async list(): Promise<TestElement> {\n if (!(await this.isOverlay())) return this.locatorFor('.wr-tree__list')();\n return this.documentRootLocatorFactory().locatorFor(`#${await this.panelId()} .wr-tree__list`)();\n }\n\n /** The combobox trigger, or a failure that says this tree renders inline. */\n private async trigger(): Promise<TestElement> {\n const trigger = await this.locatorForOptional('.wr-tree__trigger')();\n if (!trigger) {\n throw new Error(\n 'WrTreeHarness: this tree renders inline, so it has no trigger, no chips and no panel — its rows ' +\n 'are part of the host. `openOn=\"overlay\"` is the combobox shape.'\n );\n }\n return trigger;\n }\n\n /** The id the trigger publishes as `aria-controls`, which its panel carries. */\n private async panelId(): Promise<string> {\n const id = await (await this.trigger()).getAttribute('aria-controls');\n if (!id) {\n throw new Error(\n 'WrTreeHarness: the trigger publishes no `aria-controls` id, so its panel cannot be told apart ' +\n \"from another tree's.\"\n );\n }\n if (!(await this.isOpen())) {\n throw new Error('WrTreeHarness: the panel is closed — call open() first. A closed tree renders no rows.');\n }\n return id;\n }\n\n /** The trigger's text for the `text` filter, or `null` for an inline tree (which never matches). */\n private async triggerTextIfAny(): Promise<string | null> {\n const trigger = await this.locatorForOptional('.wr-tree__trigger')();\n return trigger ? this.getValueText() : null;\n }\n\n /** The rendered labels for the `nodeLabel` filter — a closed tree matches nothing rather than failing. */\n private async nodeLabelsIfShowing(): Promise<string[]> {\n if (!(await this.isOpen())) return [];\n return this.getNodeLabels();\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -893,10 +893,10 @@ class WrTree {
893
893
  if (inPanel)
894
894
  this.host.nativeElement.querySelector('.wr-tree__trigger')?.focus();
895
895
  }
896
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrTree, deps: [], target: i0.ɵɵFactoryTarget.Component });
897
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: WrTree, isStandalone: true, selector: "wr-tree", inputs: { nodes: { classPropertyName: "nodes", publicName: "nodes", isSignal: true, isRequired: false, transformFunction: null }, selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, expanded: { classPropertyName: "expanded", publicName: "expanded", isSignal: true, isRequired: false, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, openOn: { classPropertyName: "openOn", publicName: "openOn", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, maxTagCount: { classPropertyName: "maxTagCount", publicName: "maxTagCount", isSignal: true, isRequired: false, transformFunction: null }, defaultExpandAll: { classPropertyName: "defaultExpandAll", publicName: "defaultExpandAll", isSignal: true, isRequired: false, transformFunction: null }, virtualScroll: { classPropertyName: "virtualScroll", publicName: "virtualScroll", isSignal: true, isRequired: false, transformFunction: null }, rowHeight: { classPropertyName: "rowHeight", publicName: "rowHeight", isSignal: true, isRequired: false, transformFunction: null }, viewportHeight: { classPropertyName: "viewportHeight", publicName: "viewportHeight", isSignal: true, isRequired: false, transformFunction: null }, overscan: { classPropertyName: "overscan", publicName: "overscan", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selected: "selectedChange", expanded: "expandedChange", value: "valueChange", touch: "touch" }, host: { listeners: { "focusout": "onFocusOut($event)" }, properties: { "class": "classes()" } }, viewQueries: [{ propertyName: "panelTpl", first: true, predicate: ["panelTpl"], descendants: true, read: TemplateRef, isSignal: true }], ngImport: i0, template: "@if (isOverlay()) {\n <button\n type=\"button\"\n class=\"wr-tree__trigger\"\n role=\"combobox\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n [disabled]=\"disabled()\"\n [attr.aria-haspopup]=\"'tree'\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"panelId\"\n [attr.aria-readonly]=\"readonly() || null\"\n [attr.aria-invalid]=\"fieldAria.ariaInvalid()\"\n [attr.aria-describedby]=\"fieldAria.describedBy()\"\n (click)=\"onTriggerClick()\"\n (keydown)=\"onTriggerKey($event)\"\n (blur)=\"onBlur()\"\n >\n @if (isMulti()) {\n @if (hasSelection()) {\n <span class=\"wr-tree__chips\">\n @for (chip of visibleChips(); track chip.id) {\n <span class=\"wr-tree__chip\">\n <span class=\"wr-tree__chip-label\">{{ chip.label }}</span>\n <span\n class=\"wr-tree__chip-remove\"\n role=\"button\"\n [attr.aria-label]=\"chipRemoveLabel({ label: chip.label })\"\n tabindex=\"-1\"\n (click)=\"removeChip(chip.id, $event)\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n </span>\n </span>\n }\n @if (hiddenChipCount(); as extra) {\n <span class=\"wr-tree__chip wr-tree__chip--more\">{{ chipMoreLabel({ count: extra }) }}</span>\n }\n </span>\n } @else {\n <span class=\"wr-tree__placeholder\">{{ resolvedPlaceholder() }}</span>\n }\n } @else {\n @if (singleLabel(); as label) {\n <span class=\"wr-tree__value\">{{ label }}</span>\n } @else {\n <span class=\"wr-tree__placeholder\">{{ resolvedPlaceholder() }}</span>\n }\n }\n\n @if (clearable() && hasSelection() && !disabled() && !readonly()) {\n <span\n class=\"wr-tree__clear\"\n role=\"button\"\n [attr.aria-label]=\"clearLabel()\"\n tabindex=\"-1\"\n (click)=\"clearSelection($event)\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n </span>\n }\n\n <svg\n class=\"wr-icon__svg wr-tree__chevron\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n\n <!-- Tree list lives inside the overlay panel. -->\n <ng-template #panelTpl>\n <div class=\"wr-tree-panel\" [class.wr-tree-panel--virtual]=\"virtualized()\" [attr.id]=\"panelId\">\n <ng-container [ngTemplateOutlet]=\"listTpl\" />\n </div>\n </ng-template>\n} @else {\n <ng-container [ngTemplateOutlet]=\"listTpl\" />\n}\n\n<!-- Shared row list \u2014 rendered inline (default) or projected into the\n overlay panel (when openOn=\"overlay\"). -->\n<ng-template #listTpl>\n <!-- Roving tabindex (non-virtual) / aria-activedescendant (virtual): the tree\n owns keyboard focus and routes arrow keys to its currently-focused row.\n The field's error state is bound here for the INLINE shape only \u2014 in\n overlay mode the trigger carries it, and the panel would otherwise\n describe the same error a second time. -->\n <ul\n class=\"wr-tree__list\"\n role=\"tree\"\n [attr.aria-multiselectable]=\"isMulti() ? 'true' : null\"\n [attr.aria-invalid]=\"isOverlay() ? null : fieldAria.ariaInvalid()\"\n [attr.aria-describedby]=\"isOverlay() ? null : fieldAria.describedBy()\"\n [class.wr-tree__list--virtual]=\"virtualized()\"\n [attr.tabindex]=\"virtualized() ? 0 : null\"\n [attr.aria-activedescendant]=\"activeRowId()\"\n [style.max-height]=\"virtualized() ? resolvedViewportHeight() : null\"\n [style.overflow-y]=\"virtualized() ? 'auto' : null\"\n (keydown)=\"onKeydown($event)\"\n >\n @if (virtualized() && virtualWindow().padTop > 0) {\n <!-- `aria-setsize` / `aria-posinset` in BOTH shapes: the list is flat with no\n `role=\"group\"` either way, so the set a row belongs to is never expressed\n by the DOM. Gated behind the virtual flag, the same tree announced a\n position with windowing on and nothing with it off. -->\n <li\n class=\"wr-tree__spacer\"\n role=\"presentation\"\n aria-hidden=\"true\"\n [style.height.px]=\"virtualWindow().padTop\"\n ></li>\n }\n @for (entry of windowRows(); track entry.node.id) {\n <!-- Click handler lives on focusable rows; keyboard handling is owned\n by the parent <ul> via the roving-tabindex pattern. -->\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events -->\n <li\n class=\"wr-tree__row\"\n role=\"treeitem\"\n [attr.id]=\"virtualized() ? rowId(entry.index) : null\"\n [class.wr-tree__row--selected]=\"selectedSet().has(entry.node.id)\"\n [class.wr-tree__row--active]=\"virtualized() && entry.index === cursorIndex()\"\n [class.wr-tree__row--disabled]=\"entry.node.disabled\"\n [attr.aria-level]=\"entry.depth + 1\"\n [attr.aria-setsize]=\"entry.setsize\"\n [attr.aria-posinset]=\"entry.posinset\"\n [attr.aria-expanded]=\"entry.hasChildren ? expandedSet().has(entry.node.id) : null\"\n [attr.aria-selected]=\"selectionMode() === 'none' ? null : selectedSet().has(entry.node.id)\"\n [attr.aria-disabled]=\"entry.node.disabled || disabled() || null\"\n [attr.data-tree-index]=\"entry.index\"\n [attr.tabindex]=\"virtualized() ? null : entry.index === cursorIndex() ? 0 : -1\"\n [style.--wr-tree-depth]=\"entry.depth\"\n (click)=\"onRowClick(entry, $event)\"\n >\n @if (entry.hasChildren) {\n <button\n type=\"button\"\n class=\"wr-tree__toggle\"\n tabindex=\"-1\"\n [attr.aria-label]=\"expandedSet().has(entry.node.id) ? collapseLabel() : expandLabel()\"\n (click)=\"onToggleClick(entry.node, $event)\"\n >\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <path d=\"M3 1 L7 5 L3 9 Z\" fill=\"currentColor\" />\n </svg>\n </button>\n } @else {\n <span class=\"wr-tree__toggle wr-tree__toggle--leaf\" aria-hidden=\"true\"></span>\n }\n <span class=\"wr-tree__label\">{{ entry.node.label }}</span>\n </li>\n }\n @if (virtualized() && virtualWindow().padBottom > 0) {\n <li\n class=\"wr-tree__spacer\"\n role=\"presentation\"\n aria-hidden=\"true\"\n [style.height.px]=\"virtualWindow().padBottom\"\n ></li>\n }\n </ul>\n</ng-template>\n", dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], encapsulation: i0.ViewEncapsulation.None });
896
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrTree, deps: [], target: i0.ɵɵFactoryTarget.Component });
897
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: WrTree, isStandalone: true, selector: "wr-tree", inputs: { nodes: { classPropertyName: "nodes", publicName: "nodes", isSignal: true, isRequired: false, transformFunction: null }, selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, expanded: { classPropertyName: "expanded", publicName: "expanded", isSignal: true, isRequired: false, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, openOn: { classPropertyName: "openOn", publicName: "openOn", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, maxTagCount: { classPropertyName: "maxTagCount", publicName: "maxTagCount", isSignal: true, isRequired: false, transformFunction: null }, defaultExpandAll: { classPropertyName: "defaultExpandAll", publicName: "defaultExpandAll", isSignal: true, isRequired: false, transformFunction: null }, virtualScroll: { classPropertyName: "virtualScroll", publicName: "virtualScroll", isSignal: true, isRequired: false, transformFunction: null }, rowHeight: { classPropertyName: "rowHeight", publicName: "rowHeight", isSignal: true, isRequired: false, transformFunction: null }, viewportHeight: { classPropertyName: "viewportHeight", publicName: "viewportHeight", isSignal: true, isRequired: false, transformFunction: null }, overscan: { classPropertyName: "overscan", publicName: "overscan", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selected: "selectedChange", expanded: "expandedChange", value: "valueChange", touch: "touch" }, host: { listeners: { "focusout": "onFocusOut($event)" }, properties: { "class": "classes()" } }, viewQueries: [{ propertyName: "panelTpl", first: true, predicate: ["panelTpl"], descendants: true, read: TemplateRef, isSignal: true }], ngImport: i0, template: "@if (isOverlay()) {\n <button\n type=\"button\"\n class=\"wr-tree__trigger\"\n role=\"combobox\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n [disabled]=\"disabled()\"\n [attr.aria-haspopup]=\"'tree'\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"panelId\"\n [attr.aria-readonly]=\"readonly() || null\"\n [attr.aria-invalid]=\"fieldAria.ariaInvalid()\"\n [attr.aria-describedby]=\"fieldAria.describedBy()\"\n (click)=\"onTriggerClick()\"\n (keydown)=\"onTriggerKey($event)\"\n (blur)=\"onBlur()\"\n >\n @if (isMulti()) {\n @if (hasSelection()) {\n <span class=\"wr-tree__chips\">\n @for (chip of visibleChips(); track chip.id) {\n <span class=\"wr-tree__chip\">\n <span class=\"wr-tree__chip-label\">{{ chip.label }}</span>\n <span\n class=\"wr-tree__chip-remove\"\n role=\"button\"\n [attr.aria-label]=\"chipRemoveLabel({ label: chip.label })\"\n tabindex=\"-1\"\n (click)=\"removeChip(chip.id, $event)\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n </span>\n </span>\n }\n @if (hiddenChipCount(); as extra) {\n <span class=\"wr-tree__chip wr-tree__chip--more\">{{ chipMoreLabel({ count: extra }) }}</span>\n }\n </span>\n } @else {\n <span class=\"wr-tree__placeholder\">{{ resolvedPlaceholder() }}</span>\n }\n } @else {\n @if (singleLabel(); as label) {\n <span class=\"wr-tree__value\">{{ label }}</span>\n } @else {\n <span class=\"wr-tree__placeholder\">{{ resolvedPlaceholder() }}</span>\n }\n }\n\n @if (clearable() && hasSelection() && !disabled() && !readonly()) {\n <span\n class=\"wr-tree__clear\"\n role=\"button\"\n [attr.aria-label]=\"clearLabel()\"\n tabindex=\"-1\"\n (click)=\"clearSelection($event)\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n </span>\n }\n\n <svg\n class=\"wr-icon__svg wr-tree__chevron\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n\n <!-- Tree list lives inside the overlay panel. -->\n <ng-template #panelTpl>\n <div class=\"wr-tree-panel\" [class.wr-tree-panel--virtual]=\"virtualized()\" [attr.id]=\"panelId\">\n <ng-container [ngTemplateOutlet]=\"listTpl\" />\n </div>\n </ng-template>\n} @else {\n <ng-container [ngTemplateOutlet]=\"listTpl\" />\n}\n\n<!-- Shared row list \u2014 rendered inline (default) or projected into the\n overlay panel (when openOn=\"overlay\"). -->\n<ng-template #listTpl>\n <!-- Roving tabindex (non-virtual) / aria-activedescendant (virtual): the tree\n owns keyboard focus and routes arrow keys to its currently-focused row.\n The field's error state is bound here for the INLINE shape only \u2014 in\n overlay mode the trigger carries it, and the panel would otherwise\n describe the same error a second time. -->\n <ul\n class=\"wr-tree__list\"\n role=\"tree\"\n [attr.aria-multiselectable]=\"isMulti() ? 'true' : null\"\n [attr.aria-invalid]=\"isOverlay() ? null : fieldAria.ariaInvalid()\"\n [attr.aria-describedby]=\"isOverlay() ? null : fieldAria.describedBy()\"\n [class.wr-tree__list--virtual]=\"virtualized()\"\n [attr.tabindex]=\"virtualized() ? 0 : null\"\n [attr.aria-activedescendant]=\"activeRowId()\"\n [style.max-height]=\"virtualized() ? resolvedViewportHeight() : null\"\n [style.overflow-y]=\"virtualized() ? 'auto' : null\"\n (keydown)=\"onKeydown($event)\"\n >\n @if (virtualized() && virtualWindow().padTop > 0) {\n <!-- `aria-setsize` / `aria-posinset` in BOTH shapes: the list is flat with no\n `role=\"group\"` either way, so the set a row belongs to is never expressed\n by the DOM. Gated behind the virtual flag, the same tree announced a\n position with windowing on and nothing with it off. -->\n <li\n class=\"wr-tree__spacer\"\n role=\"presentation\"\n aria-hidden=\"true\"\n [style.height.px]=\"virtualWindow().padTop\"\n ></li>\n }\n @for (entry of windowRows(); track entry.node.id) {\n <!-- Click handler lives on focusable rows; keyboard handling is owned\n by the parent <ul> via the roving-tabindex pattern. -->\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events -->\n <li\n class=\"wr-tree__row\"\n role=\"treeitem\"\n [attr.id]=\"virtualized() ? rowId(entry.index) : null\"\n [class.wr-tree__row--selected]=\"selectedSet().has(entry.node.id)\"\n [class.wr-tree__row--active]=\"virtualized() && entry.index === cursorIndex()\"\n [class.wr-tree__row--disabled]=\"entry.node.disabled\"\n [attr.aria-level]=\"entry.depth + 1\"\n [attr.aria-setsize]=\"entry.setsize\"\n [attr.aria-posinset]=\"entry.posinset\"\n [attr.aria-expanded]=\"entry.hasChildren ? expandedSet().has(entry.node.id) : null\"\n [attr.aria-selected]=\"selectionMode() === 'none' ? null : selectedSet().has(entry.node.id)\"\n [attr.aria-disabled]=\"entry.node.disabled || disabled() || null\"\n [attr.data-tree-index]=\"entry.index\"\n [attr.tabindex]=\"virtualized() ? null : entry.index === cursorIndex() ? 0 : -1\"\n [style.--wr-tree-depth]=\"entry.depth\"\n (click)=\"onRowClick(entry, $event)\"\n >\n @if (entry.hasChildren) {\n <button\n type=\"button\"\n class=\"wr-tree__toggle\"\n tabindex=\"-1\"\n [attr.aria-label]=\"expandedSet().has(entry.node.id) ? collapseLabel() : expandLabel()\"\n (click)=\"onToggleClick(entry.node, $event)\"\n >\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <path d=\"M3 1 L7 5 L3 9 Z\" fill=\"currentColor\" />\n </svg>\n </button>\n } @else {\n <span class=\"wr-tree__toggle wr-tree__toggle--leaf\" aria-hidden=\"true\"></span>\n }\n <span class=\"wr-tree__label\">{{ entry.node.label }}</span>\n </li>\n }\n @if (virtualized() && virtualWindow().padBottom > 0) {\n <li\n class=\"wr-tree__spacer\"\n role=\"presentation\"\n aria-hidden=\"true\"\n [style.height.px]=\"virtualWindow().padBottom\"\n ></li>\n }\n </ul>\n</ng-template>\n", dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], encapsulation: i0.ViewEncapsulation.None });
898
898
  }
899
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrTree, decorators: [{
899
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrTree, decorators: [{
900
900
  type: Component,
901
901
  args: [{ selector: 'wr-tree', encapsulation: ViewEncapsulation.None, host: { '[class]': 'classes()', '(focusout)': 'onFocusOut($event)' }, imports: [NgTemplateOutlet], template: "@if (isOverlay()) {\n <button\n type=\"button\"\n class=\"wr-tree__trigger\"\n role=\"combobox\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n [disabled]=\"disabled()\"\n [attr.aria-haspopup]=\"'tree'\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"panelId\"\n [attr.aria-readonly]=\"readonly() || null\"\n [attr.aria-invalid]=\"fieldAria.ariaInvalid()\"\n [attr.aria-describedby]=\"fieldAria.describedBy()\"\n (click)=\"onTriggerClick()\"\n (keydown)=\"onTriggerKey($event)\"\n (blur)=\"onBlur()\"\n >\n @if (isMulti()) {\n @if (hasSelection()) {\n <span class=\"wr-tree__chips\">\n @for (chip of visibleChips(); track chip.id) {\n <span class=\"wr-tree__chip\">\n <span class=\"wr-tree__chip-label\">{{ chip.label }}</span>\n <span\n class=\"wr-tree__chip-remove\"\n role=\"button\"\n [attr.aria-label]=\"chipRemoveLabel({ label: chip.label })\"\n tabindex=\"-1\"\n (click)=\"removeChip(chip.id, $event)\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n </span>\n </span>\n }\n @if (hiddenChipCount(); as extra) {\n <span class=\"wr-tree__chip wr-tree__chip--more\">{{ chipMoreLabel({ count: extra }) }}</span>\n }\n </span>\n } @else {\n <span class=\"wr-tree__placeholder\">{{ resolvedPlaceholder() }}</span>\n }\n } @else {\n @if (singleLabel(); as label) {\n <span class=\"wr-tree__value\">{{ label }}</span>\n } @else {\n <span class=\"wr-tree__placeholder\">{{ resolvedPlaceholder() }}</span>\n }\n }\n\n @if (clearable() && hasSelection() && !disabled() && !readonly()) {\n <span\n class=\"wr-tree__clear\"\n role=\"button\"\n [attr.aria-label]=\"clearLabel()\"\n tabindex=\"-1\"\n (click)=\"clearSelection($event)\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n </span>\n }\n\n <svg\n class=\"wr-icon__svg wr-tree__chevron\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n\n <!-- Tree list lives inside the overlay panel. -->\n <ng-template #panelTpl>\n <div class=\"wr-tree-panel\" [class.wr-tree-panel--virtual]=\"virtualized()\" [attr.id]=\"panelId\">\n <ng-container [ngTemplateOutlet]=\"listTpl\" />\n </div>\n </ng-template>\n} @else {\n <ng-container [ngTemplateOutlet]=\"listTpl\" />\n}\n\n<!-- Shared row list \u2014 rendered inline (default) or projected into the\n overlay panel (when openOn=\"overlay\"). -->\n<ng-template #listTpl>\n <!-- Roving tabindex (non-virtual) / aria-activedescendant (virtual): the tree\n owns keyboard focus and routes arrow keys to its currently-focused row.\n The field's error state is bound here for the INLINE shape only \u2014 in\n overlay mode the trigger carries it, and the panel would otherwise\n describe the same error a second time. -->\n <ul\n class=\"wr-tree__list\"\n role=\"tree\"\n [attr.aria-multiselectable]=\"isMulti() ? 'true' : null\"\n [attr.aria-invalid]=\"isOverlay() ? null : fieldAria.ariaInvalid()\"\n [attr.aria-describedby]=\"isOverlay() ? null : fieldAria.describedBy()\"\n [class.wr-tree__list--virtual]=\"virtualized()\"\n [attr.tabindex]=\"virtualized() ? 0 : null\"\n [attr.aria-activedescendant]=\"activeRowId()\"\n [style.max-height]=\"virtualized() ? resolvedViewportHeight() : null\"\n [style.overflow-y]=\"virtualized() ? 'auto' : null\"\n (keydown)=\"onKeydown($event)\"\n >\n @if (virtualized() && virtualWindow().padTop > 0) {\n <!-- `aria-setsize` / `aria-posinset` in BOTH shapes: the list is flat with no\n `role=\"group\"` either way, so the set a row belongs to is never expressed\n by the DOM. Gated behind the virtual flag, the same tree announced a\n position with windowing on and nothing with it off. -->\n <li\n class=\"wr-tree__spacer\"\n role=\"presentation\"\n aria-hidden=\"true\"\n [style.height.px]=\"virtualWindow().padTop\"\n ></li>\n }\n @for (entry of windowRows(); track entry.node.id) {\n <!-- Click handler lives on focusable rows; keyboard handling is owned\n by the parent <ul> via the roving-tabindex pattern. -->\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events -->\n <li\n class=\"wr-tree__row\"\n role=\"treeitem\"\n [attr.id]=\"virtualized() ? rowId(entry.index) : null\"\n [class.wr-tree__row--selected]=\"selectedSet().has(entry.node.id)\"\n [class.wr-tree__row--active]=\"virtualized() && entry.index === cursorIndex()\"\n [class.wr-tree__row--disabled]=\"entry.node.disabled\"\n [attr.aria-level]=\"entry.depth + 1\"\n [attr.aria-setsize]=\"entry.setsize\"\n [attr.aria-posinset]=\"entry.posinset\"\n [attr.aria-expanded]=\"entry.hasChildren ? expandedSet().has(entry.node.id) : null\"\n [attr.aria-selected]=\"selectionMode() === 'none' ? null : selectedSet().has(entry.node.id)\"\n [attr.aria-disabled]=\"entry.node.disabled || disabled() || null\"\n [attr.data-tree-index]=\"entry.index\"\n [attr.tabindex]=\"virtualized() ? null : entry.index === cursorIndex() ? 0 : -1\"\n [style.--wr-tree-depth]=\"entry.depth\"\n (click)=\"onRowClick(entry, $event)\"\n >\n @if (entry.hasChildren) {\n <button\n type=\"button\"\n class=\"wr-tree__toggle\"\n tabindex=\"-1\"\n [attr.aria-label]=\"expandedSet().has(entry.node.id) ? collapseLabel() : expandLabel()\"\n (click)=\"onToggleClick(entry.node, $event)\"\n >\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <path d=\"M3 1 L7 5 L3 9 Z\" fill=\"currentColor\" />\n </svg>\n </button>\n } @else {\n <span class=\"wr-tree__toggle wr-tree__toggle--leaf\" aria-hidden=\"true\"></span>\n }\n <span class=\"wr-tree__label\">{{ entry.node.label }}</span>\n </li>\n }\n @if (virtualized() && virtualWindow().padBottom > 0) {\n <li\n class=\"wr-tree__spacer\"\n role=\"presentation\"\n aria-hidden=\"true\"\n [style.height.px]=\"virtualWindow().padBottom\"\n ></li>\n }\n </ul>\n</ng-template>\n" }]
902
902
  }], ctorParameters: () => [], propDecorators: { nodes: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodes", required: false }] }], selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "selected", required: false }] }, { type: i0.Output, args: ["selectedChange"] }], expanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "expanded", required: false }] }, { type: i0.Output, args: ["expandedChange"] }], selectionMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionMode", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], openOn: [{ type: i0.Input, args: [{ isSignal: true, alias: "openOn", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], maxTagCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxTagCount", required: false }] }], defaultExpandAll: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultExpandAll", required: false }] }], virtualScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualScroll", required: false }] }], rowHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowHeight", required: false }] }], viewportHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewportHeight", required: false }] }], overscan: [{ type: i0.Input, args: [{ isSignal: true, alias: "overscan", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], touch: [{ type: i0.Output, args: ["touch"] }], panelTpl: [{ type: i0.ViewChild, args: ['panelTpl', { ...{ read: TemplateRef }, isSignal: true }] }] } });