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-cascader.mjs","sources":["../../../projects/lib/cascader/cascader.ts","../../../projects/lib/cascader/cascader.html","../../../projects/lib/cascader/ngwr-cascader.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 { Directionality } from '@angular/cdk/bidi';\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { type OverlayRef, ScrollStrategyOptions } from '@angular/cdk/overlay';\nimport { TemplatePortal } from '@angular/cdk/portal';\nimport {\n Component,\n DestroyRef,\n ElementRef,\n Injector,\n TemplateRef,\n ViewContainerRef,\n ViewEncapsulation,\n afterNextRender,\n computed,\n effect,\n inject,\n input,\n model,\n output,\n signal,\n untracked,\n viewChild,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport type { FormValueControl } from '@angular/forms/signals';\n\nimport { useFormFieldAria } from 'ngwr/form';\nimport { useI18nText } from 'ngwr/i18n';\nimport { WR_OVERLAY, WrOutsideClick, wrFollowDirection } from 'ngwr/overlay';\n\nimport type { WrCascaderOption } from './interfaces';\n\nlet panelUid = 0;\n\n/**\n * Multi-level select — drills down through hierarchical categories\n * (e.g. country → state → city). Each level renders as a column; clicks\n * advance to the next column. Selecting a leaf (no children) commits\n * the full path.\n *\n * A signal-forms native control: it implements `FormValueControl<unknown>`,\n * so `[formField]` binds straight to its `value` model — no\n * `ControlValueAccessor` in between. `[(value)]` works standalone. The value\n * is the path through the tree (an array from root to leaf).\n *\n * @example\n * ```html\n * <!-- signal forms -->\n * <wr-cascader [options]=\"locations\" [formField]=\"form.path\" placeholder=\"Pick a location\" />\n *\n * <!-- standalone two-way binding -->\n * <wr-cascader [options]=\"locations\" [(value)]=\"path\" placeholder=\"Pick a location\" />\n * ```\n *\n * ```ts\n * locations: WrCascaderOption[] = [\n * {\n * value: 'us', label: 'United States', children: [\n * { value: 'ny', label: 'New York', children: [\n * { value: 'nyc', label: 'NYC' },\n * { value: 'buf', label: 'Buffalo' },\n * ] },\n * ],\n * },\n * ];\n * ```\n *\n * @see https://ngwr.dev/reference/components/cascader\n */\nexport type WrCascaderSize = 'sm' | 'md' | 'lg';\n\n@Component({\n selector: 'wr-cascader',\n templateUrl: './cascader.html',\n styleUrl: './cascader.scss',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n})\nexport class WrCascader<T = string> implements FormValueControl<unknown> {\n /** Accessible name. Falls back to `select.clearSelection`, then `'Clear selection'`. */\n readonly clearLabel = input<string | null>(null);\n\n protected readonly resolvedClearLabel = useI18nText(this.clearLabel, 'select.clearSelection', 'Clear selection');\n\n /** Root-level options. Each may have `children` for deeper levels. */\n readonly options = input.required<readonly WrCascaderOption<T>[]>();\n\n /** Placeholder shown when no path is selected. @default '' */\n readonly placeholder = input<string>('');\n\n /**\n * Accessible name of the trigger. Falls back to the placeholder, then to\n * `select.label` — a `role=\"combobox\"` with nothing selected and no\n * placeholder otherwise has no name at all.\n */\n readonly ariaLabel = input<string | null>(null);\n\n private readonly labelText = useI18nText(this.ariaLabel, 'select.label', 'Select');\n protected readonly resolvedAriaLabel = computed(() => {\n // Not `??`: an empty placeholder must fall through to the catalog string.\n const explicit = this.ariaLabel();\n if (explicit) return explicit;\n const placeholder = this.placeholder();\n return placeholder ? placeholder : this.labelText();\n });\n\n /**\n * Disable the cascader. Bound automatically from the field's disabled state\n * when used with `[formField]`.\n *\n * @default false\n */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n /**\n * Refuse changes while the trigger stays focusable and the path still submits.\n * Bound automatically from the field's readonly state when used with\n * `[formField]`.\n *\n * The panel is where every edit happens, so a read-only cascader simply does\n * not open — there is nothing to browse that is not already on the trigger —\n * and the clear button goes away with it. Mirrored as `aria-readonly`, which\n * role `combobox` supports.\n *\n * @default false\n */\n readonly readonly = input(false, { transform: coerceBooleanProperty });\n\n /** The surrounding `<wr-form-field>`'s error state. @internal */\n protected readonly fieldAria = useFormFieldAria();\n\n /** Control size — shares the `--wr-control-*` contract. @default 'md' */\n readonly size = input<WrCascaderSize>('md');\n\n /** Show a clear-all (×) button on the trigger when a path is selected. @default true */\n readonly clearable = input(true, { transform: coerceBooleanProperty });\n\n /**\n * Allow selecting non-leaf (parent) nodes. When `false`, only leaves\n * (nodes without children) commit a selection. @default false\n */\n readonly changeOnSelect = input(false, { transform: coerceBooleanProperty });\n\n /** Separator between labels in the trigger display. @default '/' */\n readonly separator = input<string>('/');\n\n /**\n * Committed selection path (full array from root to leaf). Bound by\n * `[formField]`, or two-way via `[(value)]`.\n */\n readonly value = model<unknown>([]);\n\n /** Emitted on blur / commit so a bound field can mark itself touched. */\n readonly touch = output<void>();\n\n /** Committed selection path (full T[] from root to leaf). @internal */\n protected readonly path = signal<readonly T[]>([]);\n\n /** Currently-expanded column path — drives which columns the panel shows. @internal */\n protected readonly activePath = signal<readonly T[]>([]);\n\n protected readonly open = signal(false);\n\n /** Panel id used by the trigger's `aria-controls`. */\n protected readonly panelId = `wr-cascader-panel-${++panelUid}`;\n\n /**\n * Columns visible in the panel. Each column shows the children of the\n * preceding activePath entry. Column 0 = root options. The last\n * column is whatever the deepest active node's children resolve to —\n * we only render a column when there are children to show.\n */\n protected readonly columns = computed<readonly (readonly WrCascaderOption<T>[])[]>(() => {\n const cols: (readonly WrCascaderOption<T>[])[] = [this.options()];\n const trail = this.activePath();\n let list: readonly WrCascaderOption<T>[] = this.options();\n for (const v of trail) {\n const node = list.find(o => o.value === v);\n if (!node?.children?.length) break;\n cols.push(node.children);\n list = node.children;\n }\n return cols;\n });\n\n /** Label trail joined by `separator()` — what the trigger shows. */\n protected readonly displayLabel = computed(() => {\n const p = this.path();\n if (p.length === 0) return null;\n const labels: string[] = [];\n let list: readonly WrCascaderOption<T>[] = this.options();\n for (const v of p) {\n const node = list.find(o => o.value === v);\n if (!node) return null;\n labels.push(node.label);\n list = node.children ?? [];\n }\n const sep = ` ${this.separator()} `;\n return labels.join(sep);\n });\n\n protected readonly hasSelection = computed(() => this.path().length > 0);\n\n protected readonly classes = computed(() => {\n const parts = ['wr-cascader'];\n const size = this.size();\n if (size !== 'md') parts.push(`wr-cascader--${size}`);\n if (this.open()) parts.push('wr-cascader--open');\n if (this.disabled()) parts.push('wr-cascader--disabled');\n else if (this.readonly()) parts.push('wr-cascader--readonly');\n return parts.join(' ');\n });\n\n protected readonly panelTpl = viewChild.required('panelTpl', { read: TemplateRef });\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly overlay = inject(WR_OVERLAY);\n private readonly outsideClick = inject(WrOutsideClick);\n private readonly vcr = inject(ViewContainerRef);\n private readonly scrollStrategies = inject(ScrollStrategyOptions);\n private readonly destroyRef = inject(DestroyRef);\n private readonly injector = inject(Injector);\n /**\n * Ambient reading direction, for the open panel alone — nothing in this\n * component reads it directly. Optional so a bare `TestBed` needs no\n * provider; `Directionality` is root-provided anyway, and a missing one\n * simply reads as `ltr`.\n */\n private readonly dir = inject(Directionality, { optional: true });\n private overlayRef: OverlayRef | null = null;\n\n constructor() {\n // Same contract as wr-select / wr-dropdown / wr-lightbox: an overlay lives in\n // the CDK container, not in this component's view, so destroying the\n // component while the panel is open would strand the pane and its scroll\n // strategy.\n this.destroyRef.onDestroy(() => this.closeOverlay());\n\n effect(() => {\n if (this.open()) {\n this.openOverlay();\n } else {\n this.closeOverlay();\n }\n });\n\n // Close the panel if the control becomes disabled or read-only while open.\n effect(() => {\n if (this.disabled() || this.readonly()) this.open.set(false);\n });\n\n // Mirror an external `value` write into the internal path/activePath\n // (the old `writeValue`). Skipped when the write merely echoes the\n // committed path, so a live drill-down can never be clobbered.\n effect(() => {\n // Coerce null/undefined/non-array to an empty path — a classic-forms\n // binding can write null, which the old `writeValue(value: unknown)`\n // treated as \"no selection\" too.\n const value = this.value();\n untracked(() => {\n const next: readonly T[] = Array.isArray(value) ? (value as readonly T[]) : [];\n if (this.pathsEqual(this.path(), next)) return;\n this.path.set(next);\n this.activePath.set(next);\n });\n });\n }\n\n // Template handlers\n\n protected onTriggerClick(): void {\n if (this.disabled() || this.readonly()) return;\n if (!this.open()) this.activePath.set(this.path());\n this.open.update(v => !v);\n }\n\n /**\n * ArrowDown / ArrowUp open the panel, Alt+ArrowDown included — the combobox way in,\n * and the shape `wr-dropdown`'s trigger uses. Enter and Space need no branch: the\n * trigger is a real `<button>`, so the browser turns them into the click above.\n *\n * Only while closed. Once the panel is up the caret is inside it, and its options\n * own their own keys.\n */\n protected onTriggerKeydown(event: KeyboardEvent): void {\n if (this.disabled() || this.readonly() || this.open()) return;\n\n // Backspace is the × from the keyboard, and it has to be: the × is a\n // `tabindex=\"-1\"` span INSIDE this button, and a keydown goes to the focused\n // element, so the `(keydown.enter)` / `(keydown.space)` it used to carry could\n // never fire. Clearing was reachable by pointer alone — a WCAG 2.1.1 failure,\n // not a missing convenience. The span stays unfocusable, because a focusable\n // child of a button is `nested-interactive`. Same key, same gating as\n // `wr-select`: `clearable()` IS the clear control, so a consumer who turned\n // the × off did not ask for a keyboard twin of it.\n if (event.key === 'Backspace') {\n if (!this.clearable() || !this.hasSelection()) return;\n event.preventDefault();\n this.clearSelection(event);\n return;\n }\n\n if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp') return;\n event.preventDefault();\n this.activePath.set(this.path());\n this.open.set(true);\n }\n\n protected onOptionClick(colIndex: number, opt: WrCascaderOption<T>, event: Event): void {\n event.stopPropagation();\n if (opt.disabled || this.disabled() || this.readonly()) return;\n\n const head = this.activePath().slice(0, colIndex);\n const newPath = [...head, opt.value];\n\n const hasChildren = !!opt.children?.length;\n\n // Always update active column for visual feedback / next column.\n this.activePath.set(newPath);\n\n // Commit when we've reached a leaf, or when changeOnSelect is on.\n if (!hasChildren || this.changeOnSelect()) {\n this.path.set(newPath);\n this.value.set(newPath);\n this.touch.emit();\n // Close once we hit a true leaf — parent commits keep the panel open.\n if (!hasChildren) this.open.set(false);\n }\n }\n\n protected clearSelection(event: Event): void {\n event.stopPropagation();\n if (this.disabled() || this.readonly()) return;\n this.path.set([]);\n this.activePath.set([]);\n this.value.set([]);\n this.touch.emit();\n }\n\n protected isActiveAt(colIndex: number, value: T): boolean {\n return this.activePath()[colIndex] === value;\n }\n\n /**\n * Whether this option is the committed choice — `null` when it is not a\n * choice at all.\n *\n * Two questions the panel has to keep apart, and `--active` answers only the\n * first: `activePath()` is where the user has NAVIGATED to, `path()` is what\n * they have COMMITTED. They agree once a leaf is picked and diverge for the\n * whole walk down.\n *\n * `null` — the attribute absent — on a branch while `changeOnSelect` is off,\n * because such a branch genuinely cannot be chosen; ARIA reads a missing\n * `aria-selected` as \"not selectable\", which is exactly true here. That makes\n * this binding the first expression the `changeOnSelect` contract has ever had\n * in ARIA, in both directions.\n */\n protected isSelectedAt(colIndex: number, opt: WrCascaderOption<T>): boolean | null {\n const committable = !opt.children?.length || this.changeOnSelect();\n if (!committable) return null;\n const path = this.path();\n return colIndex === path.length - 1 && path[colIndex] === opt.value;\n }\n\n /** Stable id for one option — what a column's `aria-labelledby` points at. */\n protected optionId(colIndex: number, optIndex: number): string {\n return `${this.panelId}-opt-${colIndex}-${optIndex}`;\n }\n\n /** Stable id for one column — what an expanded branch's `aria-controls` points at. */\n protected columnId(colIndex: number): string {\n return `${this.panelId}-col-${colIndex}`;\n }\n\n /**\n * The option whose children a column holds, by id — its accessible name.\n *\n * The columns are DOM SIBLINGS, so nothing in the markup says the second one\n * belongs to \"Europe\". Column 0 has no parent and stays unnamed; the tree\n * itself already carries the control's name.\n */\n protected parentOptionId(colIndex: number): string | null {\n if (colIndex === 0) return null;\n const parent = this.columns()[colIndex - 1] ?? [];\n const index = parent.findIndex(o => this.isActiveAt(colIndex - 1, o.value));\n return index < 0 ? null : this.optionId(colIndex - 1, index);\n }\n\n private pathsEqual(a: readonly T[], b: readonly T[]): boolean {\n return a.length === b.length && a.every((v, i) => v === b[i]);\n }\n\n // Overlay\n\n private openOverlay(): void {\n if (this.overlayRef) return;\n\n const positionStrategy = this.overlay\n .position()\n .flexibleConnectedTo(this.host)\n .withPositions([\n { originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top' },\n { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom' },\n ])\n .withPush(true);\n\n this.overlayRef = this.overlay.create({\n positionStrategy,\n scrollStrategy: this.scrollStrategies.reposition(),\n panelClass: 'wr-cascader-overlay',\n });\n\n // The columns cascade inline-wards, and the CDK captured the direction as a\n // string when this ref was created — so a flip while the panel is open left\n // the whole cascade running the other way from the page around it.\n wrFollowDirection(this.overlayRef, this.dir, this.injector);\n\n const portal = new TemplatePortal(this.panelTpl(), this.vcr);\n this.overlayRef.attach(portal);\n\n // Move the caret into the panel it just opened. Nothing did, and the pane is\n // appended to `<body>`, so an opened cascader left focus on the trigger and its\n // options were reachable only by tabbing past the whole rest of the page —\n // `wr-tree` and `wr-context-menu` were the same defect. `closeOverlay` below\n // already assumes this is where the caret lives.\n //\n // `afterNextRender`, NOT `queueMicrotask`: under zoneless CD change detection runs\n // in a macrotask, so a microtask queued here fires before the columns are in the\n // DOM — the trap that once left `wr-calendar`'s ring and its real focus on\n // different days.\n afterNextRender(() => this.focusPanelOption(), { injector: this.injector });\n\n this.outsideClick\n .outsidePointerEvents(this.overlayRef)\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe(event => {\n if (this.host.nativeElement.contains(event.target as Node)) return;\n this.open.set(false);\n });\n\n this.overlayRef\n .keydownEvents()\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe(event => {\n if (event.key === 'Escape') {\n event.preventDefault();\n this.open.set(false);\n }\n });\n }\n\n /**\n * The option the panel opens on: the selected one in the first column when there is\n * a selection, otherwise the first enabled root. A disabled option is skipped — it\n * still carries `tabindex=\"-1\"`, so `focus()` would land on it and answer for a\n * choice nobody can make.\n */\n private focusPanelOption(): void {\n const pane = this.overlayRef?.overlayElement;\n if (!pane) return;\n const option =\n pane.querySelector<HTMLElement>('.wr-cascader__opt--active:not(.wr-cascader__opt--disabled)') ??\n pane.querySelector<HTMLElement>('.wr-cascader__opt:not(.wr-cascader__opt--disabled)');\n option?.focus();\n }\n\n private closeOverlay(): void {\n if (!this.overlayRef) return;\n // Every enabled option carries `tabindex=\"0\"` and commits on Enter, so on\n // the keyboard the caret is INSIDE the pane by design — and the ordinary\n // way to finish choosing (`onOptionClick` on a leaf) closes it. Disposing\n // without handing focus back dropped it on `<body>` on the SUCCESS path,\n // not merely on dismissal: a keyboard user who had just picked a value then\n // had to Tab from the top of the document to get back to the control.\n // Untouched when focus had already moved elsewhere — that click is usually\n // what closed us, and stealing the caret back would fight the user for it.\n const pane = this.overlayRef.overlayElement;\n const focusWasInside = pane.contains(this.host.nativeElement.ownerDocument.activeElement);\n this.overlayRef.dispose();\n this.overlayRef = null;\n if (focusWasInside) this.host.nativeElement.querySelector<HTMLElement>('.wr-cascader__trigger')?.focus();\n }\n}\n\nexport type { WrCascaderOption } from './interfaces';\n","<button\n type=\"button\"\n class=\"wr-cascader__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)=\"onTriggerKeydown($event)\"\n (blur)=\"touch.emit()\"\n>\n @if (displayLabel(); as label) {\n <span class=\"wr-cascader__value\">{{ label }}</span>\n } @else {\n <span class=\"wr-cascader__placeholder\">{{ placeholder() }}</span>\n }\n\n @if (clearable() && hasSelection() && !disabled() && !readonly()) {\n <span\n class=\"wr-cascader__clear\"\n role=\"button\"\n [attr.aria-label]=\"resolvedClearLabel()\"\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-cascader__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<ng-template #panelTpl>\n <div\n class=\"wr-cascader-panel\"\n [class.wr-cascader-panel--sm]=\"size() === 'sm'\"\n [class.wr-cascader-panel--lg]=\"size() === 'lg'\"\n role=\"tree\"\n [attr.id]=\"panelId\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n >\n <!--\n tree / group / treeitem, and NOT menu. A combobox's popup may be a listbox,\n a tree, a grid or a dialog and nothing else, so `aria-haspopup=\"menu\"` on\n the trigger was an author error — and a `menu` may own menuitems and\n groups, never other menus, so the columns were a second one. Neither is\n visible to axe: `menu` is a valid token for the global `aria-haspopup`, and\n `aria-required-children` passes a menu-inside-menu (measured against this\n exact fragment). A tree is what this control has always been — the value is\n a PATH, and only `treeitem` supports aria-expanded, aria-level,\n aria-setsize, aria-posinset and aria-selected at once.\n\n The columns stay `group` rather than collapsing to `role=\"presentation\"`,\n which is also axe-clean: the DOM is column-MAJOR, so a flat tree would\n leave level plus document order as the only structure, and \"Germany\"\n (level 2) would read as a child of \"Antarctica\" (level 1, the item\n immediately before it in source order).\n -->\n @for (col of columns(); track $index; let colIndex = $index) {\n <ul\n class=\"wr-cascader__col\"\n role=\"group\"\n [attr.id]=\"columnId(colIndex)\"\n [attr.aria-labelledby]=\"parentOptionId(colIndex)\"\n >\n @for (opt of col; track opt.value; let optIndex = $index) {\n <!--\n `aria-expanded` is exactly `isActiveAt`: `columns()` renders the next\n column for the active option and only when it has children, so the\n state can never claim a column that is not on screen — and\n `aria-controls` rides that same invariant, which is what makes\n \"expanded\" refer to something when the expanded content is a SIBLING\n rather than a descendant. It is emitted only while expanded: a\n reference to an absent id is a violation with `aria-expanded=\"true\"`\n and clean while collapsed.\n\n `aria-level` is load-bearing rather than decorative. The columns are\n siblings, so the DOM ancestry represents no level at all and every\n option would read as level 1. `aria-setsize` / `aria-posinset` are\n not strictly required — each column IS a complete sibling set — and\n are written anyway, because a tree that owns sibling groups is the\n uncommon shape where browser/AT pairs are known to miscompute both.\n\n `aria-selected` is written on every option that can be COMMITTED,\n `false` included, matching `wr-tree`. The alternative a reviewer may\n prefer: only the selected node, leaning on treeitem's implicit false,\n which is quieter in a long column and loses the \"this row is\n selectable\" signal that presence carries.\n -->\n <li\n class=\"wr-cascader__opt\"\n role=\"treeitem\"\n [attr.id]=\"optionId(colIndex, optIndex)\"\n [class.wr-cascader__opt--active]=\"isActiveAt(colIndex, opt.value)\"\n [class.wr-cascader__opt--disabled]=\"opt.disabled\"\n [attr.tabindex]=\"opt.disabled ? -1 : 0\"\n [attr.aria-disabled]=\"opt.disabled ? true : null\"\n [attr.aria-level]=\"colIndex + 1\"\n [attr.aria-setsize]=\"$count\"\n [attr.aria-posinset]=\"optIndex + 1\"\n [attr.aria-selected]=\"isSelectedAt(colIndex, opt)\"\n [attr.aria-expanded]=\"opt.children?.length ? isActiveAt(colIndex, opt.value) : null\"\n [attr.aria-controls]=\"\n opt.children?.length && isActiveAt(colIndex, opt.value) ? columnId(colIndex + 1) : null\n \"\n (click)=\"onOptionClick(colIndex, opt, $event)\"\n (keydown.enter)=\"onOptionClick(colIndex, opt, $event)\"\n (keydown.space)=\"onOptionClick(colIndex, opt, $event)\"\n >\n <span class=\"wr-cascader__opt-label\">{{ opt.label }}</span>\n @if (opt.children?.length) {\n <svg\n class=\"wr-icon__svg wr-cascader__opt-arrow\"\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=\"m9 18 6-6-6-6\" />\n </svg>\n }\n </li>\n }\n </ul>\n }\n </div>\n</ng-template>\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-cascader.mjs","sources":["../../../projects/lib/cascader/cascader.ts","../../../projects/lib/cascader/cascader.html","../../../projects/lib/cascader/ngwr-cascader.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 { Directionality } from '@angular/cdk/bidi';\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { type OverlayRef, ScrollStrategyOptions } from '@angular/cdk/overlay';\nimport { TemplatePortal } from '@angular/cdk/portal';\nimport {\n Component,\n DestroyRef,\n ElementRef,\n Injector,\n TemplateRef,\n ViewContainerRef,\n ViewEncapsulation,\n afterNextRender,\n computed,\n effect,\n inject,\n input,\n model,\n output,\n signal,\n untracked,\n viewChild,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport type { FormValueControl } from '@angular/forms/signals';\n\nimport { useFormFieldAria } from 'ngwr/form';\nimport { useI18nText } from 'ngwr/i18n';\nimport { WR_OVERLAY, WrOutsideClick, wrFollowDirection } from 'ngwr/overlay';\n\nimport type { WrCascaderOption } from './interfaces';\n\nlet panelUid = 0;\n\n/**\n * Multi-level select — drills down through hierarchical categories\n * (e.g. country → state → city). Each level renders as a column; clicks\n * advance to the next column. Selecting a leaf (no children) commits\n * the full path.\n *\n * A signal-forms native control: it implements `FormValueControl<unknown>`,\n * so `[formField]` binds straight to its `value` model — no\n * `ControlValueAccessor` in between. `[(value)]` works standalone. The value\n * is the path through the tree (an array from root to leaf).\n *\n * @example\n * ```html\n * <!-- signal forms -->\n * <wr-cascader [options]=\"locations\" [formField]=\"form.path\" placeholder=\"Pick a location\" />\n *\n * <!-- standalone two-way binding -->\n * <wr-cascader [options]=\"locations\" [(value)]=\"path\" placeholder=\"Pick a location\" />\n * ```\n *\n * ```ts\n * locations: WrCascaderOption[] = [\n * {\n * value: 'us', label: 'United States', children: [\n * { value: 'ny', label: 'New York', children: [\n * { value: 'nyc', label: 'NYC' },\n * { value: 'buf', label: 'Buffalo' },\n * ] },\n * ],\n * },\n * ];\n * ```\n *\n * @see https://ngwr.dev/reference/components/cascader\n */\nexport type WrCascaderSize = 'sm' | 'md' | 'lg';\n\n@Component({\n selector: 'wr-cascader',\n templateUrl: './cascader.html',\n styleUrl: './cascader.scss',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n})\nexport class WrCascader<T = string> implements FormValueControl<unknown> {\n /** Accessible name. Falls back to `select.clearSelection`, then `'Clear selection'`. */\n readonly clearLabel = input<string | null>(null);\n\n protected readonly resolvedClearLabel = useI18nText(this.clearLabel, 'select.clearSelection', 'Clear selection');\n\n /** Root-level options. Each may have `children` for deeper levels. */\n readonly options = input.required<readonly WrCascaderOption<T>[]>();\n\n /** Placeholder shown when no path is selected. @default '' */\n readonly placeholder = input<string>('');\n\n /**\n * Accessible name of the trigger. Falls back to the placeholder, then to\n * `select.label` — a `role=\"combobox\"` with nothing selected and no\n * placeholder otherwise has no name at all.\n */\n readonly ariaLabel = input<string | null>(null);\n\n private readonly labelText = useI18nText(this.ariaLabel, 'select.label', 'Select');\n protected readonly resolvedAriaLabel = computed(() => {\n // Not `??`: an empty placeholder must fall through to the catalog string.\n const explicit = this.ariaLabel();\n if (explicit) return explicit;\n const placeholder = this.placeholder();\n return placeholder ? placeholder : this.labelText();\n });\n\n /**\n * Disable the cascader. Bound automatically from the field's disabled state\n * when used with `[formField]`.\n *\n * @default false\n */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n /**\n * Refuse changes while the trigger stays focusable and the path still submits.\n * Bound automatically from the field's readonly state when used with\n * `[formField]`.\n *\n * The panel is where every edit happens, so a read-only cascader simply does\n * not open — there is nothing to browse that is not already on the trigger —\n * and the clear button goes away with it. Mirrored as `aria-readonly`, which\n * role `combobox` supports.\n *\n * @default false\n */\n readonly readonly = input(false, { transform: coerceBooleanProperty });\n\n /** The surrounding `<wr-form-field>`'s error state. @internal */\n protected readonly fieldAria = useFormFieldAria();\n\n /** Control size — shares the `--wr-control-*` contract. @default 'md' */\n readonly size = input<WrCascaderSize>('md');\n\n /** Show a clear-all (×) button on the trigger when a path is selected. @default true */\n readonly clearable = input(true, { transform: coerceBooleanProperty });\n\n /**\n * Allow selecting non-leaf (parent) nodes. When `false`, only leaves\n * (nodes without children) commit a selection. @default false\n */\n readonly changeOnSelect = input(false, { transform: coerceBooleanProperty });\n\n /** Separator between labels in the trigger display. @default '/' */\n readonly separator = input<string>('/');\n\n /**\n * Committed selection path (full array from root to leaf). Bound by\n * `[formField]`, or two-way via `[(value)]`.\n */\n readonly value = model<unknown>([]);\n\n /** Emitted on blur / commit so a bound field can mark itself touched. */\n readonly touch = output<void>();\n\n /** Committed selection path (full T[] from root to leaf). @internal */\n protected readonly path = signal<readonly T[]>([]);\n\n /** Currently-expanded column path — drives which columns the panel shows. @internal */\n protected readonly activePath = signal<readonly T[]>([]);\n\n protected readonly open = signal(false);\n\n /** Panel id used by the trigger's `aria-controls`. */\n protected readonly panelId = `wr-cascader-panel-${++panelUid}`;\n\n /**\n * Columns visible in the panel. Each column shows the children of the\n * preceding activePath entry. Column 0 = root options. The last\n * column is whatever the deepest active node's children resolve to —\n * we only render a column when there are children to show.\n */\n protected readonly columns = computed<readonly (readonly WrCascaderOption<T>[])[]>(() => {\n const cols: (readonly WrCascaderOption<T>[])[] = [this.options()];\n const trail = this.activePath();\n let list: readonly WrCascaderOption<T>[] = this.options();\n for (const v of trail) {\n const node = list.find(o => o.value === v);\n if (!node?.children?.length) break;\n cols.push(node.children);\n list = node.children;\n }\n return cols;\n });\n\n /** Label trail joined by `separator()` — what the trigger shows. */\n protected readonly displayLabel = computed(() => {\n const p = this.path();\n if (p.length === 0) return null;\n const labels: string[] = [];\n let list: readonly WrCascaderOption<T>[] = this.options();\n for (const v of p) {\n const node = list.find(o => o.value === v);\n if (!node) return null;\n labels.push(node.label);\n list = node.children ?? [];\n }\n const sep = ` ${this.separator()} `;\n return labels.join(sep);\n });\n\n protected readonly hasSelection = computed(() => this.path().length > 0);\n\n protected readonly classes = computed(() => {\n const parts = ['wr-cascader'];\n const size = this.size();\n if (size !== 'md') parts.push(`wr-cascader--${size}`);\n if (this.open()) parts.push('wr-cascader--open');\n if (this.disabled()) parts.push('wr-cascader--disabled');\n else if (this.readonly()) parts.push('wr-cascader--readonly');\n return parts.join(' ');\n });\n\n protected readonly panelTpl = viewChild.required('panelTpl', { read: TemplateRef });\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly overlay = inject(WR_OVERLAY);\n private readonly outsideClick = inject(WrOutsideClick);\n private readonly vcr = inject(ViewContainerRef);\n private readonly scrollStrategies = inject(ScrollStrategyOptions);\n private readonly destroyRef = inject(DestroyRef);\n private readonly injector = inject(Injector);\n /**\n * Ambient reading direction, for the open panel alone — nothing in this\n * component reads it directly. Optional so a bare `TestBed` needs no\n * provider; `Directionality` is root-provided anyway, and a missing one\n * simply reads as `ltr`.\n */\n private readonly dir = inject(Directionality, { optional: true });\n private overlayRef: OverlayRef | null = null;\n\n constructor() {\n // Same contract as wr-select / wr-dropdown / wr-lightbox: an overlay lives in\n // the CDK container, not in this component's view, so destroying the\n // component while the panel is open would strand the pane and its scroll\n // strategy.\n this.destroyRef.onDestroy(() => this.closeOverlay());\n\n effect(() => {\n if (this.open()) {\n this.openOverlay();\n } else {\n this.closeOverlay();\n }\n });\n\n // Close the panel if the control becomes disabled or read-only while open.\n effect(() => {\n if (this.disabled() || this.readonly()) this.open.set(false);\n });\n\n // Mirror an external `value` write into the internal path/activePath\n // (the old `writeValue`). Skipped when the write merely echoes the\n // committed path, so a live drill-down can never be clobbered.\n effect(() => {\n // Coerce null/undefined/non-array to an empty path — a classic-forms\n // binding can write null, which the old `writeValue(value: unknown)`\n // treated as \"no selection\" too.\n const value = this.value();\n untracked(() => {\n const next: readonly T[] = Array.isArray(value) ? (value as readonly T[]) : [];\n if (this.pathsEqual(this.path(), next)) return;\n this.path.set(next);\n this.activePath.set(next);\n });\n });\n }\n\n // Template handlers\n\n protected onTriggerClick(): void {\n if (this.disabled() || this.readonly()) return;\n if (!this.open()) this.activePath.set(this.path());\n this.open.update(v => !v);\n }\n\n /**\n * ArrowDown / ArrowUp open the panel, Alt+ArrowDown included — the combobox way in,\n * and the shape `wr-dropdown`'s trigger uses. Enter and Space need no branch: the\n * trigger is a real `<button>`, so the browser turns them into the click above.\n *\n * Only while closed. Once the panel is up the caret is inside it, and its options\n * own their own keys.\n */\n protected onTriggerKeydown(event: KeyboardEvent): void {\n if (this.disabled() || this.readonly() || this.open()) return;\n\n // Backspace is the × from the keyboard, and it has to be: the × is a\n // `tabindex=\"-1\"` span INSIDE this button, and a keydown goes to the focused\n // element, so the `(keydown.enter)` / `(keydown.space)` it used to carry could\n // never fire. Clearing was reachable by pointer alone — a WCAG 2.1.1 failure,\n // not a missing convenience. The span stays unfocusable, because a focusable\n // child of a button is `nested-interactive`. Same key, same gating as\n // `wr-select`: `clearable()` IS the clear control, so a consumer who turned\n // the × off did not ask for a keyboard twin of it.\n if (event.key === 'Backspace') {\n if (!this.clearable() || !this.hasSelection()) return;\n event.preventDefault();\n this.clearSelection(event);\n return;\n }\n\n if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp') return;\n event.preventDefault();\n this.activePath.set(this.path());\n this.open.set(true);\n }\n\n protected onOptionClick(colIndex: number, opt: WrCascaderOption<T>, event: Event): void {\n event.stopPropagation();\n if (opt.disabled || this.disabled() || this.readonly()) return;\n\n const head = this.activePath().slice(0, colIndex);\n const newPath = [...head, opt.value];\n\n const hasChildren = !!opt.children?.length;\n\n // Always update active column for visual feedback / next column.\n this.activePath.set(newPath);\n\n // Commit when we've reached a leaf, or when changeOnSelect is on.\n if (!hasChildren || this.changeOnSelect()) {\n this.path.set(newPath);\n this.value.set(newPath);\n this.touch.emit();\n // Close once we hit a true leaf — parent commits keep the panel open.\n if (!hasChildren) this.open.set(false);\n }\n }\n\n protected clearSelection(event: Event): void {\n event.stopPropagation();\n if (this.disabled() || this.readonly()) return;\n this.path.set([]);\n this.activePath.set([]);\n this.value.set([]);\n this.touch.emit();\n }\n\n protected isActiveAt(colIndex: number, value: T): boolean {\n return this.activePath()[colIndex] === value;\n }\n\n /**\n * Whether this option is the committed choice — `null` when it is not a\n * choice at all.\n *\n * Two questions the panel has to keep apart, and `--active` answers only the\n * first: `activePath()` is where the user has NAVIGATED to, `path()` is what\n * they have COMMITTED. They agree once a leaf is picked and diverge for the\n * whole walk down.\n *\n * `null` — the attribute absent — on a branch while `changeOnSelect` is off,\n * because such a branch genuinely cannot be chosen; ARIA reads a missing\n * `aria-selected` as \"not selectable\", which is exactly true here. That makes\n * this binding the first expression the `changeOnSelect` contract has ever had\n * in ARIA, in both directions.\n */\n protected isSelectedAt(colIndex: number, opt: WrCascaderOption<T>): boolean | null {\n const committable = !opt.children?.length || this.changeOnSelect();\n if (!committable) return null;\n const path = this.path();\n return colIndex === path.length - 1 && path[colIndex] === opt.value;\n }\n\n /** Stable id for one option — what a column's `aria-labelledby` points at. */\n protected optionId(colIndex: number, optIndex: number): string {\n return `${this.panelId}-opt-${colIndex}-${optIndex}`;\n }\n\n /** Stable id for one column — what an expanded branch's `aria-controls` points at. */\n protected columnId(colIndex: number): string {\n return `${this.panelId}-col-${colIndex}`;\n }\n\n /**\n * The option whose children a column holds, by id — its accessible name.\n *\n * The columns are DOM SIBLINGS, so nothing in the markup says the second one\n * belongs to \"Europe\". Column 0 has no parent and stays unnamed; the tree\n * itself already carries the control's name.\n */\n protected parentOptionId(colIndex: number): string | null {\n if (colIndex === 0) return null;\n const parent = this.columns()[colIndex - 1] ?? [];\n const index = parent.findIndex(o => this.isActiveAt(colIndex - 1, o.value));\n return index < 0 ? null : this.optionId(colIndex - 1, index);\n }\n\n private pathsEqual(a: readonly T[], b: readonly T[]): boolean {\n return a.length === b.length && a.every((v, i) => v === b[i]);\n }\n\n // Overlay\n\n private openOverlay(): void {\n if (this.overlayRef) return;\n\n const positionStrategy = this.overlay\n .position()\n .flexibleConnectedTo(this.host)\n .withPositions([\n { originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top' },\n { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom' },\n ])\n .withPush(true);\n\n this.overlayRef = this.overlay.create({\n positionStrategy,\n scrollStrategy: this.scrollStrategies.reposition(),\n panelClass: 'wr-cascader-overlay',\n });\n\n // The columns cascade inline-wards, and the CDK captured the direction as a\n // string when this ref was created — so a flip while the panel is open left\n // the whole cascade running the other way from the page around it.\n wrFollowDirection(this.overlayRef, this.dir, this.injector);\n\n const portal = new TemplatePortal(this.panelTpl(), this.vcr);\n this.overlayRef.attach(portal);\n\n // Move the caret into the panel it just opened. Nothing did, and the pane is\n // appended to `<body>`, so an opened cascader left focus on the trigger and its\n // options were reachable only by tabbing past the whole rest of the page —\n // `wr-tree` and `wr-context-menu` were the same defect. `closeOverlay` below\n // already assumes this is where the caret lives.\n //\n // `afterNextRender`, NOT `queueMicrotask`: under zoneless CD change detection runs\n // in a macrotask, so a microtask queued here fires before the columns are in the\n // DOM — the trap that once left `wr-calendar`'s ring and its real focus on\n // different days.\n afterNextRender(() => this.focusPanelOption(), { injector: this.injector });\n\n this.outsideClick\n .outsidePointerEvents(this.overlayRef)\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe(event => {\n if (this.host.nativeElement.contains(event.target as Node)) return;\n this.open.set(false);\n });\n\n this.overlayRef\n .keydownEvents()\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe(event => {\n if (event.key === 'Escape') {\n event.preventDefault();\n this.open.set(false);\n }\n });\n }\n\n /**\n * The option the panel opens on: the selected one in the first column when there is\n * a selection, otherwise the first enabled root. A disabled option is skipped — it\n * still carries `tabindex=\"-1\"`, so `focus()` would land on it and answer for a\n * choice nobody can make.\n */\n private focusPanelOption(): void {\n const pane = this.overlayRef?.overlayElement;\n if (!pane) return;\n const option =\n pane.querySelector<HTMLElement>('.wr-cascader__opt--active:not(.wr-cascader__opt--disabled)') ??\n pane.querySelector<HTMLElement>('.wr-cascader__opt:not(.wr-cascader__opt--disabled)');\n option?.focus();\n }\n\n private closeOverlay(): void {\n if (!this.overlayRef) return;\n // Every enabled option carries `tabindex=\"0\"` and commits on Enter, so on\n // the keyboard the caret is INSIDE the pane by design — and the ordinary\n // way to finish choosing (`onOptionClick` on a leaf) closes it. Disposing\n // without handing focus back dropped it on `<body>` on the SUCCESS path,\n // not merely on dismissal: a keyboard user who had just picked a value then\n // had to Tab from the top of the document to get back to the control.\n // Untouched when focus had already moved elsewhere — that click is usually\n // what closed us, and stealing the caret back would fight the user for it.\n const pane = this.overlayRef.overlayElement;\n const focusWasInside = pane.contains(this.host.nativeElement.ownerDocument.activeElement);\n this.overlayRef.dispose();\n this.overlayRef = null;\n if (focusWasInside) this.host.nativeElement.querySelector<HTMLElement>('.wr-cascader__trigger')?.focus();\n }\n}\n\nexport type { WrCascaderOption } from './interfaces';\n","<button\n type=\"button\"\n class=\"wr-cascader__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)=\"onTriggerKeydown($event)\"\n (blur)=\"touch.emit()\"\n>\n @if (displayLabel(); as label) {\n <span class=\"wr-cascader__value\">{{ label }}</span>\n } @else {\n <span class=\"wr-cascader__placeholder\">{{ placeholder() }}</span>\n }\n\n @if (clearable() && hasSelection() && !disabled() && !readonly()) {\n <span\n class=\"wr-cascader__clear\"\n role=\"button\"\n [attr.aria-label]=\"resolvedClearLabel()\"\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-cascader__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<ng-template #panelTpl>\n <div\n class=\"wr-cascader-panel\"\n [class.wr-cascader-panel--sm]=\"size() === 'sm'\"\n [class.wr-cascader-panel--lg]=\"size() === 'lg'\"\n role=\"tree\"\n [attr.id]=\"panelId\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n >\n <!--\n tree / group / treeitem, and NOT menu. A combobox's popup may be a listbox,\n a tree, a grid or a dialog and nothing else, so `aria-haspopup=\"menu\"` on\n the trigger was an author error — and a `menu` may own menuitems and\n groups, never other menus, so the columns were a second one. Neither is\n visible to axe: `menu` is a valid token for the global `aria-haspopup`, and\n `aria-required-children` passes a menu-inside-menu (measured against this\n exact fragment). A tree is what this control has always been — the value is\n a PATH, and only `treeitem` supports aria-expanded, aria-level,\n aria-setsize, aria-posinset and aria-selected at once.\n\n The columns stay `group` rather than collapsing to `role=\"presentation\"`,\n which is also axe-clean: the DOM is column-MAJOR, so a flat tree would\n leave level plus document order as the only structure, and \"Germany\"\n (level 2) would read as a child of \"Antarctica\" (level 1, the item\n immediately before it in source order).\n -->\n @for (col of columns(); track $index; let colIndex = $index) {\n <ul\n class=\"wr-cascader__col\"\n role=\"group\"\n [attr.id]=\"columnId(colIndex)\"\n [attr.aria-labelledby]=\"parentOptionId(colIndex)\"\n >\n @for (opt of col; track opt.value; let optIndex = $index) {\n <!--\n `aria-expanded` is exactly `isActiveAt`: `columns()` renders the next\n column for the active option and only when it has children, so the\n state can never claim a column that is not on screen — and\n `aria-controls` rides that same invariant, which is what makes\n \"expanded\" refer to something when the expanded content is a SIBLING\n rather than a descendant. It is emitted only while expanded: a\n reference to an absent id is a violation with `aria-expanded=\"true\"`\n and clean while collapsed.\n\n `aria-level` is load-bearing rather than decorative. The columns are\n siblings, so the DOM ancestry represents no level at all and every\n option would read as level 1. `aria-setsize` / `aria-posinset` are\n not strictly required — each column IS a complete sibling set — and\n are written anyway, because a tree that owns sibling groups is the\n uncommon shape where browser/AT pairs are known to miscompute both.\n\n `aria-selected` is written on every option that can be COMMITTED,\n `false` included, matching `wr-tree`. The alternative a reviewer may\n prefer: only the selected node, leaning on treeitem's implicit false,\n which is quieter in a long column and loses the \"this row is\n selectable\" signal that presence carries.\n -->\n <li\n class=\"wr-cascader__opt\"\n role=\"treeitem\"\n [attr.id]=\"optionId(colIndex, optIndex)\"\n [class.wr-cascader__opt--active]=\"isActiveAt(colIndex, opt.value)\"\n [class.wr-cascader__opt--disabled]=\"opt.disabled\"\n [attr.tabindex]=\"opt.disabled ? -1 : 0\"\n [attr.aria-disabled]=\"opt.disabled ? true : null\"\n [attr.aria-level]=\"colIndex + 1\"\n [attr.aria-setsize]=\"$count\"\n [attr.aria-posinset]=\"optIndex + 1\"\n [attr.aria-selected]=\"isSelectedAt(colIndex, opt)\"\n [attr.aria-expanded]=\"opt.children?.length ? isActiveAt(colIndex, opt.value) : null\"\n [attr.aria-controls]=\"\n opt.children?.length && isActiveAt(colIndex, opt.value) ? columnId(colIndex + 1) : null\n \"\n (click)=\"onOptionClick(colIndex, opt, $event)\"\n (keydown.enter)=\"onOptionClick(colIndex, opt, $event)\"\n (keydown.space)=\"onOptionClick(colIndex, opt, $event)\"\n >\n <span class=\"wr-cascader__opt-label\">{{ opt.label }}</span>\n @if (opt.children?.length) {\n <svg\n class=\"wr-icon__svg wr-cascader__opt-arrow\"\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=\"m9 18 6-6-6-6\" />\n </svg>\n }\n </li>\n }\n </ul>\n }\n </div>\n</ng-template>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ngwr-checkbox-testing.mjs","sources":["../../../projects/lib/checkbox/testing/wr-checkbox-harness.ts","../../../projects/lib/checkbox/testing/ngwr-checkbox-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 } from '@angular/cdk/testing';\n\nimport type { WrCheckboxHarnessFilters } from './interfaces';\n\n/**\n * Test harness for `<wr-checkbox>`.\n *\n * The visible box is a `<span>` the stylesheet paints; the state lives on a real\n * `<input type=\"checkbox\">` inside the label, and that is what this harness reads\n * and clicks. Toggling through the input rather than the painted box is what makes\n * `check()` behave the way a user does — the label is what a click lands on.\n *\n * Note `checkboxValue` versus `value`: a checkbox's group identity is\n * `checkboxValue`, because `FormCheckboxControl` reserves `value` for the form\n * value. {@link getCheckboxValue} reads the identity.\n *\n * @example\n * ```ts\n * const terms = await loader.getHarness(WrCheckboxHarness.with({ label: 'I agree' }));\n * await terms.check();\n * expect(await terms.isChecked()).toBe(true);\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrCheckboxHarness extends ComponentHarness {\n static hostSelector = 'wr-checkbox';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrCheckboxHarnessFilters = {}): HarnessPredicate<WrCheckboxHarness> {\n return new HarnessPredicate(WrCheckboxHarness, options)\n .addOption('label', options.label, (harness, label) => HarnessPredicate.stringMatches(harness.getLabel(), label))\n .addOption('checked', options.checked, async (harness, checked) => (await harness.isChecked()) === checked)\n .addOption('disabled', options.disabled, async (harness, disabled) => (await harness.isDisabled()) === disabled);\n }\n\n private readonly input = this.locatorFor('input.wr-checkbox__input');\n\n /** The projected label text, trimmed. */\n async getLabel(): Promise<string> {\n return (await this.locatorFor('.wr-checkbox__label')()).text();\n }\n\n async isChecked(): Promise<boolean> {\n return (await this.input()).getProperty<boolean>('checked');\n }\n\n /**\n * Whether the box is in its third state.\n *\n * `indeterminate` is a DOM PROPERTY, not an attribute — reading the attribute\n * would report `null` for a box that is visibly dashed.\n */\n async isIndeterminate(): Promise<boolean> {\n return (await this.input()).getProperty<boolean>('indeterminate');\n }\n\n async isDisabled(): Promise<boolean> {\n return (await this.input()).getProperty<boolean>('disabled');\n }\n\n /**\n * The group identity — `checkboxValue`, not the form value.\n *\n * Read off the host's `data-checkbox-value`, which the component reflects for\n * exactly this. It used to read `value` from the inner `<input>`, an attribute\n * nothing writes, so it answered `null` for every checkbox whatever its\n * identity — the shape these harnesses are not allowed to have.\n *\n * `null` still means one honest thing: no identity, or an identity that is not\n * a primitive. An object or an array has no attribute form, and a harness\n * cannot reach a TypeScript value the DOM never carried.\n */\n async getCheckboxValue(): Promise<string | null> {\n return (await this.host()).getAttribute('data-checkbox-value');\n }\n\n /** Flip the box. A disabled checkbox does not move; assert rather than assume. */\n async toggle(): Promise<void> {\n return (await this.input()).click();\n }\n\n /** Tick the box if it is not already ticked. */\n async check(): Promise<void> {\n if (!(await this.isChecked())) await this.toggle();\n }\n\n /** Untick the box if it is ticked. */\n async uncheck(): Promise<void> {\n if (await this.isChecked()) await this.toggle();\n }\n\n async focus(): Promise<void> {\n return (await this.input()).focus();\n }\n\n async isFocused(): Promise<boolean> {\n return (await this.input()).isFocused();\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;AAAA;;;;;AAKG;AAMH;;;;;;;;;;;;;;;;;;;;AAoBG;AACG,MAAO,iBAAkB,SAAQ,gBAAgB,CAAA;AACrD,IAAA,OAAO,YAAY,GAAG,aAAa;;AAGnC,IAAA,OAAO,IAAI,CAAC,OAAA,GAAoC,EAAE,EAAA;AAChD,QAAA,OAAO,IAAI,gBAAgB,CAAC,iBAAiB,EAAE,OAAO;aACnD,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,KAAK,KAAK,gBAAgB,CAAC,aAAa,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,KAAK,CAAC;aAC/G,SAAS,CAAC,SAAS,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK,CAAC,MAAM,OAAO,CAAC,SAAS,EAAE,MAAM,OAAO;aACzG,SAAS,CAAC,UAAU,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC,MAAM,OAAO,CAAC,UAAU,EAAE,MAAM,QAAQ,CAAC;IACpH;AAEiB,IAAA,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,0BAA0B,CAAC;;AAGpE,IAAA,MAAM,QAAQ,GAAA;AACZ,QAAA,OAAO,CAAC,MAAM,IAAI,CAAC,UAAU,CAAC,qBAAqB,CAAC,EAAE,EAAE,IAAI,EAAE;IAChE;AAEA,IAAA,MAAM,SAAS,GAAA;AACb,QAAA,OAAO,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,EAAE,WAAW,CAAU,SAAS,CAAC;IAC7D;AAEA;;;;;AAKG;AACH,IAAA,MAAM,eAAe,GAAA;AACnB,QAAA,OAAO,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,EAAE,WAAW,CAAU,eAAe,CAAC;IACnE;AAEA,IAAA,MAAM,UAAU,GAAA;AACd,QAAA,OAAO,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,EAAE,WAAW,CAAU,UAAU,CAAC;IAC9D;AAEA;;;;;;;;;;;AAWG;AACH,IAAA,MAAM,gBAAgB,GAAA;AACpB,QAAA,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,YAAY,CAAC,qBAAqB,CAAC;IAChE;;AAGA,IAAA,MAAM,MAAM,GAAA;QACV,OAAO,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE;IACrC;;AAGA,IAAA,MAAM,KAAK,GAAA;AACT,QAAA,IAAI,EAAE,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;AAAE,YAAA,MAAM,IAAI,CAAC,MAAM,EAAE;IACpD;;AAGA,IAAA,MAAM,OAAO,GAAA;AACX,QAAA,IAAI,MAAM,IAAI,CAAC,SAAS,EAAE;AAAE,YAAA,MAAM,IAAI,CAAC,MAAM,EAAE;IACjD;AAEA,IAAA,MAAM,KAAK,GAAA;QACT,OAAO,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE;IACrC;AAEA,IAAA,MAAM,SAAS,GAAA;QACb,OAAO,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE;IACzC;;;ACzGF;;AAEG;;;;"}
1
+ {"version":3,"file":"ngwr-checkbox-testing.mjs","sources":["../../../projects/lib/checkbox/testing/wr-checkbox-harness.ts","../../../projects/lib/checkbox/testing/ngwr-checkbox-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 } from '@angular/cdk/testing';\n\nimport type { WrCheckboxHarnessFilters } from './interfaces';\n\n/**\n * Test harness for `<wr-checkbox>`.\n *\n * The visible box is a `<span>` the stylesheet paints; the state lives on a real\n * `<input type=\"checkbox\">` inside the label, and that is what this harness reads\n * and clicks. Toggling through the input rather than the painted box is what makes\n * `check()` behave the way a user does — the label is what a click lands on.\n *\n * Note `checkboxValue` versus `value`: a checkbox's group identity is\n * `checkboxValue`, because `FormCheckboxControl` reserves `value` for the form\n * value. {@link getCheckboxValue} reads the identity.\n *\n * @example\n * ```ts\n * const terms = await loader.getHarness(WrCheckboxHarness.with({ label: 'I agree' }));\n * await terms.check();\n * expect(await terms.isChecked()).toBe(true);\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrCheckboxHarness extends ComponentHarness {\n static hostSelector = 'wr-checkbox';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrCheckboxHarnessFilters = {}): HarnessPredicate<WrCheckboxHarness> {\n return new HarnessPredicate(WrCheckboxHarness, options)\n .addOption('label', options.label, (harness, label) => HarnessPredicate.stringMatches(harness.getLabel(), label))\n .addOption('checked', options.checked, async (harness, checked) => (await harness.isChecked()) === checked)\n .addOption('disabled', options.disabled, async (harness, disabled) => (await harness.isDisabled()) === disabled);\n }\n\n private readonly input = this.locatorFor('input.wr-checkbox__input');\n\n /** The projected label text, trimmed. */\n async getLabel(): Promise<string> {\n return (await this.locatorFor('.wr-checkbox__label')()).text();\n }\n\n async isChecked(): Promise<boolean> {\n return (await this.input()).getProperty<boolean>('checked');\n }\n\n /**\n * Whether the box is in its third state.\n *\n * `indeterminate` is a DOM PROPERTY, not an attribute — reading the attribute\n * would report `null` for a box that is visibly dashed.\n */\n async isIndeterminate(): Promise<boolean> {\n return (await this.input()).getProperty<boolean>('indeterminate');\n }\n\n async isDisabled(): Promise<boolean> {\n return (await this.input()).getProperty<boolean>('disabled');\n }\n\n /**\n * The group identity — `checkboxValue`, not the form value.\n *\n * Read off the host's `data-checkbox-value`, which the component reflects for\n * exactly this. It used to read `value` from the inner `<input>`, an attribute\n * nothing writes, so it answered `null` for every checkbox whatever its\n * identity — the shape these harnesses are not allowed to have.\n *\n * `null` still means one honest thing: no identity, or an identity that is not\n * a primitive. An object or an array has no attribute form, and a harness\n * cannot reach a TypeScript value the DOM never carried.\n */\n async getCheckboxValue(): Promise<string | null> {\n return (await this.host()).getAttribute('data-checkbox-value');\n }\n\n /** Flip the box. A disabled checkbox does not move; assert rather than assume. */\n async toggle(): Promise<void> {\n return (await this.input()).click();\n }\n\n /** Tick the box if it is not already ticked. */\n async check(): Promise<void> {\n if (!(await this.isChecked())) await this.toggle();\n }\n\n /** Untick the box if it is ticked. */\n async uncheck(): Promise<void> {\n if (await this.isChecked()) await this.toggle();\n }\n\n async focus(): Promise<void> {\n return (await this.input()).focus();\n }\n\n async isFocused(): Promise<boolean> {\n return (await this.input()).isFocused();\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;AAAA;;;;;AAKG;AAMH;;;;;;;;;;;;;;;;;;;;AAoBG;AACG,MAAO,iBAAkB,SAAQ,gBAAgB,CAAA;AACrD,IAAA,OAAO,YAAY,GAAG,aAAa;;AAGnC,IAAA,OAAO,IAAI,CAAC,OAAA,GAAoC,EAAE,EAAA;AAChD,QAAA,OAAO,IAAI,gBAAgB,CAAC,iBAAiB,EAAE,OAAO;aACnD,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,KAAK,KAAK,gBAAgB,CAAC,aAAa,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,KAAK,CAAC;aAC/G,SAAS,CAAC,SAAS,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK,CAAC,MAAM,OAAO,CAAC,SAAS,EAAE,MAAM,OAAO;aACzG,SAAS,CAAC,UAAU,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC,MAAM,OAAO,CAAC,UAAU,EAAE,MAAM,QAAQ,CAAC;IACpH;AAEiB,IAAA,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,0BAA0B,CAAC;;AAGpE,IAAA,MAAM,QAAQ,GAAA;AACZ,QAAA,OAAO,CAAC,MAAM,IAAI,CAAC,UAAU,CAAC,qBAAqB,CAAC,EAAE,EAAE,IAAI,EAAE;IAChE;AAEA,IAAA,MAAM,SAAS,GAAA;AACb,QAAA,OAAO,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,EAAE,WAAW,CAAU,SAAS,CAAC;IAC7D;AAEA;;;;;AAKG;AACH,IAAA,MAAM,eAAe,GAAA;AACnB,QAAA,OAAO,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,EAAE,WAAW,CAAU,eAAe,CAAC;IACnE;AAEA,IAAA,MAAM,UAAU,GAAA;AACd,QAAA,OAAO,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,EAAE,WAAW,CAAU,UAAU,CAAC;IAC9D;AAEA;;;;;;;;;;;AAWG;AACH,IAAA,MAAM,gBAAgB,GAAA;AACpB,QAAA,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,YAAY,CAAC,qBAAqB,CAAC;IAChE;;AAGA,IAAA,MAAM,MAAM,GAAA;QACV,OAAO,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE;IACrC;;AAGA,IAAA,MAAM,KAAK,GAAA;AACT,QAAA,IAAI,EAAE,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;AAAE,YAAA,MAAM,IAAI,CAAC,MAAM,EAAE;IACpD;;AAGA,IAAA,MAAM,OAAO,GAAA;AACX,QAAA,IAAI,MAAM,IAAI,CAAC,SAAS,EAAE;AAAE,YAAA,MAAM,IAAI,CAAC,MAAM,EAAE;IACjD;AAEA,IAAA,MAAM,KAAK,GAAA;QACT,OAAO,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE;IACrC;AAEA,IAAA,MAAM,SAAS,GAAA;QACb,OAAO,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE;IACzC;;;ACzGF;;AAEG;;"}
@@ -208,10 +208,10 @@ class WrCheckbox {
208
208
  this.group.blurred();
209
209
  this.touch.emit();
210
210
  }
211
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrCheckbox, deps: [], target: i0.ɵɵFactoryTarget.Component });
212
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: WrCheckbox, isStandalone: true, selector: "wr-checkbox", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, checkboxValue: { classPropertyName: "checkboxValue", publicName: "checkboxValue", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, checked: { classPropertyName: "checked", publicName: "checked", 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 }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, indeterminate: { classPropertyName: "indeterminate", publicName: "indeterminate", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { checked: "checkedChange", touch: "touch" }, host: { properties: { "class": "classes()", "attr.id": "null", "attr.data-checkbox-value": "reflectedValue()" } }, ngImport: i0, template: "<label class=\"wr-checkbox__label\" [for]=\"id()\">\n <input\n class=\"wr-checkbox__input\"\n type=\"checkbox\"\n [id]=\"id()\"\n [attr.aria-label]=\"ariaLabel()\"\n [checked]=\"isChecked()\"\n [indeterminate]=\"indeterminate()\"\n [disabled]=\"effectiveDisabled()\"\n [attr.aria-readonly]=\"effectiveReadonly() || null\"\n [attr.aria-invalid]=\"ariaInvalid()\"\n [attr.aria-describedby]=\"describedBy()\"\n (click)=\"onInputClick($event)\"\n (change)=\"onInputChange($event)\"\n (blur)=\"onInputBlur()\"\n />\n\n <span class=\"wr-checkbox__box\" aria-hidden=\"true\">\n @if (indeterminate()) {\n <svg viewBox=\"0 0 16 16\" class=\"wr-checkbox__dash\">\n <line x1=\"3.5\" y1=\"8\" x2=\"12.5\" y2=\"8\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" />\n </svg>\n } @else if (icon(); as iconName) {\n <wr-icon class=\"wr-checkbox__icon\" [name]=\"iconName\" />\n } @else {\n <svg viewBox=\"0 0 16 16\" class=\"wr-checkbox__mark\">\n <polyline\n points=\"3.5 8.5 6.5 11.5 12.5 5\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n }\n </span>\n\n <span class=\"wr-checkbox__text\">\n <ng-content />\n </span>\n</label>\n", dependencies: [{ kind: "component", type: WrIcon, selector: "wr-icon", inputs: ["name"] }], encapsulation: i0.ViewEncapsulation.None });
211
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrCheckbox, deps: [], target: i0.ɵɵFactoryTarget.Component });
212
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: WrCheckbox, isStandalone: true, selector: "wr-checkbox", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, checkboxValue: { classPropertyName: "checkboxValue", publicName: "checkboxValue", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, checked: { classPropertyName: "checked", publicName: "checked", 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 }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, indeterminate: { classPropertyName: "indeterminate", publicName: "indeterminate", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { checked: "checkedChange", touch: "touch" }, host: { properties: { "class": "classes()", "attr.id": "null", "attr.data-checkbox-value": "reflectedValue()" } }, ngImport: i0, template: "<label class=\"wr-checkbox__label\" [for]=\"id()\">\n <input\n class=\"wr-checkbox__input\"\n type=\"checkbox\"\n [id]=\"id()\"\n [attr.aria-label]=\"ariaLabel()\"\n [checked]=\"isChecked()\"\n [indeterminate]=\"indeterminate()\"\n [disabled]=\"effectiveDisabled()\"\n [attr.aria-readonly]=\"effectiveReadonly() || null\"\n [attr.aria-invalid]=\"ariaInvalid()\"\n [attr.aria-describedby]=\"describedBy()\"\n (click)=\"onInputClick($event)\"\n (change)=\"onInputChange($event)\"\n (blur)=\"onInputBlur()\"\n />\n\n <span class=\"wr-checkbox__box\" aria-hidden=\"true\">\n @if (indeterminate()) {\n <svg viewBox=\"0 0 16 16\" class=\"wr-checkbox__dash\">\n <line x1=\"3.5\" y1=\"8\" x2=\"12.5\" y2=\"8\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" />\n </svg>\n } @else if (icon(); as iconName) {\n <wr-icon class=\"wr-checkbox__icon\" [name]=\"iconName\" />\n } @else {\n <svg viewBox=\"0 0 16 16\" class=\"wr-checkbox__mark\">\n <polyline\n points=\"3.5 8.5 6.5 11.5 12.5 5\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n }\n </span>\n\n <span class=\"wr-checkbox__text\">\n <ng-content />\n </span>\n</label>\n", dependencies: [{ kind: "component", type: WrIcon, selector: "wr-icon", inputs: ["name"] }], encapsulation: i0.ViewEncapsulation.None });
213
213
  }
214
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrCheckbox, decorators: [{
214
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrCheckbox, decorators: [{
215
215
  type: Component,
216
216
  args: [{ selector: 'wr-checkbox', encapsulation: ViewEncapsulation.None, host: {
217
217
  '[class]': 'classes()',
@@ -319,8 +319,8 @@ class WrCheckboxGroup {
319
319
  blurred() {
320
320
  this.touch.emit();
321
321
  }
322
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrCheckboxGroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
323
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: WrCheckboxGroup, isStandalone: true, selector: "wr-checkbox-group", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { attributes: { "role": "group" }, properties: { "attr.aria-invalid": "fieldAria.ariaInvalid()", "attr.aria-describedby": "fieldAria.describedBy()" }, classAttribute: "wr-checkbox-group" }, providers: [
322
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrCheckboxGroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
323
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.7", type: WrCheckboxGroup, isStandalone: true, selector: "wr-checkbox-group", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { attributes: { "role": "group" }, properties: { "attr.aria-invalid": "fieldAria.ariaInvalid()", "attr.aria-describedby": "fieldAria.describedBy()" }, classAttribute: "wr-checkbox-group" }, providers: [
324
324
  {
325
325
  provide: WR_CHECKBOX_GROUP,
326
326
  // eslint-disable-next-line @angular-eslint/no-forward-ref
@@ -328,7 +328,7 @@ class WrCheckboxGroup {
328
328
  },
329
329
  ], ngImport: i0, template: '<ng-content />', isInline: true, encapsulation: i0.ViewEncapsulation.None });
330
330
  }
331
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrCheckboxGroup, decorators: [{
331
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrCheckboxGroup, decorators: [{
332
332
  type: Component,
333
333
  args: [{
334
334
  selector: 'wr-checkbox-group',
@@ -1 +1 @@
1
- {"version":3,"file":"ngwr-checkbox.mjs","sources":["../../../projects/lib/checkbox/tokens/checkbox-group.token.ts","../../../projects/lib/checkbox/checkbox.ts","../../../projects/lib/checkbox/checkbox.html","../../../projects/lib/checkbox/checkbox-group.ts","../../../projects/lib/checkbox/ngwr-checkbox.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 { InjectionToken, type Signal } from '@angular/core';\n\n/**\n * Contract a checkbox uses to talk to its parent `<wr-checkbox-group>`.\n *\n * @internal\n */\nexport interface WrCheckboxGroupContext {\n /** Is the given value currently selected? */\n isSelected(value: unknown): boolean;\n /** Toggle the given value in the group. */\n toggle(value: unknown): void;\n /**\n * A child lost focus.\n *\n * The group is the control a form binds to, so it is the group that has to\n * report touched — and a child's own `touch` output goes nowhere, since the\n * group never listens to it. Without this channel the only way to mark a\n * group touched was to CHANGE it: tabbing through every box and picking none\n * left the field pristine, so a `required` group showed no error until the\n * user toggled something, which is the one thing they had decided not to do.\n */\n blurred(): void;\n /** Whether the entire group is disabled. */\n readonly isDisabled: Signal<boolean>;\n /** Whether the entire group refuses edits while staying focusable. */\n readonly isReadonly: Signal<boolean>;\n}\n\n/**\n * Token a `<wr-checkbox>` injects to read selection state from — and\n * toggle values in — its parent `<wr-checkbox-group>` (when present).\n *\n * @internal\n */\nexport const WR_CHECKBOX_GROUP = new InjectionToken<WrCheckboxGroupContext>('WR_CHECKBOX_GROUP');\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 { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { Component, ViewEncapsulation, computed, inject, input, model, output } from '@angular/core';\nimport type { FormCheckboxControl } from '@angular/forms/signals';\n\nimport { useConfigValue } from 'ngwr/config';\nimport { useFormFieldAria } from 'ngwr/form';\nimport { WrIcon, type WrIconName } from 'ngwr/icon';\nimport { randomId } from 'ngwr/utils';\n\nimport { WR_CHECKBOX_GROUP } from './tokens';\n\n/**\n * Two-state checkbox.\n *\n * A signal-forms native control: it implements `FormCheckboxControl`, so\n * `[formField]` binds straight to its `checked` model — no\n * `ControlValueAccessor` in between. `[(checked)]` works standalone, and\n * classic `[(ngModel)]` / reactive forms keep working through Angular's bridge.\n *\n * @example\n * ```html\n * <wr-checkbox [(checked)]=\"agree\">I agree</wr-checkbox>\n * <wr-checkbox [formField]=\"form.agree\">I agree</wr-checkbox>\n * ```\n *\n * **Inside `<wr-checkbox-group>`** — the checkbox's `checkboxValue` is added to\n * or removed from the group's array, and the group is the native form control.\n * (The identity input is `checkboxValue`, not `value`, because\n * `FormCheckboxControl` reserves `value` — its form state is the boolean\n * `checked`.)\n *\n * @example\n * ```html\n * <wr-checkbox-group [formField]=\"form.features\">\n * <wr-checkbox checkboxValue=\"autosave\">Autosave</wr-checkbox>\n * <wr-checkbox checkboxValue=\"notifications\">Notifications</wr-checkbox>\n * </wr-checkbox-group>\n * ```\n *\n * @see https://ngwr.dev/reference/components/checkbox\n */\nexport type WrCheckboxSize = 'sm' | 'md' | 'lg';\n\n@Component({\n selector: 'wr-checkbox',\n templateUrl: './checkbox.html',\n encapsulation: ViewEncapsulation.None,\n host: {\n '[class]': 'classes()',\n // The `id` input belongs to the native input, not to this element. A static\n // `id=\"x\"` in a consumer's template is written to the host as a plain\n // attribute AS WELL as fed to the input, which put two elements with the\n // same id in the document and made `<label for>` resolve through\n // `getElementById` to the host — not a labelable element, so `input.labels`\n // went from 1 to 0 and `document.getElementById(id)` returned the wrong node.\n '[attr.id]': 'null',\n // The group identity, reflected so a HARNESS can read it. It is the only\n // way: `checkboxValue` is an `unknown`-typed TypeScript value that reaches\n // no attribute otherwise, and `WrCheckboxHarness.getCheckboxValue()` read\n // `value` off the inner `<input>` — which nothing writes, so it answered\n // `null` for every checkbox in every state. A harness method that answers\n // the same for a working component and a broken one is the one thing the\n // harness rules forbid outright.\n //\n // `data-`, deliberately, and NOT `value`: a leftover static `value=\"x\"` from\n // before v9 still lands on this host as a plain attribute, so reading\n // `value` here would report the identity a consumer THOUGHT they set while\n // the component used `null`. That is the exact confusion migration-v9\n // exists to end.\n '[attr.data-checkbox-value]': 'reflectedValue()',\n },\n imports: [WrIcon],\n})\nexport class WrCheckbox implements FormCheckboxControl {\n /**\n * Stable id used to associate the native input with its label. Lands on the\n * inner `<input>`; the host never keeps it.\n *\n * @default Randomly generated\n */\n readonly id = input<string>(randomId('wr-checkbox'));\n\n /**\n * This checkbox's identity when inside a `<wr-checkbox-group>` — the value\n * added to / removed from the group's array. Ignored in standalone mode.\n * (Named `checkboxValue`, not `value`, because `FormCheckboxControl` reserves\n * `value`.)\n */\n readonly checkboxValue = input<unknown>(null);\n\n /**\n * `checkboxValue` as an attribute, when it can be one.\n *\n * A primitive round-trips through the DOM and is what a group identity is in\n * practice. Anything else — an object, an array — has no honest attribute\n * form, so the attribute is ABSENT rather than `[object Object]`: a harness\n * reading it then gets `null`, which is true, instead of a string that looks\n * like data and identifies nothing.\n */\n protected readonly reflectedValue = computed(() => {\n const value = this.checkboxValue();\n // Narrowed inline rather than through a `typeof` held in a variable, which\n // TypeScript does not follow — and the linter is right to refuse it: the\n // point of this guard is that `String()` never sees an object.\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean') return String(value);\n return null;\n });\n\n /**\n * Accessible name for a checkbox used WITHOUT projected text — a selection\n * cell in a table, say. The wrapping `<label>` names the control whenever\n * content is projected; with none, the native input has no name, and an\n * `aria-label` put on the host lands on a `<wr-checkbox>` element that no\n * screen reader ever announces.\n */\n readonly ariaLabel = input<string | null>(null);\n\n /**\n * Checked state — the form value. Bound by `[formField]`, two-way via\n * `[(checked)]`, or `[(ngModel)]`. Ignored inside a `<wr-checkbox-group>`,\n * where the group's array is the source of truth.\n */\n readonly checked = model<boolean>(false);\n\n /** Emitted on blur so a bound field can mark itself touched. */\n readonly touch = output<void>();\n\n /**\n * Disable the checkbox. Bound automatically from the field's disabled state\n * when used with `[formField]`.\n *\n * @default false\n */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n /**\n * Refuse edits while staying focusable and submittable. Bound automatically\n * from the field's readonly state when used with `[formField]`.\n *\n * A native `<input type=\"checkbox\">` ignores the `readonly` attribute, so this\n * cancels the click's activation behaviour instead — which covers Space too,\n * since a checkbox turns Space into a click — and mirrors the state as\n * `aria-readonly`, which role `checkbox` supports.\n *\n * @default false\n */\n readonly readonly = input(false, { transform: coerceBooleanProperty });\n\n /**\n * Control size — shares the `--wr-control-*` contract. Unset falls back to the\n * `checkbox.size` app default from `provideWrConfig()`. @default 'md'\n */\n readonly size = input<WrCheckboxSize | null>(null);\n\n /** `size`, then the app config, then `md`. @internal */\n protected readonly resolvedSize = useConfigValue(this.size, c => c.checkbox?.size, 'md');\n\n /**\n * Optional icon name rendered inside the box when checked, in place of the\n * default checkmark. Use any registered NGWR icon.\n */\n readonly icon = input<WrIconName | null>(null);\n\n /**\n * Show the indeterminate (\"mixed\") state — a dash instead of a check. Visual\n * only and controlled: set it yourself for a parent \"select all\" whose\n * children are partly checked, and clear it on the next toggle. Takes visual\n * precedence over `checked`; the native input reports `aria-checked=\"mixed\"`.\n * A click the host does not answer still toggles `checked` underneath, and the\n * dash and the mixed state both stay until the binding turns `false`.\n *\n * @default false\n */\n readonly indeterminate = input(false, { transform: coerceBooleanProperty });\n\n private readonly group = inject(WR_CHECKBOX_GROUP, { optional: true });\n\n /** Rendered \"is checked\" — reads the group when grouped, else the `checked` model. */\n protected readonly isChecked = computed(() =>\n this.group ? this.group.isSelected(this.checkboxValue()) : this.checked()\n );\n\n /** Effective disabled — the `disabled` input wins, then the group. */\n protected readonly effectiveDisabled = computed(() => {\n if (this.disabled()) return true;\n return this.group ? this.group.isDisabled() : false;\n });\n\n /** Effective readonly — this box's own `readonly` input, or the group's. */\n protected readonly effectiveReadonly = computed(() => {\n if (this.readonly()) return true;\n return this.group ? this.group.isReadonly() : false;\n });\n\n /**\n * The surrounding `<wr-form-field>`'s error state, mirrored onto the native\n * input. Inside a `<wr-checkbox-group>` the GROUP is the bound control and\n * carries the state, so a grouped box shields itself and stays silent — nine\n * boxes each announcing the group's one error is noise, not information.\n */\n private readonly fieldAria = useFormFieldAria();\n protected readonly ariaInvalid = computed(() => (this.group ? null : this.fieldAria.ariaInvalid()));\n protected readonly describedBy = computed(() => (this.group ? null : this.fieldAria.describedBy()));\n\n protected readonly classes = computed(() => {\n const parts = ['wr-checkbox'];\n const size = this.resolvedSize();\n if (size !== 'md') parts.push(`wr-checkbox--${size}`);\n if (this.indeterminate()) parts.push('wr-checkbox--indeterminate');\n else if (this.isChecked()) parts.push('wr-checkbox--checked');\n if (this.effectiveDisabled()) parts.push('wr-checkbox--disabled');\n else if (this.effectiveReadonly()) parts.push('wr-checkbox--readonly');\n return parts.join(' ');\n });\n\n // Template handlers\n\n /**\n * Cancel the toggle while readonly. `change` never fires for a click whose\n * default was prevented, so this is the only guard the pointer and Space\n * paths need; `onInputChange` keeps its own for a synthetic `change`.\n */\n protected onInputClick(event: Event): void {\n if (this.effectiveReadonly()) event.preventDefault();\n }\n\n protected onInputChange(event: Event): void {\n const inputEl = event.target as HTMLInputElement;\n // Activating a checkbox clears its own `indeterminate` before `change` fires,\n // and the `[indeterminate]` binding never writes again while the bound value\n // stays `true` — so the box kept painting the dash while the accessibility\n // tree announced \"checked\". The input is controlled: the mixed state holds\n // until the host clears it, and a host that does clears it through the\n // binding on the next change detection.\n inputEl.indeterminate = this.indeterminate();\n\n if (this.effectiveReadonly()) {\n // A synthetic `change` cannot be prevented — put the DOM back instead.\n inputEl.checked = this.isChecked();\n return;\n }\n if (this.group) {\n this.group.toggle(this.checkboxValue());\n return;\n }\n this.checked.set(inputEl.checked);\n }\n\n protected onInputBlur(): void {\n // Inside a group the GROUP is the bound control, and its own `touch` is\n // what a form listens to; the child's output is wired to nothing there.\n if (this.group) this.group.blurred();\n this.touch.emit();\n }\n}\n","<label class=\"wr-checkbox__label\" [for]=\"id()\">\n <input\n class=\"wr-checkbox__input\"\n type=\"checkbox\"\n [id]=\"id()\"\n [attr.aria-label]=\"ariaLabel()\"\n [checked]=\"isChecked()\"\n [indeterminate]=\"indeterminate()\"\n [disabled]=\"effectiveDisabled()\"\n [attr.aria-readonly]=\"effectiveReadonly() || null\"\n [attr.aria-invalid]=\"ariaInvalid()\"\n [attr.aria-describedby]=\"describedBy()\"\n (click)=\"onInputClick($event)\"\n (change)=\"onInputChange($event)\"\n (blur)=\"onInputBlur()\"\n />\n\n <span class=\"wr-checkbox__box\" aria-hidden=\"true\">\n @if (indeterminate()) {\n <svg viewBox=\"0 0 16 16\" class=\"wr-checkbox__dash\">\n <line x1=\"3.5\" y1=\"8\" x2=\"12.5\" y2=\"8\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" />\n </svg>\n } @else if (icon(); as iconName) {\n <wr-icon class=\"wr-checkbox__icon\" [name]=\"iconName\" />\n } @else {\n <svg viewBox=\"0 0 16 16\" class=\"wr-checkbox__mark\">\n <polyline\n points=\"3.5 8.5 6.5 11.5 12.5 5\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n }\n </span>\n\n <span class=\"wr-checkbox__text\">\n <ng-content />\n </span>\n</label>\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 { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { Component, ViewEncapsulation, computed, forwardRef, input, model, output } from '@angular/core';\nimport type { FormValueControl } from '@angular/forms/signals';\n\nimport { useFormFieldAria } from 'ngwr/form';\n\nimport { WR_CHECKBOX_GROUP, type WrCheckboxGroupContext } from './tokens';\n\n/**\n * Manages a group of `<wr-checkbox>` children as a single form value\n * (an array of the checked items' `value` inputs).\n *\n * A signal-forms native control: it implements `FormValueControl<unknown[]>`,\n * so `[formField]` binds to its `value` model. `[(value)]` works standalone,\n * and classic `[(ngModel)]` / reactive forms keep working through the bridge.\n *\n * @example\n * ```html\n * <wr-checkbox-group [formField]=\"form.features\">\n * <wr-checkbox checkboxValue=\"autosave\">Autosave</wr-checkbox>\n * <wr-checkbox checkboxValue=\"notifications\">Notifications</wr-checkbox>\n * <wr-checkbox checkboxValue=\"darkmode\">Dark mode</wr-checkbox>\n * </wr-checkbox-group>\n * ```\n *\n * @see https://ngwr.dev/reference/components/checkbox\n */\n@Component({\n selector: 'wr-checkbox-group',\n template: '<ng-content />',\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'wr-checkbox-group',\n role: 'group',\n '[attr.aria-invalid]': 'fieldAria.ariaInvalid()',\n '[attr.aria-describedby]': 'fieldAria.describedBy()',\n },\n providers: [\n {\n provide: WR_CHECKBOX_GROUP,\n // eslint-disable-next-line @angular-eslint/no-forward-ref\n useExisting: forwardRef(() => WrCheckboxGroup),\n },\n ],\n})\nexport class WrCheckboxGroup implements FormValueControl<unknown[]>, WrCheckboxGroupContext {\n /**\n * Disable every child checkbox. Bound automatically from the field's\n * disabled state when used with `[formField]`.\n *\n * @default false\n */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n /**\n * Refuse edits on every child while they stay focusable and the value still\n * submits. Bound automatically from the field's readonly state when used with\n * `[formField]`.\n *\n * No `aria-readonly` on the host: role `group` does not support it (the state\n * is not global), so each child box mirrors its own instead.\n *\n * @default false\n */\n readonly readonly = input(false, { transform: coerceBooleanProperty });\n\n /** The surrounding `<wr-form-field>`'s error state. @internal */\n protected readonly fieldAria = useFormFieldAria();\n\n /** The checked items' values. Bound by `[formField]`, or two-way via `[(value)]`. */\n readonly value = model<unknown[]>([]);\n\n /** Emitted when a child toggles so a bound field can mark itself touched. */\n readonly touch = output<void>();\n\n // The current selection as a guaranteed array — a classic-forms binding can\n // write null even though the type is `unknown[]`, so normalise every read.\n private readonly selected = computed<readonly unknown[]>(() => {\n const v = this.value();\n return Array.isArray(v) ? v : [];\n });\n\n /** Effective disabled state (WrCheckboxGroupContext). */\n readonly isDisabled = computed(() => this.disabled());\n\n /** Effective readonly state (WrCheckboxGroupContext). */\n readonly isReadonly = computed(() => this.readonly());\n\n // WrCheckboxGroupContext\n\n isSelected(value: unknown): boolean {\n return this.selected().includes(value);\n }\n\n toggle(value: unknown): void {\n if (this.isDisabled() || this.isReadonly()) return;\n const current = this.selected();\n const next = current.includes(value) ? current.filter(v => v !== value) : [...current, value];\n this.value.set(next);\n this.touch.emit();\n }\n\n /** @internal A child checkbox lost focus — see {@link WrCheckboxGroupContext.blurred}. */\n blurred(): void {\n this.touch.emit();\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-checkbox.mjs","sources":["../../../projects/lib/checkbox/tokens/checkbox-group.token.ts","../../../projects/lib/checkbox/checkbox.ts","../../../projects/lib/checkbox/checkbox.html","../../../projects/lib/checkbox/checkbox-group.ts","../../../projects/lib/checkbox/ngwr-checkbox.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 { InjectionToken, type Signal } from '@angular/core';\n\n/**\n * Contract a checkbox uses to talk to its parent `<wr-checkbox-group>`.\n *\n * @internal\n */\nexport interface WrCheckboxGroupContext {\n /** Is the given value currently selected? */\n isSelected(value: unknown): boolean;\n /** Toggle the given value in the group. */\n toggle(value: unknown): void;\n /**\n * A child lost focus.\n *\n * The group is the control a form binds to, so it is the group that has to\n * report touched — and a child's own `touch` output goes nowhere, since the\n * group never listens to it. Without this channel the only way to mark a\n * group touched was to CHANGE it: tabbing through every box and picking none\n * left the field pristine, so a `required` group showed no error until the\n * user toggled something, which is the one thing they had decided not to do.\n */\n blurred(): void;\n /** Whether the entire group is disabled. */\n readonly isDisabled: Signal<boolean>;\n /** Whether the entire group refuses edits while staying focusable. */\n readonly isReadonly: Signal<boolean>;\n}\n\n/**\n * Token a `<wr-checkbox>` injects to read selection state from — and\n * toggle values in — its parent `<wr-checkbox-group>` (when present).\n *\n * @internal\n */\nexport const WR_CHECKBOX_GROUP = new InjectionToken<WrCheckboxGroupContext>('WR_CHECKBOX_GROUP');\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 { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { Component, ViewEncapsulation, computed, inject, input, model, output } from '@angular/core';\nimport type { FormCheckboxControl } from '@angular/forms/signals';\n\nimport { useConfigValue } from 'ngwr/config';\nimport { useFormFieldAria } from 'ngwr/form';\nimport { WrIcon, type WrIconName } from 'ngwr/icon';\nimport { randomId } from 'ngwr/utils';\n\nimport { WR_CHECKBOX_GROUP } from './tokens';\n\n/**\n * Two-state checkbox.\n *\n * A signal-forms native control: it implements `FormCheckboxControl`, so\n * `[formField]` binds straight to its `checked` model — no\n * `ControlValueAccessor` in between. `[(checked)]` works standalone, and\n * classic `[(ngModel)]` / reactive forms keep working through Angular's bridge.\n *\n * @example\n * ```html\n * <wr-checkbox [(checked)]=\"agree\">I agree</wr-checkbox>\n * <wr-checkbox [formField]=\"form.agree\">I agree</wr-checkbox>\n * ```\n *\n * **Inside `<wr-checkbox-group>`** — the checkbox's `checkboxValue` is added to\n * or removed from the group's array, and the group is the native form control.\n * (The identity input is `checkboxValue`, not `value`, because\n * `FormCheckboxControl` reserves `value` — its form state is the boolean\n * `checked`.)\n *\n * @example\n * ```html\n * <wr-checkbox-group [formField]=\"form.features\">\n * <wr-checkbox checkboxValue=\"autosave\">Autosave</wr-checkbox>\n * <wr-checkbox checkboxValue=\"notifications\">Notifications</wr-checkbox>\n * </wr-checkbox-group>\n * ```\n *\n * @see https://ngwr.dev/reference/components/checkbox\n */\nexport type WrCheckboxSize = 'sm' | 'md' | 'lg';\n\n@Component({\n selector: 'wr-checkbox',\n templateUrl: './checkbox.html',\n encapsulation: ViewEncapsulation.None,\n host: {\n '[class]': 'classes()',\n // The `id` input belongs to the native input, not to this element. A static\n // `id=\"x\"` in a consumer's template is written to the host as a plain\n // attribute AS WELL as fed to the input, which put two elements with the\n // same id in the document and made `<label for>` resolve through\n // `getElementById` to the host — not a labelable element, so `input.labels`\n // went from 1 to 0 and `document.getElementById(id)` returned the wrong node.\n '[attr.id]': 'null',\n // The group identity, reflected so a HARNESS can read it. It is the only\n // way: `checkboxValue` is an `unknown`-typed TypeScript value that reaches\n // no attribute otherwise, and `WrCheckboxHarness.getCheckboxValue()` read\n // `value` off the inner `<input>` — which nothing writes, so it answered\n // `null` for every checkbox in every state. A harness method that answers\n // the same for a working component and a broken one is the one thing the\n // harness rules forbid outright.\n //\n // `data-`, deliberately, and NOT `value`: a leftover static `value=\"x\"` from\n // before v9 still lands on this host as a plain attribute, so reading\n // `value` here would report the identity a consumer THOUGHT they set while\n // the component used `null`. That is the exact confusion migration-v9\n // exists to end.\n '[attr.data-checkbox-value]': 'reflectedValue()',\n },\n imports: [WrIcon],\n})\nexport class WrCheckbox implements FormCheckboxControl {\n /**\n * Stable id used to associate the native input with its label. Lands on the\n * inner `<input>`; the host never keeps it.\n *\n * @default Randomly generated\n */\n readonly id = input<string>(randomId('wr-checkbox'));\n\n /**\n * This checkbox's identity when inside a `<wr-checkbox-group>` — the value\n * added to / removed from the group's array. Ignored in standalone mode.\n * (Named `checkboxValue`, not `value`, because `FormCheckboxControl` reserves\n * `value`.)\n */\n readonly checkboxValue = input<unknown>(null);\n\n /**\n * `checkboxValue` as an attribute, when it can be one.\n *\n * A primitive round-trips through the DOM and is what a group identity is in\n * practice. Anything else — an object, an array — has no honest attribute\n * form, so the attribute is ABSENT rather than `[object Object]`: a harness\n * reading it then gets `null`, which is true, instead of a string that looks\n * like data and identifies nothing.\n */\n protected readonly reflectedValue = computed(() => {\n const value = this.checkboxValue();\n // Narrowed inline rather than through a `typeof` held in a variable, which\n // TypeScript does not follow — and the linter is right to refuse it: the\n // point of this guard is that `String()` never sees an object.\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean') return String(value);\n return null;\n });\n\n /**\n * Accessible name for a checkbox used WITHOUT projected text — a selection\n * cell in a table, say. The wrapping `<label>` names the control whenever\n * content is projected; with none, the native input has no name, and an\n * `aria-label` put on the host lands on a `<wr-checkbox>` element that no\n * screen reader ever announces.\n */\n readonly ariaLabel = input<string | null>(null);\n\n /**\n * Checked state — the form value. Bound by `[formField]`, two-way via\n * `[(checked)]`, or `[(ngModel)]`. Ignored inside a `<wr-checkbox-group>`,\n * where the group's array is the source of truth.\n */\n readonly checked = model<boolean>(false);\n\n /** Emitted on blur so a bound field can mark itself touched. */\n readonly touch = output<void>();\n\n /**\n * Disable the checkbox. Bound automatically from the field's disabled state\n * when used with `[formField]`.\n *\n * @default false\n */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n /**\n * Refuse edits while staying focusable and submittable. Bound automatically\n * from the field's readonly state when used with `[formField]`.\n *\n * A native `<input type=\"checkbox\">` ignores the `readonly` attribute, so this\n * cancels the click's activation behaviour instead — which covers Space too,\n * since a checkbox turns Space into a click — and mirrors the state as\n * `aria-readonly`, which role `checkbox` supports.\n *\n * @default false\n */\n readonly readonly = input(false, { transform: coerceBooleanProperty });\n\n /**\n * Control size — shares the `--wr-control-*` contract. Unset falls back to the\n * `checkbox.size` app default from `provideWrConfig()`. @default 'md'\n */\n readonly size = input<WrCheckboxSize | null>(null);\n\n /** `size`, then the app config, then `md`. @internal */\n protected readonly resolvedSize = useConfigValue(this.size, c => c.checkbox?.size, 'md');\n\n /**\n * Optional icon name rendered inside the box when checked, in place of the\n * default checkmark. Use any registered NGWR icon.\n */\n readonly icon = input<WrIconName | null>(null);\n\n /**\n * Show the indeterminate (\"mixed\") state — a dash instead of a check. Visual\n * only and controlled: set it yourself for a parent \"select all\" whose\n * children are partly checked, and clear it on the next toggle. Takes visual\n * precedence over `checked`; the native input reports `aria-checked=\"mixed\"`.\n * A click the host does not answer still toggles `checked` underneath, and the\n * dash and the mixed state both stay until the binding turns `false`.\n *\n * @default false\n */\n readonly indeterminate = input(false, { transform: coerceBooleanProperty });\n\n private readonly group = inject(WR_CHECKBOX_GROUP, { optional: true });\n\n /** Rendered \"is checked\" — reads the group when grouped, else the `checked` model. */\n protected readonly isChecked = computed(() =>\n this.group ? this.group.isSelected(this.checkboxValue()) : this.checked()\n );\n\n /** Effective disabled — the `disabled` input wins, then the group. */\n protected readonly effectiveDisabled = computed(() => {\n if (this.disabled()) return true;\n return this.group ? this.group.isDisabled() : false;\n });\n\n /** Effective readonly — this box's own `readonly` input, or the group's. */\n protected readonly effectiveReadonly = computed(() => {\n if (this.readonly()) return true;\n return this.group ? this.group.isReadonly() : false;\n });\n\n /**\n * The surrounding `<wr-form-field>`'s error state, mirrored onto the native\n * input. Inside a `<wr-checkbox-group>` the GROUP is the bound control and\n * carries the state, so a grouped box shields itself and stays silent — nine\n * boxes each announcing the group's one error is noise, not information.\n */\n private readonly fieldAria = useFormFieldAria();\n protected readonly ariaInvalid = computed(() => (this.group ? null : this.fieldAria.ariaInvalid()));\n protected readonly describedBy = computed(() => (this.group ? null : this.fieldAria.describedBy()));\n\n protected readonly classes = computed(() => {\n const parts = ['wr-checkbox'];\n const size = this.resolvedSize();\n if (size !== 'md') parts.push(`wr-checkbox--${size}`);\n if (this.indeterminate()) parts.push('wr-checkbox--indeterminate');\n else if (this.isChecked()) parts.push('wr-checkbox--checked');\n if (this.effectiveDisabled()) parts.push('wr-checkbox--disabled');\n else if (this.effectiveReadonly()) parts.push('wr-checkbox--readonly');\n return parts.join(' ');\n });\n\n // Template handlers\n\n /**\n * Cancel the toggle while readonly. `change` never fires for a click whose\n * default was prevented, so this is the only guard the pointer and Space\n * paths need; `onInputChange` keeps its own for a synthetic `change`.\n */\n protected onInputClick(event: Event): void {\n if (this.effectiveReadonly()) event.preventDefault();\n }\n\n protected onInputChange(event: Event): void {\n const inputEl = event.target as HTMLInputElement;\n // Activating a checkbox clears its own `indeterminate` before `change` fires,\n // and the `[indeterminate]` binding never writes again while the bound value\n // stays `true` — so the box kept painting the dash while the accessibility\n // tree announced \"checked\". The input is controlled: the mixed state holds\n // until the host clears it, and a host that does clears it through the\n // binding on the next change detection.\n inputEl.indeterminate = this.indeterminate();\n\n if (this.effectiveReadonly()) {\n // A synthetic `change` cannot be prevented — put the DOM back instead.\n inputEl.checked = this.isChecked();\n return;\n }\n if (this.group) {\n this.group.toggle(this.checkboxValue());\n return;\n }\n this.checked.set(inputEl.checked);\n }\n\n protected onInputBlur(): void {\n // Inside a group the GROUP is the bound control, and its own `touch` is\n // what a form listens to; the child's output is wired to nothing there.\n if (this.group) this.group.blurred();\n this.touch.emit();\n }\n}\n","<label class=\"wr-checkbox__label\" [for]=\"id()\">\n <input\n class=\"wr-checkbox__input\"\n type=\"checkbox\"\n [id]=\"id()\"\n [attr.aria-label]=\"ariaLabel()\"\n [checked]=\"isChecked()\"\n [indeterminate]=\"indeterminate()\"\n [disabled]=\"effectiveDisabled()\"\n [attr.aria-readonly]=\"effectiveReadonly() || null\"\n [attr.aria-invalid]=\"ariaInvalid()\"\n [attr.aria-describedby]=\"describedBy()\"\n (click)=\"onInputClick($event)\"\n (change)=\"onInputChange($event)\"\n (blur)=\"onInputBlur()\"\n />\n\n <span class=\"wr-checkbox__box\" aria-hidden=\"true\">\n @if (indeterminate()) {\n <svg viewBox=\"0 0 16 16\" class=\"wr-checkbox__dash\">\n <line x1=\"3.5\" y1=\"8\" x2=\"12.5\" y2=\"8\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" />\n </svg>\n } @else if (icon(); as iconName) {\n <wr-icon class=\"wr-checkbox__icon\" [name]=\"iconName\" />\n } @else {\n <svg viewBox=\"0 0 16 16\" class=\"wr-checkbox__mark\">\n <polyline\n points=\"3.5 8.5 6.5 11.5 12.5 5\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n }\n </span>\n\n <span class=\"wr-checkbox__text\">\n <ng-content />\n </span>\n</label>\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 { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { Component, ViewEncapsulation, computed, forwardRef, input, model, output } from '@angular/core';\nimport type { FormValueControl } from '@angular/forms/signals';\n\nimport { useFormFieldAria } from 'ngwr/form';\n\nimport { WR_CHECKBOX_GROUP, type WrCheckboxGroupContext } from './tokens';\n\n/**\n * Manages a group of `<wr-checkbox>` children as a single form value\n * (an array of the checked items' `value` inputs).\n *\n * A signal-forms native control: it implements `FormValueControl<unknown[]>`,\n * so `[formField]` binds to its `value` model. `[(value)]` works standalone,\n * and classic `[(ngModel)]` / reactive forms keep working through the bridge.\n *\n * @example\n * ```html\n * <wr-checkbox-group [formField]=\"form.features\">\n * <wr-checkbox checkboxValue=\"autosave\">Autosave</wr-checkbox>\n * <wr-checkbox checkboxValue=\"notifications\">Notifications</wr-checkbox>\n * <wr-checkbox checkboxValue=\"darkmode\">Dark mode</wr-checkbox>\n * </wr-checkbox-group>\n * ```\n *\n * @see https://ngwr.dev/reference/components/checkbox\n */\n@Component({\n selector: 'wr-checkbox-group',\n template: '<ng-content />',\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'wr-checkbox-group',\n role: 'group',\n '[attr.aria-invalid]': 'fieldAria.ariaInvalid()',\n '[attr.aria-describedby]': 'fieldAria.describedBy()',\n },\n providers: [\n {\n provide: WR_CHECKBOX_GROUP,\n // eslint-disable-next-line @angular-eslint/no-forward-ref\n useExisting: forwardRef(() => WrCheckboxGroup),\n },\n ],\n})\nexport class WrCheckboxGroup implements FormValueControl<unknown[]>, WrCheckboxGroupContext {\n /**\n * Disable every child checkbox. Bound automatically from the field's\n * disabled state when used with `[formField]`.\n *\n * @default false\n */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n /**\n * Refuse edits on every child while they stay focusable and the value still\n * submits. Bound automatically from the field's readonly state when used with\n * `[formField]`.\n *\n * No `aria-readonly` on the host: role `group` does not support it (the state\n * is not global), so each child box mirrors its own instead.\n *\n * @default false\n */\n readonly readonly = input(false, { transform: coerceBooleanProperty });\n\n /** The surrounding `<wr-form-field>`'s error state. @internal */\n protected readonly fieldAria = useFormFieldAria();\n\n /** The checked items' values. Bound by `[formField]`, or two-way via `[(value)]`. */\n readonly value = model<unknown[]>([]);\n\n /** Emitted when a child toggles so a bound field can mark itself touched. */\n readonly touch = output<void>();\n\n // The current selection as a guaranteed array — a classic-forms binding can\n // write null even though the type is `unknown[]`, so normalise every read.\n private readonly selected = computed<readonly unknown[]>(() => {\n const v = this.value();\n return Array.isArray(v) ? v : [];\n });\n\n /** Effective disabled state (WrCheckboxGroupContext). */\n readonly isDisabled = computed(() => this.disabled());\n\n /** Effective readonly state (WrCheckboxGroupContext). */\n readonly isReadonly = computed(() => this.readonly());\n\n // WrCheckboxGroupContext\n\n isSelected(value: unknown): boolean {\n return this.selected().includes(value);\n }\n\n toggle(value: unknown): void {\n if (this.isDisabled() || this.isReadonly()) return;\n const current = this.selected();\n const next = current.includes(value) ? current.filter(v => v !== value) : [...current, value];\n this.value.set(next);\n this.touch.emit();\n }\n\n /** @internal A child checkbox lost focus — see {@link WrCheckboxGroupContext.blurred}. */\n blurred(): void {\n this.touch.emit();\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ngwr-circular-text-testing.mjs","sources":["../../../projects/lib/circular-text/testing/wr-circular-text-harness.ts","../../../projects/lib/circular-text/testing/ngwr-circular-text-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 { WrCircularTextHarnessFilters } from './interfaces';\n\n/** One grapheme of the ring, placed by an inline transform the component writes itself. */\nconst CHAR = '.wr-circular-text__char';\n\n/** The wrapper the rotation is applied to, and the one element taken out of the a11y tree. */\nconst SPIN = '.wr-circular-text__spin';\n\n/** The readable copy of the string, carried once outside the ring. */\nconst SR_ONLY = '.wr-circular-text__sr-only';\n\n/**\n * The placement each character carries: a rotation about the centre, then a push outward.\n *\n * Matched off the `style` ATTRIBUTE rather than through `getCssValue`. A computed style\n * would fold in whatever the stylesheet said — and a unit test loads no stylesheet, so it\n * would answer `none` for a character the component placed perfectly well. The attribute\n * is the component's own writing, which is the only thing worth pinning.\n */\nconst PLACEMENT = /^\\s*rotate\\(\\s*(-?[\\d.]+)deg\\s*\\)\\s+(.+?)\\s*$/;\n\n/** Exactly what the element holds — untrimmed, unlike `TestElement.text()`. */\nasync function rawText(element: TestElement): Promise<string> {\n return (await element.getProperty<string | null>('textContent')) ?? '';\n}\n\n/** The `transform` declaration out of an element's own `style` attribute, or `null`. */\nfunction inlineTransform(style: string | null): string | null {\n const declaration = /(?:^|;)\\s*transform\\s*:\\s*([^;]+)/.exec(style ?? '');\n return declaration ? declaration[1].trim() : null;\n}\n\n/**\n * Test harness for `<wr-circular-text>`.\n *\n * **The ring's geometry is the component's real output, and it is exact without a\n * browser.** Each character is placed by an inline `transform` the component computes —\n * `rotate(360 / N × i deg)` and then a push outward by the orbit radius — so\n * {@link getCharacterAngles} reads the entire layout back as numbers. A broken circle\n * shows up as uneven angles, as an offset that varies per character, or as a surrogate\n * pair torn into two glyphs, and none of those need a single measured pixel.\n *\n * **The spin does not exist in the DOM, and every method that would report it is absent\n * on purpose.** The rotation is one Web Animation on the ring wrapper, advanced by a\n * compositor, and `spinDuration` reaches nothing but that animation's `duration` option\n * — so there is no `getSpinDurationSeconds()` (it would report whatever the spec's own\n * `animate` stub recorded, which is the test reading back its own fixture), no\n * `isSpinning()` and no `getRotationAngle()` (both live on `Animation.currentTime`, in an\n * API jsdom does not implement). There is no `hover()` either: hovering swaps that\n * duration through listeners on the host and changes not one attribute, so a harness\n * hover would appear to work and assert nothing. `pause()` / `resume()` are missing for\n * the same reason — the state is the private `Animation` object, never the document.\n * `respectsReducedMotion()` is the same shape once more: the component honours it by NOT\n * calling `animate`, which is a spec assertion against a stub rather than something a\n * harness can read.\n *\n * **The radius is exposed as text, not as pixels.** `--wr-circular-text-size` and\n * `--wr-circular-text-radius` are declared in the stylesheet, so a test running no\n * stylesheets reads them back empty — hence {@link getOrbitOffsets} hands over the CSS\n * each character carries verbatim instead of a `getRadiusPx()` nobody could compute, and\n * there is no `getCharacterPositions()`: every rect in a unit test is 0×0.\n *\n * **{@link isBonkers} is the one hover mode with a DOM footprint, and the INPUT sets it,\n * not the pointer.** `onHover=\"goBonkers\"` puts the modifier on the host at render time;\n * the scale it enables is a CSS `:hover` rule the harness cannot see. Reading it as \"the\n * pointer is over the ring\" is exactly backwards.\n *\n * **What is announced and what is drawn are two questions.** The string is carried once\n * in a visually-hidden span, and the ring as a whole is `aria-hidden` so a screen reader\n * hears the word rather than spelling it out — {@link getAccessibleText} is the first,\n * {@link getText} the second, and a spec that read only the second would pass on a\n * component announcing `N. G. W. R.`\n *\n * jsdom implements no Web Animations API and this component animates on mount, so a spec\n * has to supply one of the two halves before the fixture is created — either the API, or\n * a reason not to reach for it:\n *\n * ```ts\n * // Either: mount under reduced motion, where the component never animates at all.\n * // (jsdom has no matchMedia, so WrPlatform must be provided as a value.)\n * TestBed.configureTestingModule({ providers: [{ provide: WrPlatform, useValue: reducedMotion }] });\n *\n * // Or: stub the API. Save the descriptor and put it back by hand in afterEach — this\n * // is an assignment, not a spy, so it leaks into whichever file vitest runs next.\n * Reflect.set(Element.prototype, 'animate', () => ({ cancel: () => undefined }));\n * ```\n *\n * @example\n * ```ts\n * const ring = await loader.getHarness(WrCircularTextHarness.with({ text: 'NGWR' }));\n *\n * expect(await ring.getCharacters()).toEqual(['N', 'G', 'W', 'R']);\n * expect(await ring.getCharacterAngles()).toEqual([0, 90, 180, 270]);\n * expect(await ring.getText()).toBe(await ring.getAccessibleText());\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrCircularTextHarness extends ComponentHarness {\n static hostSelector = 'wr-circular-text';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrCircularTextHarnessFilters = {}): HarnessPredicate<WrCircularTextHarness> {\n return new HarnessPredicate(WrCircularTextHarness, options)\n .addOption('text', options.text, (harness, text) =>\n HarnessPredicate.stringMatches(harness.getAccessibleText(), text)\n )\n .addOption(\n 'characterCount',\n options.characterCount,\n async (harness, count) => (await harness.getCharacterCount()) === count\n );\n }\n\n private readonly chars = this.locatorForAll(CHAR);\n\n /**\n * The whole string, as the one readable copy holds it.\n *\n * All a screen reader gets, the ring itself being out of the tree — lose this span and\n * the component becomes a nameless pile of hidden letters, with no other symptom\n * anywhere in the DOM.\n *\n * Untrimmed, deliberately: a ring is usually given a separator-padded string like\n * `'HELLO * NGWR * '`, whose trailing space is a real character that takes a slot on\n * the circle. {@link getText} is meant to compare equal to this, and a trimmed read on\n * either side would forgive losing it.\n */\n async getAccessibleText(): Promise<string> {\n return rawText(await this.locatorFor(SR_ONLY)());\n }\n\n /**\n * The characters laid out around the circle, in DOM order.\n *\n * Pins the splitting rule — `Array.from(text())`, so a surrogate pair is ONE slot and\n * not two broken halves, and a space is its own slot rather than being collapsed away.\n * DOM order is the only order there is: every character is absolutely positioned, so\n * the sequence here is what the angles below are indexed by.\n */\n async getCharacters(): Promise<string[]> {\n return Promise.all((await this.chars()).map(rawText));\n }\n\n /**\n * Everything the ring draws, put back together in DOM order.\n *\n * The assertion this exists for is `getText() === getAccessibleText()`: the split has\n * to be lossless. Read from the character spans rather than from the host, because the\n * host also holds the readable copy and would report the string twice over.\n */\n async getText(): Promise<string> {\n return (await this.getCharacters()).join('');\n }\n\n /** How many slots the circle was divided into — the divisor every angle is derived from. */\n async getCharacterCount(): Promise<number> {\n return (await this.chars()).length;\n }\n\n /**\n * Where each character sits on the circle, in degrees, in DOM order.\n *\n * The component's whole geometric output, and the one thing that tells a ring from a\n * crowded arc: the angles must start at 0 and be exactly `360 / N` apart. Empty text\n * yields an empty array — no characters, no angles.\n *\n * Throws for a character carrying no rotation of its own rather than reporting `0` or\n * `NaN` for it. Both of those describe a ring collapsed onto a single point as though\n * nothing were wrong, and that is precisely the failure this method exists to catch.\n */\n async getCharacterAngles(): Promise<number[]> {\n return (await this.placements()).map(placement => placement.angle);\n }\n\n /**\n * How far each character is pushed out from the centre, as the CSS the component wrote.\n *\n * A string rather than a number, and that is the honest answer: the distance is\n * `calc(-1 * var(--wr-circular-text-radius))`, a custom property the STYLESHEET\n * declares, so there is no pixel value to resolve in a test that loads no stylesheet.\n * What matters is assertable anyway — every character must be pushed out by the SAME\n * offset, along the same axis. A per-character or axis-mixed one is the classic bug\n * that turns the ring into a diagonal line, and it survives every other check here\n * because the angles stay perfect while it happens.\n *\n * Throws on the same unplaced character {@link getCharacterAngles} does, for the same\n * reason.\n */\n async getOrbitOffsets(): Promise<string[]> {\n return (await this.placements()).map(placement => placement.offset);\n }\n\n /**\n * Whether the host carries the `wr-circular-text--bonkers` modifier.\n *\n * Set from the `onHover` INPUT being `'goBonkers'` — at render time, before anyone has\n * hovered anything — which is the one assumption a spec author makes backwards here.\n * It is also the only one of the four hover modes with any DOM footprint at all; the\n * other three exist purely as a number handed to a Web Animation.\n */\n async isBonkers(): Promise<boolean> {\n return (await this.host()).hasClass('wr-circular-text--bonkers');\n }\n\n /**\n * Whether the ring is out of the accessibility tree.\n *\n * ONE attribute answers this, and that is the contract rather than an approximation:\n * `aria-hidden` sits on the `__spin` wrapper, so the letters underneath inherit it and\n * none of them carries the attribute itself — which keeps it off the nodes the rotation\n * touches. Asserting it per character would fail on a component that is behaving.\n *\n * Answers for the wrapper even when the text is empty, and that is deliberate: the\n * wrapper is always rendered, so there is no vacuous case to guard against — a ring\n * with nothing in it is still correctly hidden or incorrectly readable.\n *\n * Assert it together with {@link getAccessibleText}: hidden letters AND no readable\n * copy is an element with no accessible name at all, which passes either check alone.\n */\n async areCharactersHiddenFromAssistiveTech(): Promise<boolean> {\n return (await (await this.locatorFor(SPIN)()).getAttribute('aria-hidden')) === 'true';\n }\n\n /** Each character's placement, parsed once out of the inline transform it carries. */\n private async placements(): Promise<{ angle: number; offset: string }[]> {\n const styles = await Promise.all((await this.chars()).map(char => char.getAttribute('style')));\n\n return styles.map((style, index) => {\n const transform = inlineTransform(style);\n const placement = transform === null ? null : PLACEMENT.exec(transform);\n\n if (!placement) {\n throw new Error(\n `WrCircularTextHarness: character ${index} is not placed — its own inline transform is ` +\n `${transform === null ? 'absent' : `\"${transform}\"`}, which carries no rotate(<n>deg). The placement ` +\n 'is the whole of what this component computes, so answering 0° here would describe a ring collapsed ' +\n 'onto a single point as though it were fine.'\n );\n }\n\n return { angle: Number.parseFloat(placement[1]), offset: placement[2] };\n });\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-circular-text-testing.mjs","sources":["../../../projects/lib/circular-text/testing/wr-circular-text-harness.ts","../../../projects/lib/circular-text/testing/ngwr-circular-text-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 { WrCircularTextHarnessFilters } from './interfaces';\n\n/** One grapheme of the ring, placed by an inline transform the component writes itself. */\nconst CHAR = '.wr-circular-text__char';\n\n/** The wrapper the rotation is applied to, and the one element taken out of the a11y tree. */\nconst SPIN = '.wr-circular-text__spin';\n\n/** The readable copy of the string, carried once outside the ring. */\nconst SR_ONLY = '.wr-circular-text__sr-only';\n\n/**\n * The placement each character carries: a rotation about the centre, then a push outward.\n *\n * Matched off the `style` ATTRIBUTE rather than through `getCssValue`. A computed style\n * would fold in whatever the stylesheet said — and a unit test loads no stylesheet, so it\n * would answer `none` for a character the component placed perfectly well. The attribute\n * is the component's own writing, which is the only thing worth pinning.\n */\nconst PLACEMENT = /^\\s*rotate\\(\\s*(-?[\\d.]+)deg\\s*\\)\\s+(.+?)\\s*$/;\n\n/** Exactly what the element holds — untrimmed, unlike `TestElement.text()`. */\nasync function rawText(element: TestElement): Promise<string> {\n return (await element.getProperty<string | null>('textContent')) ?? '';\n}\n\n/** The `transform` declaration out of an element's own `style` attribute, or `null`. */\nfunction inlineTransform(style: string | null): string | null {\n const declaration = /(?:^|;)\\s*transform\\s*:\\s*([^;]+)/.exec(style ?? '');\n return declaration ? declaration[1].trim() : null;\n}\n\n/**\n * Test harness for `<wr-circular-text>`.\n *\n * **The ring's geometry is the component's real output, and it is exact without a\n * browser.** Each character is placed by an inline `transform` the component computes —\n * `rotate(360 / N × i deg)` and then a push outward by the orbit radius — so\n * {@link getCharacterAngles} reads the entire layout back as numbers. A broken circle\n * shows up as uneven angles, as an offset that varies per character, or as a surrogate\n * pair torn into two glyphs, and none of those need a single measured pixel.\n *\n * **The spin does not exist in the DOM, and every method that would report it is absent\n * on purpose.** The rotation is one Web Animation on the ring wrapper, advanced by a\n * compositor, and `spinDuration` reaches nothing but that animation's `duration` option\n * — so there is no `getSpinDurationSeconds()` (it would report whatever the spec's own\n * `animate` stub recorded, which is the test reading back its own fixture), no\n * `isSpinning()` and no `getRotationAngle()` (both live on `Animation.currentTime`, in an\n * API jsdom does not implement). There is no `hover()` either: hovering swaps that\n * duration through listeners on the host and changes not one attribute, so a harness\n * hover would appear to work and assert nothing. `pause()` / `resume()` are missing for\n * the same reason — the state is the private `Animation` object, never the document.\n * `respectsReducedMotion()` is the same shape once more: the component honours it by NOT\n * calling `animate`, which is a spec assertion against a stub rather than something a\n * harness can read.\n *\n * **The radius is exposed as text, not as pixels.** `--wr-circular-text-size` and\n * `--wr-circular-text-radius` are declared in the stylesheet, so a test running no\n * stylesheets reads them back empty — hence {@link getOrbitOffsets} hands over the CSS\n * each character carries verbatim instead of a `getRadiusPx()` nobody could compute, and\n * there is no `getCharacterPositions()`: every rect in a unit test is 0×0.\n *\n * **{@link isBonkers} is the one hover mode with a DOM footprint, and the INPUT sets it,\n * not the pointer.** `onHover=\"goBonkers\"` puts the modifier on the host at render time;\n * the scale it enables is a CSS `:hover` rule the harness cannot see. Reading it as \"the\n * pointer is over the ring\" is exactly backwards.\n *\n * **What is announced and what is drawn are two questions.** The string is carried once\n * in a visually-hidden span, and the ring as a whole is `aria-hidden` so a screen reader\n * hears the word rather than spelling it out — {@link getAccessibleText} is the first,\n * {@link getText} the second, and a spec that read only the second would pass on a\n * component announcing `N. G. W. R.`\n *\n * jsdom implements no Web Animations API and this component animates on mount, so a spec\n * has to supply one of the two halves before the fixture is created — either the API, or\n * a reason not to reach for it:\n *\n * ```ts\n * // Either: mount under reduced motion, where the component never animates at all.\n * // (jsdom has no matchMedia, so WrPlatform must be provided as a value.)\n * TestBed.configureTestingModule({ providers: [{ provide: WrPlatform, useValue: reducedMotion }] });\n *\n * // Or: stub the API. Save the descriptor and put it back by hand in afterEach — this\n * // is an assignment, not a spy, so it leaks into whichever file vitest runs next.\n * Reflect.set(Element.prototype, 'animate', () => ({ cancel: () => undefined }));\n * ```\n *\n * @example\n * ```ts\n * const ring = await loader.getHarness(WrCircularTextHarness.with({ text: 'NGWR' }));\n *\n * expect(await ring.getCharacters()).toEqual(['N', 'G', 'W', 'R']);\n * expect(await ring.getCharacterAngles()).toEqual([0, 90, 180, 270]);\n * expect(await ring.getText()).toBe(await ring.getAccessibleText());\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrCircularTextHarness extends ComponentHarness {\n static hostSelector = 'wr-circular-text';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrCircularTextHarnessFilters = {}): HarnessPredicate<WrCircularTextHarness> {\n return new HarnessPredicate(WrCircularTextHarness, options)\n .addOption('text', options.text, (harness, text) =>\n HarnessPredicate.stringMatches(harness.getAccessibleText(), text)\n )\n .addOption(\n 'characterCount',\n options.characterCount,\n async (harness, count) => (await harness.getCharacterCount()) === count\n );\n }\n\n private readonly chars = this.locatorForAll(CHAR);\n\n /**\n * The whole string, as the one readable copy holds it.\n *\n * All a screen reader gets, the ring itself being out of the tree — lose this span and\n * the component becomes a nameless pile of hidden letters, with no other symptom\n * anywhere in the DOM.\n *\n * Untrimmed, deliberately: a ring is usually given a separator-padded string like\n * `'HELLO * NGWR * '`, whose trailing space is a real character that takes a slot on\n * the circle. {@link getText} is meant to compare equal to this, and a trimmed read on\n * either side would forgive losing it.\n */\n async getAccessibleText(): Promise<string> {\n return rawText(await this.locatorFor(SR_ONLY)());\n }\n\n /**\n * The characters laid out around the circle, in DOM order.\n *\n * Pins the splitting rule — `Array.from(text())`, so a surrogate pair is ONE slot and\n * not two broken halves, and a space is its own slot rather than being collapsed away.\n * DOM order is the only order there is: every character is absolutely positioned, so\n * the sequence here is what the angles below are indexed by.\n */\n async getCharacters(): Promise<string[]> {\n return Promise.all((await this.chars()).map(rawText));\n }\n\n /**\n * Everything the ring draws, put back together in DOM order.\n *\n * The assertion this exists for is `getText() === getAccessibleText()`: the split has\n * to be lossless. Read from the character spans rather than from the host, because the\n * host also holds the readable copy and would report the string twice over.\n */\n async getText(): Promise<string> {\n return (await this.getCharacters()).join('');\n }\n\n /** How many slots the circle was divided into — the divisor every angle is derived from. */\n async getCharacterCount(): Promise<number> {\n return (await this.chars()).length;\n }\n\n /**\n * Where each character sits on the circle, in degrees, in DOM order.\n *\n * The component's whole geometric output, and the one thing that tells a ring from a\n * crowded arc: the angles must start at 0 and be exactly `360 / N` apart. Empty text\n * yields an empty array — no characters, no angles.\n *\n * Throws for a character carrying no rotation of its own rather than reporting `0` or\n * `NaN` for it. Both of those describe a ring collapsed onto a single point as though\n * nothing were wrong, and that is precisely the failure this method exists to catch.\n */\n async getCharacterAngles(): Promise<number[]> {\n return (await this.placements()).map(placement => placement.angle);\n }\n\n /**\n * How far each character is pushed out from the centre, as the CSS the component wrote.\n *\n * A string rather than a number, and that is the honest answer: the distance is\n * `calc(-1 * var(--wr-circular-text-radius))`, a custom property the STYLESHEET\n * declares, so there is no pixel value to resolve in a test that loads no stylesheet.\n * What matters is assertable anyway — every character must be pushed out by the SAME\n * offset, along the same axis. A per-character or axis-mixed one is the classic bug\n * that turns the ring into a diagonal line, and it survives every other check here\n * because the angles stay perfect while it happens.\n *\n * Throws on the same unplaced character {@link getCharacterAngles} does, for the same\n * reason.\n */\n async getOrbitOffsets(): Promise<string[]> {\n return (await this.placements()).map(placement => placement.offset);\n }\n\n /**\n * Whether the host carries the `wr-circular-text--bonkers` modifier.\n *\n * Set from the `onHover` INPUT being `'goBonkers'` — at render time, before anyone has\n * hovered anything — which is the one assumption a spec author makes backwards here.\n * It is also the only one of the four hover modes with any DOM footprint at all; the\n * other three exist purely as a number handed to a Web Animation.\n */\n async isBonkers(): Promise<boolean> {\n return (await this.host()).hasClass('wr-circular-text--bonkers');\n }\n\n /**\n * Whether the ring is out of the accessibility tree.\n *\n * ONE attribute answers this, and that is the contract rather than an approximation:\n * `aria-hidden` sits on the `__spin` wrapper, so the letters underneath inherit it and\n * none of them carries the attribute itself — which keeps it off the nodes the rotation\n * touches. Asserting it per character would fail on a component that is behaving.\n *\n * Answers for the wrapper even when the text is empty, and that is deliberate: the\n * wrapper is always rendered, so there is no vacuous case to guard against — a ring\n * with nothing in it is still correctly hidden or incorrectly readable.\n *\n * Assert it together with {@link getAccessibleText}: hidden letters AND no readable\n * copy is an element with no accessible name at all, which passes either check alone.\n */\n async areCharactersHiddenFromAssistiveTech(): Promise<boolean> {\n return (await (await this.locatorFor(SPIN)()).getAttribute('aria-hidden')) === 'true';\n }\n\n /** Each character's placement, parsed once out of the inline transform it carries. */\n private async placements(): Promise<{ angle: number; offset: string }[]> {\n const styles = await Promise.all((await this.chars()).map(char => char.getAttribute('style')));\n\n return styles.map((style, index) => {\n const transform = inlineTransform(style);\n const placement = transform === null ? null : PLACEMENT.exec(transform);\n\n if (!placement) {\n throw new Error(\n `WrCircularTextHarness: character ${index} is not placed — its own inline transform is ` +\n `${transform === null ? 'absent' : `\"${transform}\"`}, which carries no rotate(<n>deg). The placement ` +\n 'is the whole of what this component computes, so answering 0° here would describe a ring collapsed ' +\n 'onto a single point as though it were fine.'\n );\n }\n\n return { angle: Number.parseFloat(placement[1]), offset: placement[2] };\n });\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -169,10 +169,10 @@ class WrCircularText {
169
169
  this.rotation = this.spinEl().nativeElement.animate([{ transform: 'rotate(0deg)' }, { transform: 'rotate(360deg)' }], { duration: newDurMs, iterations: Infinity, easing: 'linear' });
170
170
  this.rotation.currentTime = ratio * newDurMs;
171
171
  }
172
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrCircularText, deps: [], target: i0.ɵɵFactoryTarget.Component });
173
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: WrCircularText, isStandalone: true, selector: "wr-circular-text", inputs: { text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: true, transformFunction: null }, spinDuration: { classPropertyName: "spinDuration", publicName: "spinDuration", isSignal: true, isRequired: false, transformFunction: null }, onHover: { classPropertyName: "onHover", publicName: "onHover", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.wr-circular-text--bonkers": "onHover() === 'goBonkers'" }, classAttribute: "wr-circular-text" }, viewQueries: [{ propertyName: "spinEl", first: true, predicate: ["spin"], descendants: true, isSignal: true }], ngImport: i0, template: "<!--\n The readable text, once: the ring below is per-character spans, which a screen\n reader may read out one letter at a time. Same shape as `wr-blur-text` and\n `wr-decrypt-text` \u2014 the string is carried here and the pieces are taken out of\n the tree with one `aria-hidden` on the wrapper rather than N on the chars, so\n the attribute stays off the nodes the rotation touches. It sits OUTSIDE\n `__spin`, or it would be hidden with the chars and would spin with them.\n-->\n<span class=\"wr-circular-text__sr-only\">{{ text() }}</span>\n<span class=\"wr-circular-text__spin\" aria-hidden=\"true\" #spin>\n @for (c of chars(); track $index) {\n <span class=\"wr-circular-text__char\" [style.transform]=\"c.transform\">{{ c.ch }}</span>\n }\n</span>\n", styles: [".wr-circular-text{--wr-circular-text-size: 12rem;--wr-circular-text-radius: calc(var(--wr-circular-text-size) / 2);position:relative;display:inline-block;width:var(--wr-circular-text-size);height:var(--wr-circular-text-size);border-radius:50%;font-weight:700;text-align:center;-webkit-user-select:none;user-select:none;transition:transform .6s var(--wr-ease-spring)}.wr-circular-text__sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}.wr-circular-text__spin{position:absolute;inset:0;will-change:transform}.wr-circular-text__char{position:absolute;top:50%;left:50%;display:inline-block;margin-left:-.5em;margin-top:-.5em;line-height:1}.wr-circular-text--bonkers:hover{transform:scale(.8)}\n"], encapsulation: i0.ViewEncapsulation.None });
172
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrCircularText, deps: [], target: i0.ɵɵFactoryTarget.Component });
173
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: WrCircularText, isStandalone: true, selector: "wr-circular-text", inputs: { text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: true, transformFunction: null }, spinDuration: { classPropertyName: "spinDuration", publicName: "spinDuration", isSignal: true, isRequired: false, transformFunction: null }, onHover: { classPropertyName: "onHover", publicName: "onHover", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.wr-circular-text--bonkers": "onHover() === 'goBonkers'" }, classAttribute: "wr-circular-text" }, viewQueries: [{ propertyName: "spinEl", first: true, predicate: ["spin"], descendants: true, isSignal: true }], ngImport: i0, template: "<!--\n The readable text, once: the ring below is per-character spans, which a screen\n reader may read out one letter at a time. Same shape as `wr-blur-text` and\n `wr-decrypt-text` \u2014 the string is carried here and the pieces are taken out of\n the tree with one `aria-hidden` on the wrapper rather than N on the chars, so\n the attribute stays off the nodes the rotation touches. It sits OUTSIDE\n `__spin`, or it would be hidden with the chars and would spin with them.\n-->\n<span class=\"wr-circular-text__sr-only\">{{ text() }}</span>\n<span class=\"wr-circular-text__spin\" aria-hidden=\"true\" #spin>\n @for (c of chars(); track $index) {\n <span class=\"wr-circular-text__char\" [style.transform]=\"c.transform\">{{ c.ch }}</span>\n }\n</span>\n", styles: [".wr-circular-text{--wr-circular-text-size: 12rem;--wr-circular-text-radius: calc(var(--wr-circular-text-size) / 2);position:relative;display:inline-block;width:var(--wr-circular-text-size);height:var(--wr-circular-text-size);border-radius:50%;font-weight:700;text-align:center;-webkit-user-select:none;user-select:none;transition:transform .6s var(--wr-ease-spring)}.wr-circular-text__sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}.wr-circular-text__spin{position:absolute;inset:0;will-change:transform}.wr-circular-text__char{position:absolute;top:50%;left:50%;display:inline-block;margin-left:-.5em;margin-top:-.5em;line-height:1}.wr-circular-text--bonkers:hover{transform:scale(.8)}\n"], encapsulation: i0.ViewEncapsulation.None });
174
174
  }
175
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrCircularText, decorators: [{
175
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrCircularText, decorators: [{
176
176
  type: Component,
177
177
  args: [{ selector: 'wr-circular-text', encapsulation: ViewEncapsulation.None, host: {
178
178
  class: 'wr-circular-text',