ngwr 14.7.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 (482) 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/bar-chart/styles/_index.scss +1 -0
  7. package/button/styles/_index.scss +6 -0
  8. package/calendar-heatmap/styles/_index.scss +1 -0
  9. package/cascader/styles/_rules.scss +87 -15
  10. package/checkbox/styles/_index.scss +4 -0
  11. package/command-palette/styles/_index.scss +1 -1
  12. package/date-picker/styles/_index.scss +30 -0
  13. package/density/styles/_index.scss +4 -2
  14. package/divider/styles/_index.scss +2 -0
  15. package/donut-chart/styles/_index.scss +10 -0
  16. package/dropdown/styles/_index.scss +67 -5
  17. package/editor/styles/_index.scss +441 -0
  18. package/event-calendar/styles/_index.scss +209 -35
  19. package/fesm2022/ngwr-action-sheet-testing.mjs.map +1 -1
  20. package/fesm2022/ngwr-action-sheet.mjs +3 -3
  21. package/fesm2022/ngwr-action-sheet.mjs.map +1 -1
  22. package/fesm2022/ngwr-affix.mjs +3 -3
  23. package/fesm2022/ngwr-affix.mjs.map +1 -1
  24. package/fesm2022/ngwr-alert.mjs +3 -3
  25. package/fesm2022/ngwr-alert.mjs.map +1 -1
  26. package/fesm2022/ngwr-anchor.mjs +3 -3
  27. package/fesm2022/ngwr-anchor.mjs.map +1 -1
  28. package/fesm2022/ngwr-aurora.mjs +3 -3
  29. package/fesm2022/ngwr-aurora.mjs.map +1 -1
  30. package/fesm2022/ngwr-avatar.mjs +3 -3
  31. package/fesm2022/ngwr-avatar.mjs.map +1 -1
  32. package/fesm2022/ngwr-back-top.mjs +3 -3
  33. package/fesm2022/ngwr-back-top.mjs.map +1 -1
  34. package/fesm2022/ngwr-badge.mjs +28 -13
  35. package/fesm2022/ngwr-badge.mjs.map +1 -1
  36. package/fesm2022/ngwr-bar-chart-testing.mjs.map +1 -1
  37. package/fesm2022/ngwr-bar-chart.mjs +31 -6
  38. package/fesm2022/ngwr-bar-chart.mjs.map +1 -1
  39. package/fesm2022/ngwr-blur-text-testing.mjs.map +1 -1
  40. package/fesm2022/ngwr-blur-text.mjs +3 -3
  41. package/fesm2022/ngwr-blur-text.mjs.map +1 -1
  42. package/fesm2022/ngwr-border-glow-testing.mjs.map +1 -1
  43. package/fesm2022/ngwr-border-glow.mjs +3 -3
  44. package/fesm2022/ngwr-border-glow.mjs.map +1 -1
  45. package/fesm2022/ngwr-breadcrumbs.mjs +6 -6
  46. package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
  47. package/fesm2022/ngwr-burger.mjs +3 -3
  48. package/fesm2022/ngwr-burger.mjs.map +1 -1
  49. package/fesm2022/ngwr-button-testing.mjs.map +1 -1
  50. package/fesm2022/ngwr-button.mjs +6 -6
  51. package/fesm2022/ngwr-button.mjs.map +1 -1
  52. package/fesm2022/ngwr-calendar-heatmap-testing.mjs.map +1 -1
  53. package/fesm2022/ngwr-calendar-heatmap.mjs +61 -6
  54. package/fesm2022/ngwr-calendar-heatmap.mjs.map +1 -1
  55. package/fesm2022/ngwr-calendar-testing.mjs.map +1 -1
  56. package/fesm2022/ngwr-calendar.mjs +3 -3
  57. package/fesm2022/ngwr-calendar.mjs.map +1 -1
  58. package/fesm2022/ngwr-card.mjs +9 -9
  59. package/fesm2022/ngwr-card.mjs.map +1 -1
  60. package/fesm2022/ngwr-carousel-testing.mjs.map +1 -1
  61. package/fesm2022/ngwr-carousel.mjs +6 -6
  62. package/fesm2022/ngwr-carousel.mjs.map +1 -1
  63. package/fesm2022/ngwr-cascader-testing.mjs.map +1 -1
  64. package/fesm2022/ngwr-cascader.mjs +4 -4
  65. package/fesm2022/ngwr-cascader.mjs.map +1 -1
  66. package/fesm2022/ngwr-checkbox-testing.mjs.map +1 -1
  67. package/fesm2022/ngwr-checkbox.mjs +18 -8
  68. package/fesm2022/ngwr-checkbox.mjs.map +1 -1
  69. package/fesm2022/ngwr-circular-text-testing.mjs.map +1 -1
  70. package/fesm2022/ngwr-circular-text.mjs +3 -3
  71. package/fesm2022/ngwr-circular-text.mjs.map +1 -1
  72. package/fesm2022/ngwr-click-spark.mjs +3 -3
  73. package/fesm2022/ngwr-click-spark.mjs.map +1 -1
  74. package/fesm2022/ngwr-clipboard.mjs +3 -3
  75. package/fesm2022/ngwr-clipboard.mjs.map +1 -1
  76. package/fesm2022/ngwr-collapse-testing.mjs.map +1 -1
  77. package/fesm2022/ngwr-collapse.mjs +9 -9
  78. package/fesm2022/ngwr-collapse.mjs.map +1 -1
  79. package/fesm2022/ngwr-color-picker-testing.mjs.map +1 -1
  80. package/fesm2022/ngwr-color-picker.mjs +6 -6
  81. package/fesm2022/ngwr-color-picker.mjs.map +1 -1
  82. package/fesm2022/ngwr-command-palette-testing.mjs.map +1 -1
  83. package/fesm2022/ngwr-command-palette.mjs +3 -3
  84. package/fesm2022/ngwr-command-palette.mjs.map +1 -1
  85. package/fesm2022/ngwr-compare.mjs +3 -3
  86. package/fesm2022/ngwr-compare.mjs.map +1 -1
  87. package/fesm2022/ngwr-confetti.mjs +3 -3
  88. package/fesm2022/ngwr-confetti.mjs.map +1 -1
  89. package/fesm2022/ngwr-config.mjs.map +1 -1
  90. package/fesm2022/ngwr-context-menu-testing.mjs.map +1 -1
  91. package/fesm2022/ngwr-context-menu.mjs +12 -12
  92. package/fesm2022/ngwr-context-menu.mjs.map +1 -1
  93. package/fesm2022/ngwr-cookie.mjs +3 -3
  94. package/fesm2022/ngwr-cookie.mjs.map +1 -1
  95. package/fesm2022/ngwr-counter.mjs +6 -6
  96. package/fesm2022/ngwr-counter.mjs.map +1 -1
  97. package/fesm2022/ngwr-date-adapters-fns.mjs +3 -3
  98. package/fesm2022/ngwr-date-adapters-fns.mjs.map +1 -1
  99. package/fesm2022/ngwr-date-adapters-luxon.mjs +3 -3
  100. package/fesm2022/ngwr-date-adapters-luxon.mjs.map +1 -1
  101. package/fesm2022/ngwr-date-picker-testing.mjs.map +1 -1
  102. package/fesm2022/ngwr-date-picker.mjs +721 -62
  103. package/fesm2022/ngwr-date-picker.mjs.map +1 -1
  104. package/fesm2022/ngwr-date.mjs +3 -3
  105. package/fesm2022/ngwr-date.mjs.map +1 -1
  106. package/fesm2022/ngwr-decrypt-text-testing.mjs.map +1 -1
  107. package/fesm2022/ngwr-decrypt-text.mjs +3 -3
  108. package/fesm2022/ngwr-decrypt-text.mjs.map +1 -1
  109. package/fesm2022/ngwr-density.mjs +6 -6
  110. package/fesm2022/ngwr-density.mjs.map +1 -1
  111. package/fesm2022/ngwr-descriptions.mjs +6 -6
  112. package/fesm2022/ngwr-descriptions.mjs.map +1 -1
  113. package/fesm2022/ngwr-dialog-testing.mjs.map +1 -1
  114. package/fesm2022/ngwr-dialog.mjs +15 -15
  115. package/fesm2022/ngwr-dialog.mjs.map +1 -1
  116. package/fesm2022/ngwr-directives.mjs +12 -12
  117. package/fesm2022/ngwr-directives.mjs.map +1 -1
  118. package/fesm2022/ngwr-divider.mjs +3 -3
  119. package/fesm2022/ngwr-divider.mjs.map +1 -1
  120. package/fesm2022/ngwr-donut-chart-testing.mjs.map +1 -1
  121. package/fesm2022/ngwr-donut-chart.mjs +48 -6
  122. package/fesm2022/ngwr-donut-chart.mjs.map +1 -1
  123. package/fesm2022/ngwr-drag-drop.mjs +6 -6
  124. package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
  125. package/fesm2022/ngwr-drawer-testing.mjs.map +1 -1
  126. package/fesm2022/ngwr-drawer.mjs +18 -18
  127. package/fesm2022/ngwr-drawer.mjs.map +1 -1
  128. package/fesm2022/ngwr-dropdown-testing.mjs.map +1 -1
  129. package/fesm2022/ngwr-dropdown.mjs +174 -25
  130. package/fesm2022/ngwr-dropdown.mjs.map +1 -1
  131. package/fesm2022/ngwr-editor-testing.mjs +568 -0
  132. package/fesm2022/ngwr-editor-testing.mjs.map +1 -0
  133. package/fesm2022/ngwr-editor.mjs +2601 -0
  134. package/fesm2022/ngwr-editor.mjs.map +1 -0
  135. package/fesm2022/ngwr-empty.mjs +3 -3
  136. package/fesm2022/ngwr-empty.mjs.map +1 -1
  137. package/fesm2022/ngwr-event-calendar-testing.mjs.map +1 -1
  138. package/fesm2022/ngwr-event-calendar.mjs +14 -7
  139. package/fesm2022/ngwr-event-calendar.mjs.map +1 -1
  140. package/fesm2022/ngwr-falling-text-testing.mjs.map +1 -1
  141. package/fesm2022/ngwr-falling-text.mjs +3 -3
  142. package/fesm2022/ngwr-falling-text.mjs.map +1 -1
  143. package/fesm2022/ngwr-file-upload-testing.mjs.map +1 -1
  144. package/fesm2022/ngwr-file-upload.mjs +3 -3
  145. package/fesm2022/ngwr-file-upload.mjs.map +1 -1
  146. package/fesm2022/ngwr-form-testing.mjs.map +1 -1
  147. package/fesm2022/ngwr-form.mjs +61 -10
  148. package/fesm2022/ngwr-form.mjs.map +1 -1
  149. package/fesm2022/ngwr-fuzzy-text-testing.mjs.map +1 -1
  150. package/fesm2022/ngwr-fuzzy-text.mjs +3 -3
  151. package/fesm2022/ngwr-fuzzy-text.mjs.map +1 -1
  152. package/fesm2022/ngwr-gauge-testing.mjs.map +1 -1
  153. package/fesm2022/ngwr-gauge.mjs +35 -6
  154. package/fesm2022/ngwr-gauge.mjs.map +1 -1
  155. package/fesm2022/ngwr-glitch-text-testing.mjs.map +1 -1
  156. package/fesm2022/ngwr-glitch-text.mjs +3 -3
  157. package/fesm2022/ngwr-glitch-text.mjs.map +1 -1
  158. package/fesm2022/ngwr-gradient-text-testing.mjs.map +1 -1
  159. package/fesm2022/ngwr-gradient-text.mjs +3 -3
  160. package/fesm2022/ngwr-gradient-text.mjs.map +1 -1
  161. package/fesm2022/ngwr-graph-testing.mjs.map +1 -1
  162. package/fesm2022/ngwr-graph.mjs +6 -6
  163. package/fesm2022/ngwr-graph.mjs.map +1 -1
  164. package/fesm2022/ngwr-hotkey.mjs +6 -6
  165. package/fesm2022/ngwr-hotkey.mjs.map +1 -1
  166. package/fesm2022/ngwr-i18n-ar.mjs +31 -0
  167. package/fesm2022/ngwr-i18n-ar.mjs.map +1 -1
  168. package/fesm2022/ngwr-i18n-cs.mjs +31 -0
  169. package/fesm2022/ngwr-i18n-cs.mjs.map +1 -1
  170. package/fesm2022/ngwr-i18n-de.mjs +31 -0
  171. package/fesm2022/ngwr-i18n-de.mjs.map +1 -1
  172. package/fesm2022/ngwr-i18n-en.mjs +39 -0
  173. package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
  174. package/fesm2022/ngwr-i18n-es.mjs +31 -0
  175. package/fesm2022/ngwr-i18n-es.mjs.map +1 -1
  176. package/fesm2022/ngwr-i18n-fr.mjs +31 -0
  177. package/fesm2022/ngwr-i18n-fr.mjs.map +1 -1
  178. package/fesm2022/ngwr-i18n-he.mjs +31 -0
  179. package/fesm2022/ngwr-i18n-he.mjs.map +1 -1
  180. package/fesm2022/ngwr-i18n-hi.mjs +31 -0
  181. package/fesm2022/ngwr-i18n-hi.mjs.map +1 -1
  182. package/fesm2022/ngwr-i18n-id.mjs +31 -0
  183. package/fesm2022/ngwr-i18n-id.mjs.map +1 -1
  184. package/fesm2022/ngwr-i18n-it.mjs +31 -0
  185. package/fesm2022/ngwr-i18n-it.mjs.map +1 -1
  186. package/fesm2022/ngwr-i18n-ja.mjs +31 -0
  187. package/fesm2022/ngwr-i18n-ja.mjs.map +1 -1
  188. package/fesm2022/ngwr-i18n-ko.mjs +31 -0
  189. package/fesm2022/ngwr-i18n-ko.mjs.map +1 -1
  190. package/fesm2022/ngwr-i18n-nl.mjs +31 -0
  191. package/fesm2022/ngwr-i18n-nl.mjs.map +1 -1
  192. package/fesm2022/ngwr-i18n-pl.mjs +31 -0
  193. package/fesm2022/ngwr-i18n-pl.mjs.map +1 -1
  194. package/fesm2022/ngwr-i18n-pt.mjs +31 -0
  195. package/fesm2022/ngwr-i18n-pt.mjs.map +1 -1
  196. package/fesm2022/ngwr-i18n-ru.mjs +31 -0
  197. package/fesm2022/ngwr-i18n-ru.mjs.map +1 -1
  198. package/fesm2022/ngwr-i18n-sv.mjs +31 -0
  199. package/fesm2022/ngwr-i18n-sv.mjs.map +1 -1
  200. package/fesm2022/ngwr-i18n-tr.mjs +31 -0
  201. package/fesm2022/ngwr-i18n-tr.mjs.map +1 -1
  202. package/fesm2022/ngwr-i18n-uk.mjs +31 -0
  203. package/fesm2022/ngwr-i18n-uk.mjs.map +1 -1
  204. package/fesm2022/ngwr-i18n-vi.mjs +31 -0
  205. package/fesm2022/ngwr-i18n-vi.mjs.map +1 -1
  206. package/fesm2022/ngwr-i18n-zh-TW.mjs +31 -0
  207. package/fesm2022/ngwr-i18n-zh-TW.mjs.map +1 -1
  208. package/fesm2022/ngwr-i18n-zh.mjs +31 -0
  209. package/fesm2022/ngwr-i18n-zh.mjs.map +1 -1
  210. package/fesm2022/ngwr-i18n.mjs +9 -9
  211. package/fesm2022/ngwr-i18n.mjs.map +1 -1
  212. package/fesm2022/ngwr-icon-adapters-feather.mjs.map +1 -1
  213. package/fesm2022/ngwr-icon-adapters-lucide.mjs.map +1 -1
  214. package/fesm2022/ngwr-icon.mjs +6 -6
  215. package/fesm2022/ngwr-icon.mjs.map +1 -1
  216. package/fesm2022/ngwr-image-cropper-testing.mjs.map +1 -1
  217. package/fesm2022/ngwr-image-cropper.mjs +3 -3
  218. package/fesm2022/ngwr-image-cropper.mjs.map +1 -1
  219. package/fesm2022/ngwr-input-number-testing.mjs.map +1 -1
  220. package/fesm2022/ngwr-input-number.mjs +15 -3
  221. package/fesm2022/ngwr-input-number.mjs.map +1 -1
  222. package/fesm2022/ngwr-input-otp-testing.mjs.map +1 -1
  223. package/fesm2022/ngwr-input-otp.mjs +3 -3
  224. package/fesm2022/ngwr-input-otp.mjs.map +1 -1
  225. package/fesm2022/ngwr-input-testing.mjs.map +1 -1
  226. package/fesm2022/ngwr-input.mjs +15 -15
  227. package/fesm2022/ngwr-input.mjs.map +1 -1
  228. package/fesm2022/ngwr-keyboard.mjs +3 -3
  229. package/fesm2022/ngwr-keyboard.mjs.map +1 -1
  230. package/fesm2022/ngwr-knob-testing.mjs.map +1 -1
  231. package/fesm2022/ngwr-knob.mjs +3 -3
  232. package/fesm2022/ngwr-knob.mjs.map +1 -1
  233. package/fesm2022/ngwr-layout.mjs +15 -15
  234. package/fesm2022/ngwr-layout.mjs.map +1 -1
  235. package/fesm2022/ngwr-lightbox-testing.mjs.map +1 -1
  236. package/fesm2022/ngwr-lightbox.mjs +3 -3
  237. package/fesm2022/ngwr-lightbox.mjs.map +1 -1
  238. package/fesm2022/ngwr-line-chart-testing.mjs.map +1 -1
  239. package/fesm2022/ngwr-line-chart.mjs +18 -7
  240. package/fesm2022/ngwr-line-chart.mjs.map +1 -1
  241. package/fesm2022/ngwr-list.mjs +6 -6
  242. package/fesm2022/ngwr-list.mjs.map +1 -1
  243. package/fesm2022/ngwr-loading-bar-router.mjs.map +1 -1
  244. package/fesm2022/ngwr-loading-bar.mjs +6 -6
  245. package/fesm2022/ngwr-loading-bar.mjs.map +1 -1
  246. package/fesm2022/ngwr-markdown-testing.mjs.map +1 -1
  247. package/fesm2022/ngwr-markdown.mjs +798 -17
  248. package/fesm2022/ngwr-markdown.mjs.map +1 -1
  249. package/fesm2022/ngwr-marquee-testing.mjs.map +1 -1
  250. package/fesm2022/ngwr-marquee.mjs +3 -3
  251. package/fesm2022/ngwr-marquee.mjs.map +1 -1
  252. package/fesm2022/ngwr-media.mjs +3 -3
  253. package/fesm2022/ngwr-media.mjs.map +1 -1
  254. package/fesm2022/ngwr-mention-testing.mjs.map +1 -1
  255. package/fesm2022/ngwr-mention.mjs +6 -6
  256. package/fesm2022/ngwr-mention.mjs.map +1 -1
  257. package/fesm2022/ngwr-meta.mjs +6 -6
  258. package/fesm2022/ngwr-meta.mjs.map +1 -1
  259. package/fesm2022/ngwr-meter-group-testing.mjs +7 -3
  260. package/fesm2022/ngwr-meter-group-testing.mjs.map +1 -1
  261. package/fesm2022/ngwr-meter-group.mjs +26 -6
  262. package/fesm2022/ngwr-meter-group.mjs.map +1 -1
  263. package/fesm2022/ngwr-overlay.mjs +6 -6
  264. package/fesm2022/ngwr-overlay.mjs.map +1 -1
  265. package/fesm2022/ngwr-page-header.mjs +13 -5
  266. package/fesm2022/ngwr-page-header.mjs.map +1 -1
  267. package/fesm2022/ngwr-pagination-testing.mjs.map +1 -1
  268. package/fesm2022/ngwr-pagination.mjs +3 -3
  269. package/fesm2022/ngwr-pagination.mjs.map +1 -1
  270. package/fesm2022/ngwr-pipes.mjs +21 -21
  271. package/fesm2022/ngwr-pipes.mjs.map +1 -1
  272. package/fesm2022/ngwr-platform.mjs +9 -9
  273. package/fesm2022/ngwr-platform.mjs.map +1 -1
  274. package/fesm2022/ngwr-popconfirm-testing.mjs.map +1 -1
  275. package/fesm2022/ngwr-popconfirm.mjs +6 -6
  276. package/fesm2022/ngwr-popconfirm.mjs.map +1 -1
  277. package/fesm2022/ngwr-popover-testing.mjs.map +1 -1
  278. package/fesm2022/ngwr-popover.mjs +578 -16
  279. package/fesm2022/ngwr-popover.mjs.map +1 -1
  280. package/fesm2022/ngwr-progress.mjs +3 -3
  281. package/fesm2022/ngwr-progress.mjs.map +1 -1
  282. package/fesm2022/ngwr-pull-to-refresh.mjs +3 -3
  283. package/fesm2022/ngwr-pull-to-refresh.mjs.map +1 -1
  284. package/fesm2022/ngwr-qr.mjs +3 -3
  285. package/fesm2022/ngwr-qr.mjs.map +1 -1
  286. package/fesm2022/ngwr-radio-testing.mjs.map +1 -1
  287. package/fesm2022/ngwr-radio.mjs +6 -6
  288. package/fesm2022/ngwr-radio.mjs.map +1 -1
  289. package/fesm2022/ngwr-rating-testing.mjs.map +1 -1
  290. package/fesm2022/ngwr-rating.mjs +3 -3
  291. package/fesm2022/ngwr-rating.mjs.map +1 -1
  292. package/fesm2022/ngwr-result.mjs +12 -12
  293. package/fesm2022/ngwr-result.mjs.map +1 -1
  294. package/fesm2022/ngwr-rotating-text-testing.mjs.map +1 -1
  295. package/fesm2022/ngwr-rotating-text.mjs +3 -3
  296. package/fesm2022/ngwr-rotating-text.mjs.map +1 -1
  297. package/fesm2022/ngwr-schema-form.mjs +3 -3
  298. package/fesm2022/ngwr-schema-form.mjs.map +1 -1
  299. package/fesm2022/ngwr-scroll.mjs +3 -3
  300. package/fesm2022/ngwr-scroll.mjs.map +1 -1
  301. package/fesm2022/ngwr-segmented-testing.mjs.map +1 -1
  302. package/fesm2022/ngwr-segmented.mjs +3 -3
  303. package/fesm2022/ngwr-segmented.mjs.map +1 -1
  304. package/fesm2022/ngwr-select-testing.mjs.map +1 -1
  305. package/fesm2022/ngwr-select.mjs +12 -12
  306. package/fesm2022/ngwr-select.mjs.map +1 -1
  307. package/fesm2022/ngwr-shiny-text-testing.mjs.map +1 -1
  308. package/fesm2022/ngwr-shiny-text.mjs +6 -6
  309. package/fesm2022/ngwr-shiny-text.mjs.map +1 -1
  310. package/fesm2022/ngwr-sidebar.mjs +10 -3
  311. package/fesm2022/ngwr-sidebar.mjs.map +1 -1
  312. package/fesm2022/ngwr-skeleton.mjs +3 -3
  313. package/fesm2022/ngwr-skeleton.mjs.map +1 -1
  314. package/fesm2022/ngwr-slider-testing.mjs.map +1 -1
  315. package/fesm2022/ngwr-slider.mjs +3 -3
  316. package/fesm2022/ngwr-slider.mjs.map +1 -1
  317. package/fesm2022/ngwr-sparkline-testing.mjs.map +1 -1
  318. package/fesm2022/ngwr-sparkline.mjs +84 -10
  319. package/fesm2022/ngwr-sparkline.mjs.map +1 -1
  320. package/fesm2022/ngwr-speed-dial-testing.mjs.map +1 -1
  321. package/fesm2022/ngwr-speed-dial.mjs +3 -3
  322. package/fesm2022/ngwr-speed-dial.mjs.map +1 -1
  323. package/fesm2022/ngwr-spinner.mjs +3 -3
  324. package/fesm2022/ngwr-spinner.mjs.map +1 -1
  325. package/fesm2022/ngwr-splash-cursor-testing.mjs.map +1 -1
  326. package/fesm2022/ngwr-splash-cursor.mjs +3 -3
  327. package/fesm2022/ngwr-splash-cursor.mjs.map +1 -1
  328. package/fesm2022/ngwr-split-text-testing.mjs.map +1 -1
  329. package/fesm2022/ngwr-split-text.mjs +3 -3
  330. package/fesm2022/ngwr-split-text.mjs.map +1 -1
  331. package/fesm2022/ngwr-splitter-testing.mjs.map +1 -1
  332. package/fesm2022/ngwr-splitter.mjs +3 -3
  333. package/fesm2022/ngwr-splitter.mjs.map +1 -1
  334. package/fesm2022/ngwr-spotlight-card-testing.mjs.map +1 -1
  335. package/fesm2022/ngwr-spotlight-card.mjs +6 -6
  336. package/fesm2022/ngwr-spotlight-card.mjs.map +1 -1
  337. package/fesm2022/ngwr-squircle.mjs +6 -6
  338. package/fesm2022/ngwr-squircle.mjs.map +1 -1
  339. package/fesm2022/ngwr-star-border-testing.mjs.map +1 -1
  340. package/fesm2022/ngwr-star-border.mjs +3 -3
  341. package/fesm2022/ngwr-star-border.mjs.map +1 -1
  342. package/fesm2022/ngwr-statistic.mjs +9 -9
  343. package/fesm2022/ngwr-statistic.mjs.map +1 -1
  344. package/fesm2022/ngwr-stepper-testing.mjs.map +1 -1
  345. package/fesm2022/ngwr-stepper.mjs +6 -6
  346. package/fesm2022/ngwr-stepper.mjs.map +1 -1
  347. package/fesm2022/ngwr-storage.mjs +3 -3
  348. package/fesm2022/ngwr-storage.mjs.map +1 -1
  349. package/fesm2022/ngwr-switch-testing.mjs.map +1 -1
  350. package/fesm2022/ngwr-switch.mjs +3 -3
  351. package/fesm2022/ngwr-switch.mjs.map +1 -1
  352. package/fesm2022/ngwr-table-testing.mjs.map +1 -1
  353. package/fesm2022/ngwr-table.mjs +18 -18
  354. package/fesm2022/ngwr-table.mjs.map +1 -1
  355. package/fesm2022/ngwr-tabs-router.mjs +3 -3
  356. package/fesm2022/ngwr-tabs-router.mjs.map +1 -1
  357. package/fesm2022/ngwr-tabs-testing.mjs.map +1 -1
  358. package/fesm2022/ngwr-tabs.mjs +6 -6
  359. package/fesm2022/ngwr-tabs.mjs.map +1 -1
  360. package/fesm2022/ngwr-textarea-testing.mjs.map +1 -1
  361. package/fesm2022/ngwr-textarea.mjs +3 -3
  362. package/fesm2022/ngwr-textarea.mjs.map +1 -1
  363. package/fesm2022/ngwr-theme.mjs +3 -3
  364. package/fesm2022/ngwr-theme.mjs.map +1 -1
  365. package/fesm2022/ngwr-tilt-card-testing.mjs.map +1 -1
  366. package/fesm2022/ngwr-tilt-card.mjs +6 -6
  367. package/fesm2022/ngwr-tilt-card.mjs.map +1 -1
  368. package/fesm2022/ngwr-timeline.mjs +6 -6
  369. package/fesm2022/ngwr-timeline.mjs.map +1 -1
  370. package/fesm2022/ngwr-toast-testing.mjs.map +1 -1
  371. package/fesm2022/ngwr-toast.mjs +9 -9
  372. package/fesm2022/ngwr-toast.mjs.map +1 -1
  373. package/fesm2022/ngwr-toolbar.mjs +10 -3
  374. package/fesm2022/ngwr-toolbar.mjs.map +1 -1
  375. package/fesm2022/ngwr-tour-testing.mjs.map +1 -1
  376. package/fesm2022/ngwr-tour.mjs +6 -6
  377. package/fesm2022/ngwr-tour.mjs.map +1 -1
  378. package/fesm2022/ngwr-transfer-testing.mjs.map +1 -1
  379. package/fesm2022/ngwr-transfer.mjs +3 -3
  380. package/fesm2022/ngwr-transfer.mjs.map +1 -1
  381. package/fesm2022/ngwr-tree-testing.mjs.map +1 -1
  382. package/fesm2022/ngwr-tree.mjs +3 -3
  383. package/fesm2022/ngwr-tree.mjs.map +1 -1
  384. package/fesm2022/ngwr-typewriter-testing.mjs.map +1 -1
  385. package/fesm2022/ngwr-typewriter.mjs +3 -3
  386. package/fesm2022/ngwr-typewriter.mjs.map +1 -1
  387. package/fesm2022/ngwr-typography.mjs +7 -3
  388. package/fesm2022/ngwr-typography.mjs.map +1 -1
  389. package/fesm2022/ngwr-utils.mjs.map +1 -1
  390. package/fesm2022/ngwr-validators.mjs.map +1 -1
  391. package/fesm2022/ngwr-version.mjs +1 -1
  392. package/fesm2022/ngwr-version.mjs.map +1 -1
  393. package/fesm2022/ngwr-virtual-scroll.mjs +3 -3
  394. package/fesm2022/ngwr-virtual-scroll.mjs.map +1 -1
  395. package/fesm2022/ngwr-waves-testing.mjs.map +1 -1
  396. package/fesm2022/ngwr-waves.mjs +3 -3
  397. package/fesm2022/ngwr-waves.mjs.map +1 -1
  398. package/fesm2022/ngwr-window-testing.mjs.map +1 -1
  399. package/fesm2022/ngwr-window.mjs +12 -12
  400. package/fesm2022/ngwr-window.mjs.map +1 -1
  401. package/form/styles/_index.scss +16 -1
  402. package/gauge/styles/_index.scss +1 -0
  403. package/i18n/ar.json +32 -1
  404. package/i18n/cs.json +32 -1
  405. package/i18n/de.json +32 -1
  406. package/i18n/en.json +32 -1
  407. package/i18n/es.json +32 -1
  408. package/i18n/fr.json +32 -1
  409. package/i18n/he.json +32 -1
  410. package/i18n/hi.json +32 -1
  411. package/i18n/id.json +32 -1
  412. package/i18n/it.json +32 -1
  413. package/i18n/ja.json +32 -1
  414. package/i18n/ko.json +32 -1
  415. package/i18n/nl.json +32 -1
  416. package/i18n/pl.json +32 -1
  417. package/i18n/pt.json +32 -1
  418. package/i18n/ru.json +32 -1
  419. package/i18n/sv.json +32 -1
  420. package/i18n/tr.json +32 -1
  421. package/i18n/uk.json +32 -1
  422. package/i18n/vi.json +32 -1
  423. package/i18n/zh-TW.json +32 -1
  424. package/i18n/zh.json +32 -1
  425. package/input/styles/_index.scss +24 -1
  426. package/input-number/styles/_index.scss +69 -0
  427. package/input-otp/styles/_index.scss +5 -5
  428. package/line-chart/styles/_index.scss +30 -2
  429. package/llms-full.txt +14 -4
  430. package/llms.txt +188 -132
  431. package/mcp/providers.js +2 -2
  432. package/mcp/server.js +1 -1
  433. package/meter-group/styles/_index.scss +1 -0
  434. package/overlay/styles/_arrow.scss +30 -2
  435. package/package.json +43 -2
  436. package/page-header/styles/_index.scss +37 -1
  437. package/pagination/styles/_index.scss +9 -5
  438. package/popover/styles/_index.scss +73 -5
  439. package/progress/styles/_index.scss +4 -0
  440. package/radio/styles/_index.scss +4 -1
  441. package/schematics/use/symbol-map.json +1 -0
  442. package/select/styles/_index.scss +51 -12
  443. package/sidebar/styles/_index.scss +44 -2
  444. package/skeleton/styles/_index.scss +3 -0
  445. package/skills/ngwr/SKILL.md +5 -5
  446. package/skills/ngwr/references/catalog.md +2 -0
  447. package/skills/ngwr/references/setup.md +3 -3
  448. package/sparkline/styles/_index.scss +19 -0
  449. package/styles.scss +1 -0
  450. package/table/styles/_index.scss +7 -0
  451. package/textarea/styles/_index.scss +12 -3
  452. package/theme/styles/_colors.scss +39 -13
  453. package/theme/styles/_contrast.scss +9 -7
  454. package/toast/styles/_index.scss +4 -0
  455. package/toolbar/styles/_index.scss +35 -1
  456. package/tree/styles/_index.scss +46 -7
  457. package/types/ngwr-badge.d.ts +22 -7
  458. package/types/ngwr-bar-chart.d.ts +19 -1
  459. package/types/ngwr-calendar-heatmap.d.ts +29 -1
  460. package/types/ngwr-checkbox.d.ts +2 -0
  461. package/types/ngwr-config.d.ts +12 -0
  462. package/types/ngwr-date-picker.d.ts +308 -43
  463. package/types/ngwr-donut-chart.d.ts +24 -1
  464. package/types/ngwr-dropdown.d.ts +22 -2
  465. package/types/ngwr-editor-testing.d.ts +378 -0
  466. package/types/ngwr-editor.d.ts +449 -0
  467. package/types/ngwr-event-calendar.d.ts +8 -0
  468. package/types/ngwr-form.d.ts +35 -5
  469. package/types/ngwr-gauge.d.ts +20 -1
  470. package/types/ngwr-input-number.d.ts +7 -0
  471. package/types/ngwr-line-chart.d.ts +9 -1
  472. package/types/ngwr-markdown.d.ts +61 -2
  473. package/types/ngwr-meter-group-testing.d.ts +3 -2
  474. package/types/ngwr-meter-group.d.ts +14 -1
  475. package/types/ngwr-page-header.d.ts +10 -2
  476. package/types/ngwr-popover.d.ts +154 -3
  477. package/types/ngwr-sidebar.d.ts +7 -0
  478. package/types/ngwr-sparkline.d.ts +43 -1
  479. package/types/ngwr-toolbar.d.ts +7 -0
  480. package/types/ngwr-typography.d.ts +4 -0
  481. package/types/ngwr-version.d.ts +1 -1
  482. package/typography/styles/_index.scss +16 -0
@@ -1,7 +1,7 @@
1
1
  import { coerceBooleanProperty } from '@angular/cdk/coercion';
2
2
  import * as i0 from '@angular/core';
3
3
  import { input, computed, ViewEncapsulation, Component, InjectionToken, makeEnvironmentProviders, inject, signal, contentChild, effect, DestroyRef, contentChildren, forwardRef } from '@angular/core';
4
- import { NgControl } from '@angular/forms';
4
+ import { NgControl, AbstractControl } from '@angular/forms';
5
5
  import { EMPTY } from 'rxjs';
6
6
  import { useI18nText, WrI18n } from 'ngwr/i18n';
7
7
  import { createMetadataKey } from '@angular/forms/signals';
@@ -43,10 +43,10 @@ class WrFormItem {
43
43
  return parts.join(' ');
44
44
  }, /* @ts-ignore */
45
45
  ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
46
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrFormItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
47
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: WrFormItem, isStandalone: true, selector: "wr-form-item", inputs: { hasError: { classPropertyName: "hasError", publicName: "hasError", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: '<ng-content />', isInline: true, encapsulation: i0.ViewEncapsulation.None });
46
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrFormItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
47
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.7", type: WrFormItem, isStandalone: true, selector: "wr-form-item", inputs: { hasError: { classPropertyName: "hasError", publicName: "hasError", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: '<ng-content />', isInline: true, encapsulation: i0.ViewEncapsulation.None });
48
48
  }
49
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrFormItem, decorators: [{
49
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrFormItem, decorators: [{
50
50
  type: Component,
51
51
  args: [{
52
52
  selector: 'wr-form-item',
@@ -139,6 +139,11 @@ const WR_FORM_ERROR_FALLBACKS = {
139
139
  oneOf: 'Choose one of the allowed values.',
140
140
  minDate: 'Choose a later date.',
141
141
  maxDate: 'Choose an earlier date.',
142
+ // `<wr-date-picker>` / `<wr-date-range-picker>` — text typed into the field that
143
+ // was refused rather than committed. The picker reports these to its form as
144
+ // parse errors; `example` is a date written in the field's own format.
145
+ dateFormat: ({ error }) => `Expected format: ${num(error, 'example')}`,
146
+ dateFilter: 'This date is not available.',
142
147
  };
143
148
 
144
149
  /**
@@ -239,10 +244,10 @@ class WrFormError {
239
244
  return this.field.errorKeys().includes(key);
240
245
  }, /* @ts-ignore */
241
246
  ...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
242
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrFormError, deps: [], target: i0.ɵɵFactoryTarget.Component });
243
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: WrFormError, isStandalone: true, selector: "wr-form-error", inputs: { key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "alert" }, properties: { "attr.data-key": "key() ?? null", "class.wr-form-field__error--hidden": "!visible()" }, classAttribute: "wr-form-error wr-form-field__error" }, ngImport: i0, template: `<ng-content />`, isInline: true, encapsulation: i0.ViewEncapsulation.None });
247
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrFormError, deps: [], target: i0.ɵɵFactoryTarget.Component });
248
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.7", type: WrFormError, isStandalone: true, selector: "wr-form-error", inputs: { key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "alert" }, properties: { "attr.data-key": "key() ?? null", "class.wr-form-field__error--hidden": "!visible()" }, classAttribute: "wr-form-error wr-form-field__error" }, ngImport: i0, template: `<ng-content />`, isInline: true, encapsulation: i0.ViewEncapsulation.None });
244
249
  }
245
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrFormError, decorators: [{
250
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrFormError, decorators: [{
246
251
  type: Component,
247
252
  args: [{
248
253
  selector: 'wr-form-error',
@@ -344,9 +349,55 @@ class WrFormField {
344
349
  * Angular does expose, so the computed depends on this counter instead.
345
350
  * Signal Forms needs none of this — its interop getters read live signals —
346
351
  * and harmlessly contributes no events.
352
+ *
353
+ * Events are not the whole story, which is what {@link ngAfterContentChecked} is for.
347
354
  */
348
355
  revision = signal(0, /* @ts-ignore */
349
356
  ...(ngDevMode ? [{ debugName: "revision" }] : /* istanbul ignore next */ []));
357
+ /** What the last check saw on a reactive control — see {@link ngAfterContentChecked}. */
358
+ seen = null;
359
+ /**
360
+ * Catch the changes a reactive control makes WITHOUT an event.
361
+ *
362
+ * `updateValueAndValidity({ emitEvent: false })`, `markAsTouched({ emitEvent: false })`
363
+ * and their siblings change `errors`, `touched` and `dirty` and emit nothing, so the
364
+ * subscription above never hears them and the message stays whatever it was. That is
365
+ * not only an app's own silent write: Angular reports a custom control's PARSE errors
366
+ * to a `FormControl` exactly that way — a validator re-run with `emitEvent: false` —
367
+ * so a `wr-date-picker` refusing typed text made its control invalid while the field
368
+ * went on showing the message from before, or nothing — and a later pass of change
369
+ * detection did not help, because the message was memoised on a revision only events
370
+ * move.
371
+ *
372
+ * This runs whenever the view holding the field is checked, which is when the page
373
+ * around the control changes — for the date picker, the moment its refusal turns
374
+ * visible. It is `ngAfterContentChecked` and not `ngDoCheck` for an ordering reason
375
+ * read out of Angular's `refreshView`: check hooks run BEFORE the view's effects, and
376
+ * Angular's parse-error validator is re-run from an effect in that same view, so a
377
+ * `DoCheck` saw the errors one pass late and lost the message whenever nothing
378
+ * refreshed the view again. Content-checked hooks run after those effects and before
379
+ * the field's own bindings. Only a change moves the revision.
380
+ *
381
+ * Signal Forms' interop control is skipped: it is reactive already, and its `errors`
382
+ * getter builds a fresh object on every read, which a reference check would call a
383
+ * change on every pass — and re-resolve every message with it.
384
+ */
385
+ ngAfterContentChecked() {
386
+ const control = this.ngControl()?.control;
387
+ if (!(control instanceof AbstractControl)) {
388
+ this.seen = null;
389
+ return;
390
+ }
391
+ const { errors, touched, dirty } = control;
392
+ const seen = this.seen;
393
+ if (seen?.errors === errors && seen.touched === touched && seen.dirty === dirty)
394
+ return;
395
+ this.seen = { errors, touched, dirty };
396
+ // The first sighting is only the baseline: `errors` reads `ngControl()`, so the
397
+ // message already recomputed when the control appeared.
398
+ if (seen)
399
+ this.revision.update(n => n + 1);
400
+ }
350
401
  constructor() {
351
402
  let sub = null;
352
403
  effect(() => {
@@ -456,8 +507,8 @@ class WrFormField {
456
507
  return parts.join(' ');
457
508
  }, /* @ts-ignore */
458
509
  ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
459
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrFormField, deps: [], target: i0.ɵɵFactoryTarget.Component });
460
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: WrFormField, isStandalone: true, selector: "wr-form-field", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, optional: { classPropertyName: "optional", publicName: "optional", isSignal: true, isRequired: false, transformFunction: null }, optionalLabel: { classPropertyName: "optionalLabel", publicName: "optionalLabel", isSignal: true, isRequired: false, transformFunction: null }, controlId: { classPropertyName: "controlId", publicName: "controlId", isSignal: true, isRequired: false, transformFunction: null }, autoErrors: { classPropertyName: "autoErrors", publicName: "autoErrors", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, providers: [
510
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrFormField, deps: [], target: i0.ɵɵFactoryTarget.Component });
511
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: WrFormField, isStandalone: true, selector: "wr-form-field", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, optional: { classPropertyName: "optional", publicName: "optional", isSignal: true, isRequired: false, transformFunction: null }, optionalLabel: { classPropertyName: "optionalLabel", publicName: "optionalLabel", isSignal: true, isRequired: false, transformFunction: null }, controlId: { classPropertyName: "controlId", publicName: "controlId", isSignal: true, isRequired: false, transformFunction: null }, autoErrors: { classPropertyName: "autoErrors", publicName: "autoErrors", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, providers: [
461
512
  {
462
513
  provide: WR_FORM_FIELD,
463
514
  // eslint-disable-next-line @angular-eslint/no-forward-ref
@@ -465,7 +516,7 @@ class WrFormField {
465
516
  },
466
517
  ], queries: [{ propertyName: "ngControl", first: true, predicate: NgControl, descendants: true, isSignal: true }, { propertyName: "projectedErrors", predicate: WrFormError, isSignal: true }], ngImport: i0, template: "@if (label()) {\n <label class=\"wr-form-field__label\" [attr.id]=\"labelId()\" [attr.for]=\"labelFor()\">\n {{ label() }}\n @if (required()) {\n <span class=\"wr-form-field__required\" aria-hidden=\"true\">*</span>\n } @else if (optional()) {\n <span class=\"wr-form-field__optional\">({{ resolvedOptional() }})</span>\n }\n </label>\n}\n\n<div class=\"wr-form-field__control\"><ng-content /></div>\n\n@if (hasError()) {\n <div class=\"wr-form-field__errors\" [attr.id]=\"describedBy()\">\n <ng-content select=\"wr-form-error\" />\n @for (message of autoMessages(); track message.key) {\n <div class=\"wr-form-error wr-form-field__error\" role=\"alert\" [attr.data-key]=\"message.key\">\n {{ message.text }}\n </div>\n }\n </div>\n} @else if (hint()) {\n <small class=\"wr-form-field__hint\" [attr.id]=\"hintId()\">{{ hint() }}</small>\n}\n", encapsulation: i0.ViewEncapsulation.None });
467
518
  }
468
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrFormField, decorators: [{
519
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrFormField, decorators: [{
469
520
  type: Component,
470
521
  args: [{ selector: 'wr-form-field', encapsulation: ViewEncapsulation.None, host: { '[class]': 'classes()' }, providers: [
471
522
  {
@@ -1 +1 @@
1
- {"version":3,"file":"ngwr-form.mjs","sources":["../../../projects/lib/form/form-item.ts","../../../projects/lib/form/form-errors.ts","../../../projects/lib/form/tokens.ts","../../../projects/lib/form/form-field.ts","../../../projects/lib/form/form-field.html","../../../projects/lib/form/field-aria.ts","../../../projects/lib/form/schema.ts","../../../projects/lib/form/ngwr-form.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 { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { Component, ViewEncapsulation, computed, input } from '@angular/core';\n\n/**\n * Wraps a label + control + error message into a single field row.\n *\n * Toggle `hasError` to apply error styling to the projected label and\n * any descendant input / textarea / checkbox.\n *\n * @example\n * ```html\n * <wr-form-item [hasError]=\"form.controls.email.invalid\">\n * <label>Email</label>\n * <input wrInput formControlName=\"email\" />\n * <wr-form-error>Invalid email</wr-form-error>\n * </wr-form-item>\n * ```\n *\n * @see https://ngwr.dev/reference/components/form\n */\n@Component({\n selector: 'wr-form-item',\n template: '<ng-content />',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n})\nexport class WrFormItem {\n /**\n * When `true`, applies error coloring to the projected label and inputs.\n *\n * @default false\n */\n readonly hasError = input(false, { transform: coerceBooleanProperty });\n\n protected readonly classes = computed(() => {\n const parts = ['wr-form-item'];\n if (this.hasError()) parts.push('wr-form-item--error');\n return parts.join(' ');\n });\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { InjectionToken, type EnvironmentProviders, makeEnvironmentProviders } from '@angular/core';\n\n/** Pull a number out of a validator payload without trusting its shape. */\nfunction num(error: unknown, field: string): string {\n if (error && typeof error === 'object' && field in error) {\n const value = (error as Record<string, unknown>)[field];\n if (typeof value === 'number' || typeof value === 'string') return String(value);\n }\n return '';\n}\n\n/** What a message function is handed to build its sentence. */\nexport interface WrFormErrorContext {\n /** Validator key (classic forms) or Signal Forms `kind` that produced the error. */\n readonly key: string;\n /**\n * The validator's own payload — `{ requiredLength, actualLength }` for\n * `minlength`, `{ min }` for `wrMinDate`, and so on. `true` for the\n * flag-shaped validators, which carry nothing.\n */\n readonly error: unknown;\n /** The surrounding field's `label`, so a message can name the field. */\n readonly label: string;\n}\n\n/** A message, or a function that builds one from the validator's payload. */\nexport type WrFormErrorMessage = string | ((ctx: WrFormErrorContext) => string);\n\n/** Validator key → message. Keys are matched exactly against `control.errors`. */\nexport type WrFormErrorMessages = Readonly<Record<string, WrFormErrorMessage>>;\n\n/**\n * App-wide validation copy. Empty by default; `<wr-form-field>` falls through\n * to the `ngwr/i18n` catalog and then to a built-in English sentence, so a\n * form shows a usable message with no configuration at all.\n */\nexport const WR_FORM_ERRORS = new InjectionToken<WrFormErrorMessages>('WR_FORM_ERRORS', {\n providedIn: 'root',\n factory: () => ({}),\n});\n\n/**\n * Register validation messages for the whole app.\n *\n * Only the keys you name are overridden — everything else keeps resolving\n * through the i18n catalog, so this composes with `provideWrI18n()` rather than\n * replacing it. A projected `<wr-form-error key=\"…\">` still wins over both:\n * per-field copy beats app-wide copy.\n *\n * @example\n * ```ts\n * bootstrapApplication(App, {\n * providers: [\n * provideWrFormErrors({\n * required: 'Please fill this in.',\n * minlength: ({ error }) => `At least ${(error as { requiredLength: number }).requiredLength} characters.`,\n * }),\n * ],\n * });\n * ```\n */\nexport function provideWrFormErrors(messages: WrFormErrorMessages = {}): EnvironmentProviders {\n return makeEnvironmentProviders([{ provide: WR_FORM_ERRORS, useValue: messages }]);\n}\n\n/**\n * Last-resort English, used when no app catalog and no i18n catalog answer.\n *\n * These exist so that a form with zero configuration still says something true\n * rather than rendering an empty error block. Every key here also ships as a\n * `validation.*` entry in `ngwr/i18n/{en,ru}`, which is what a localized app\n * actually reads.\n */\nexport const WR_FORM_ERROR_FALLBACKS: WrFormErrorMessages = {\n // Angular built-ins.\n required: 'This field is required.',\n requiredTrue: 'This field must be checked.',\n email: 'Enter a valid email address.',\n // The number goes LAST, so the sentence reads the same at 1 as at 80. A noun\n // straight after a count needs plural machinery this layer deliberately does\n // not have — see the note beside the same two keys in `ngwr/i18n/en`.\n minlength: ({ error }) => `Minimum length is ${num(error, 'requiredLength')}.`,\n maxlength: ({ error }) => `Maximum length is ${num(error, 'requiredLength')}.`,\n min: ({ error }) => `Enter ${num(error, 'min')} or more.`,\n max: ({ error }) => `Enter ${num(error, 'max')} or less.`,\n pattern: 'This value is not in the expected format.',\n\n // WrValidators.\n // Not \"cannot be blank\": the validator PASSES on an empty value and fails on\n // any value that holds whitespace, so the blank wording described the one case\n // that never reaches this message — over a field reading `Ada Lovelace`.\n noWhitespace: 'This value cannot contain spaces.',\n hexColor: 'Enter a hex colour, e.g. #1a2b3c.',\n url: 'Enter a valid URL.',\n cardNumber: 'Enter a valid card number.',\n cvc: ({ error }) => `Enter the ${num(error, 'length')}-digit security code.`,\n iban: 'Enter a valid IBAN.',\n match: 'The two values do not match.',\n matchFields: 'These fields do not match.',\n oneOf: 'Choose one of the allowed values.',\n minDate: 'Choose a later date.',\n maxDate: 'Choose an earlier date.',\n};\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { InjectionToken, type Signal } from '@angular/core';\n\n/**\n * What a projected control can read from its surrounding `<wr-form-field>`.\n *\n * The field renders `<label [for]>` before it can see what was projected into\n * it, so the id has to travel the other way: the control adopts the id the\n * label already points at. Doing it through DI keeps it a render-time binding,\n * which is what SSR needs — stamping the id from `afterNextRender` would leave\n * every prerendered page with a label pointing at nothing.\n */\nexport interface WrFormFieldContext {\n /** Id the field's `<label for>` points at. */\n readonly controlId: Signal<string>;\n\n /**\n * The reverse direction, for the one case the paragraph above does not cover: a\n * projected control that already carries its own `id` keeps it, and the label has\n * to follow, or `for` names an element that does not exist and the field ends up\n * with no label at all. Called during the control's construction, so the label's\n * binding still resolves in the same render pass.\n */\n adoptControlId(id: string): void;\n\n /**\n * Validator keys currently in error, once the control is touched or dirty.\n * Empty when the field is valid or has not been interacted with.\n */\n readonly errorKeys: Signal<readonly string[]>;\n\n /** Id of the element listing the visible messages, or `null` when there are none. */\n readonly describedBy: Signal<string | null>;\n\n /**\n * Id of the field's own `<label>`, or `null` when it renders none.\n *\n * For the controls `<label for>` cannot reach. `for` only binds to a LABELABLE\n * element — button, input, meter, output, progress, select, textarea — so a\n * control whose focusable part is a `div[role=\"slider\"]`, a `role=\"button\"`\n * drop zone or a radiogroup got a label pointing at nothing: measured, five of\n * the eighteen value controls resolved `for` to no element in the document at\n * all. Those point `aria-labelledby` back at this instead, which is the\n * direction that works for a role.\n */\n readonly labelId?: Signal<string | null>;\n\n /**\n * Id of the field's hint, or `null` when it is showing none — including while\n * an error has replaced it, since the two never render together and an\n * `aria-describedby` naming an absent element is an author error.\n *\n * Separate from {@link describedBy} rather than folded into it because the two\n * carry different weight: a control keyed `aria-invalid` on \"the field is\n * describing me\" would announce itself invalid for a plain hint. Compose the\n * pair with `useFormFieldAria()` instead of reading either one directly.\n *\n * Optional so an app that provides its own `WR_FORM_FIELD` keeps compiling; a\n * field without it simply describes nothing but its errors.\n */\n readonly hintId?: Signal<string | null>;\n}\n\n/** Present only inside a `<wr-form-field>`; inject with `{ optional: true }`. */\nexport const WR_FORM_FIELD = new InjectionToken<WrFormFieldContext>('WR_FORM_FIELD');\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 {\n Component,\n DestroyRef,\n ViewEncapsulation,\n computed,\n contentChild,\n contentChildren,\n effect,\n forwardRef,\n inject,\n input,\n signal,\n} from '@angular/core';\nimport { NgControl } from '@angular/forms';\n\nimport { EMPTY, type Subscription } from 'rxjs';\n\nimport { WrI18n, useI18nText } from 'ngwr/i18n';\n\nimport { WR_FORM_ERRORS, WR_FORM_ERROR_FALLBACKS, type WrFormErrorMessage } from './form-errors';\nimport { WR_FORM_FIELD, type WrFormFieldContext } from './tokens';\n\nlet uid = 0;\n\n/** A message is either literal text or a function over the validator's payload. */\nfunction render(message: WrFormErrorMessage, key: string, error: unknown, label: string): string {\n return typeof message === 'function' ? message({ key, error, label }) : message;\n}\n\n/** Validator payloads are plain objects; anything else interpolates nothing. */\nfunction toParams(error: unknown): Record<string, unknown> | undefined {\n return error && typeof error === 'object' ? (error as Record<string, unknown>) : undefined;\n}\n\n/**\n * The two Signal Forms kinds whose spelling and payload differ from the classic\n * validator that means the same thing.\n *\n * Reactive forms emit `minlength` / `maxlength` carrying `requiredLength`;\n * Signal Forms emit `minLength` / `maxLength` carrying `minLength` / `maxLength`.\n * Nothing bridged them, so the library's FLAGSHIP forms flavour rendered an\n * empty error block for both: the key missed every message source in turn — the\n * app's own map, all twenty-two i18n catalogs, and the built-in fallbacks — and\n * `resolve` returns `''` for a miss, which the caller then filters out. A field\n * over its length limit was invalid, marked invalid, and said nothing.\n *\n * Normalised here rather than by adding two keys to twenty-two catalogs,\n * because the message is the SAME message: one sentence about a length, reached\n * by two spellings of one rule.\n */\nconst SIGNAL_FORMS_ALIASES: Readonly<Record<string, { readonly key: string; readonly from: string }>> = {\n minLength: { key: 'minlength', from: 'minLength' },\n maxLength: { key: 'maxlength', from: 'maxLength' },\n};\n\n/**\n * A Signal Forms length error, restated in the classic shape every message\n * source already understands. Anything else passes through untouched.\n */\nfunction normalizeError(key: string, error: unknown): { readonly key: string; readonly error: unknown } {\n const alias = SIGNAL_FORMS_ALIASES[key];\n if (!alias) return { key, error };\n\n const params = toParams(error);\n const bound = params?.[alias.from];\n return {\n key: alias.key,\n error: bound === undefined ? error : { ...params, requiredLength: bound },\n };\n}\n\n/**\n * One error message tied to a validator key. Renders only when the parent\n * form-field has a matching error in `control.errors`, and only once the\n * control is touched or dirty.\n *\n * @example\n * ```html\n * <wr-form-error key=\"required\">This field is required.</wr-form-error>\n * <wr-form-error key=\"email\">That doesn't look right.</wr-form-error>\n * ```\n */\n@Component({\n selector: 'wr-form-error',\n template: `<ng-content />`,\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'wr-form-error wr-form-field__error',\n role: 'alert',\n '[attr.data-key]': 'key() ?? null',\n '[class.wr-form-field__error--hidden]': '!visible()',\n },\n})\nexport class WrFormError {\n /**\n * Validator key this message corresponds to (e.g. `'required'`).\n * Optional — without a key the message always renders, which is the\n * plain inline-error usage inside `<wr-form-item>`.\n */\n readonly key = input<string>();\n\n private readonly field = inject(WR_FORM_FIELD, { optional: true });\n\n /**\n * Whether this message is the one the current error calls for.\n *\n * The parent projects every `<wr-form-error>` through a single\n * `<ng-content select>`, which cannot filter — so each message decides for\n * itself. Without this, one invalid control rendered \"Email is required.\"\n * and \"That isn't a valid email.\" side by side, which is what the docs have\n * always described as gated behaviour.\n *\n * A keyless message always shows: that is the plain inline-error usage inside\n * `<wr-form-item>`, which has no error discovery at all.\n */\n protected readonly visible = computed(() => {\n const key = this.key();\n if (!key || !this.field) return true;\n return this.field.errorKeys().includes(key);\n });\n}\n\n/**\n * Wraps a label + control + hint + error messages into a single block —\n * the layout primitive every form ends up reinventing.\n *\n * - Auto-binds `label[for]` to the projected control via a generated id\n * (or use the form-control's `[id]` if you set one).\n * - Reads the projected control's `NgControl` to surface validation\n * errors only when the control has been touched / submitted.\n * - Optional `[required]` / `[optional]` markers next to the label.\n *\n * @example\n * ```html\n * <wr-form-field label=\"Email\" hint=\"We'll never share it.\">\n * <input wrInput [formControl]=\"email\" type=\"email\" />\n * <wr-form-error key=\"required\">Email is required.</wr-form-error>\n * <wr-form-error key=\"email\">Not a valid email.</wr-form-error>\n * </wr-form-field>\n * ```\n *\n * @see https://ngwr.dev/reference/components/form-field\n */\n@Component({\n selector: 'wr-form-field',\n templateUrl: './form-field.html',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n providers: [\n {\n provide: WR_FORM_FIELD,\n // eslint-disable-next-line @angular-eslint/no-forward-ref\n useExisting: forwardRef(() => WrFormField),\n },\n ],\n})\nexport class WrFormField implements WrFormFieldContext {\n /** Label text shown above the control. */\n readonly label = input<string>('');\n\n /** Hint text shown below the control. Hidden when an error is visible. */\n readonly hint = input<string>('');\n\n /** Show a `*` next to the label. @default false */\n readonly required = input(false, { transform: coerceBooleanProperty });\n\n /**\n * Show an \"optional\" marker next to the label — the word comes from\n * `optionalLabel`. Mutually exclusive with `required`. @default false\n */\n readonly optional = input(false, { transform: coerceBooleanProperty });\n\n /**\n * Word inside the optional marker's parentheses. Falls back to\n * `form.optional`, then `'optional'`. The parentheses are the template's, so\n * no locale has to repeat punctuation.\n */\n readonly optionalLabel = input<string | null>(null);\n\n // Unlike the `*` marker beside it, this one is NOT `aria-hidden` — it sits\n // inside the `<label>` and is read as part of the control's accessible name,\n // so an English word here reached a Russian screen reader.\n protected readonly resolvedOptional = useI18nText(this.optionalLabel, 'form.optional', 'optional');\n\n /**\n * Force a specific id on the label's `for` attribute. Auto-generated\n * otherwise, and adopted by the projected `wrInput` unless that element\n * already carries an `id` of its own.\n */\n readonly controlId = input<string>(`wr-form-field-${++uid}`);\n\n // What a projected control reported it actually kept. `null` until one does — most\n // controls simply adopt `controlId`, and only a control with its own `id` overrides\n // it from the other direction.\n private readonly adoptedId = signal<string | null>(null);\n\n /**\n * Id the `<label for>` renders. A control that came with its own `id` keeps it, so\n * the label follows that instead of the generated one — otherwise `for` points at\n * an element that is not in the document and the field is unlabelled.\n */\n protected readonly labelFor = computed(() => this.adoptedId() ?? this.controlId());\n\n /** @internal `WrFormFieldContext` — see the token's docs. */\n adoptControlId(id: string): void {\n this.adoptedId.set(id);\n }\n\n /**\n * Projected `NgControl` — used to read touched / dirty / errors.\n *\n * This catches `[formField]` too: Angular's Signal Forms directive provides\n * `NgControl` via its interop shim, so both forms flavours land here.\n */\n protected readonly ngControl = contentChild(NgControl);\n\n /**\n * Bumped on every event the projected control emits.\n *\n * `AbstractControl`'s `touched` / `dirty` / `errors` accessors are NOT\n * reactive under classic forms — Angular reads them inside `untracked()`, and\n * `errors` is a plain assigned field. A `computed` over them therefore caches\n * its first value and never recomputes, which in a zoneless app means the\n * error block never appears at all. `control.events` is the reactive source\n * Angular does expose, so the computed depends on this counter instead.\n * Signal Forms needs none of this — its interop getters read live signals —\n * and harmlessly contributes no events.\n */\n private readonly revision = signal(0);\n\n constructor() {\n let sub: Subscription | null = null;\n effect(() => {\n const control = this.ngControl()?.control;\n sub?.unsubscribe();\n sub = (control?.events ?? EMPTY).subscribe(() => this.revision.update(n => n + 1));\n });\n inject(DestroyRef).onDestroy(() => sub?.unsubscribe());\n }\n\n protected readonly errors = computed(() => {\n this.revision();\n const c = this.ngControl();\n if (!c) return null;\n if (!c.touched && !c.dirty) return null;\n return c.errors;\n });\n\n protected readonly hasError = computed(() => {\n const errs = this.errors();\n return !!errs && Object.keys(errs).length > 0;\n });\n\n /** @internal Read by the projected `<wr-form-error>` children to decide which of them renders. */\n readonly errorKeys = computed<readonly string[]>(() => Object.keys(this.errors() ?? {}));\n\n /** @internal Read by the projected control so a screen reader is pointed at the message. */\n readonly describedBy = computed(() => (this.hasError() ? `${this.controlId()}-errors` : null));\n\n /**\n * @internal Read by the projected control so the hint is announced with the field.\n *\n * The hint used to carry no id at all, so the only thing `aria-describedby`\n * could ever name was the error block: the sentence explaining what to type was\n * on screen and reached a screen-reader user through no path whatsoever, and\n * the one gate that could have said so does not exist — axe has no rule that\n * visible help text must be programmatically associated.\n *\n * `null` while an error is showing, because the template swaps the hint out for\n * the message; publishing the id anyway would point every control at an element\n * that had just left the document.\n */\n readonly hintId = computed(() => (!this.hasError() && this.hint() ? `${this.controlId()}-hint` : null));\n\n /** @internal `WrFormFieldContext` — the id a role-based control points `aria-labelledby` at. */\n readonly labelId = computed(() => (this.label() ? `${this.controlId()}-label` : null));\n\n /**\n * Render a catalog message for any error the markup does not already answer.\n *\n * On by default: a field with no `<wr-form-error>` at all is the common case,\n * and an empty error block helps nobody. Turn it off for a field whose copy is\n * entirely hand-written. @default true\n */\n readonly autoErrors = input(true, { transform: coerceBooleanProperty });\n\n private readonly projectedErrors = contentChildren(WrFormError);\n private readonly appMessages = inject(WR_FORM_ERRORS);\n private readonly i18n = inject(WrI18n, { optional: true });\n\n /**\n * Errors with no projected `<wr-form-error key>` to answer them, resolved to\n * text: the app catalog first, then the `validation.*` i18n keys, then a\n * built-in English sentence. Per-field markup always wins — it is the most\n * specific thing the author wrote.\n */\n protected readonly autoMessages = computed<readonly { key: string; text: string }[]>(() => {\n if (!this.autoErrors()) return [];\n const errors = this.errors();\n if (!errors) return [];\n\n const claimed = new Set(\n this.projectedErrors()\n .map(e => e.key())\n .filter(Boolean)\n );\n\n return Object.entries(errors)\n .filter(([key]) => !claimed.has(key))\n .map(([key, error]) => ({ key, text: this.resolve(key, error) }))\n .filter(m => m.text.length > 0);\n });\n\n private resolve(rawKey: string, rawError: unknown): string {\n // A consumer's own map is consulted under BOTH spellings — theirs first, so\n // someone who already worked around this by writing `minLength` keeps\n // winning, and the normalised one after.\n const appRaw = this.appMessages[rawKey];\n if (appRaw !== undefined) return render(appRaw, rawKey, rawError, this.label());\n\n const { key, error } = normalizeError(rawKey, rawError);\n const app = this.appMessages[key];\n if (app !== undefined) return render(app, key, error, this.label());\n\n // `t()` reads the service's revision signal, so this recomputes on a locale\n // switch; a miss returns the key itself, which is the documented signal.\n const translated = this.i18n?.t(`validation.${key}`, toParams(error));\n if (translated && translated !== `validation.${key}`) return translated;\n\n const fallback = WR_FORM_ERROR_FALLBACKS[key];\n return fallback === undefined ? '' : render(fallback, key, error, this.label());\n }\n\n protected readonly classes = computed(() => {\n const parts = ['wr-form-field'];\n if (this.hasError()) parts.push('wr-form-field--invalid');\n if (this.required()) parts.push('wr-form-field--required');\n return parts.join(' ');\n });\n}\n","@if (label()) {\n <label class=\"wr-form-field__label\" [attr.id]=\"labelId()\" [attr.for]=\"labelFor()\">\n {{ label() }}\n @if (required()) {\n <span class=\"wr-form-field__required\" aria-hidden=\"true\">*</span>\n } @else if (optional()) {\n <span class=\"wr-form-field__optional\">({{ resolvedOptional() }})</span>\n }\n </label>\n}\n\n<div class=\"wr-form-field__control\"><ng-content /></div>\n\n@if (hasError()) {\n <div class=\"wr-form-field__errors\" [attr.id]=\"describedBy()\">\n <ng-content select=\"wr-form-error\" />\n @for (message of autoMessages(); track message.key) {\n <div class=\"wr-form-error wr-form-field__error\" role=\"alert\" [attr.data-key]=\"message.key\">\n {{ message.text }}\n </div>\n }\n </div>\n} @else if (hint()) {\n <small class=\"wr-form-field__hint\" [attr.id]=\"hintId()\">{{ hint() }}</small>\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { type Signal, computed, inject } from '@angular/core';\n\nimport { WR_FORM_FIELD } from './tokens';\n\n/** What {@link useFormFieldAria} hands a control to bind on its own element. */\nexport interface WrFormFieldAria {\n /**\n * Id of the field's message block while it is showing one, of its hint\n * otherwise, and `null` when it is showing neither.\n */\n readonly describedBy: Signal<string | null>;\n /** `'true'` while the field has a validation error, `null` otherwise. */\n readonly ariaInvalid: Signal<'true' | null>;\n /**\n * Id of the field's `<label>`, for a control `<label for>` cannot reach.\n *\n * `for` binds only to a LABELABLE element, so a control whose focusable part\n * is a `div` with a role gets nothing from it — measured, `wr-rating`,\n * `wr-knob` and `wr-file-upload` all rendered a field label whose `for` named\n * no element in the document. Point `aria-labelledby` at this instead; a\n * control that IS labelable should ignore it and let `for` do the work, or the\n * name is announced twice.\n */\n readonly labelledBy: Signal<string | null>;\n}\n\n/**\n * The two attributes that make a `<wr-form-field>`'s visible text — its error\n * message, or its hint — reach a screen reader. Bind both on whichever element\n * carries the control's role.\n *\n * Without them the copy the field renders is visible and nothing else: the\n * control announces itself as valid, and the text is associated with nothing.\n * No automated gate catches that — axe has no rule that a visible error or hint\n * must be programmatically associated with its control — so this helper exists\n * to make the wiring one line per control rather than three, and the specs are\n * the gate.\n *\n * The field renders an error OR a hint, never both, so `describedBy` names\n * whichever is on screen and `aria-invalid` is keyed SEPARATELY, on the field's\n * `errorKeys()`. Deriving it from `describedBy` instead — which is what every\n * control did while a hint had no id to name — makes a field with a plain hint\n * announce its control as invalid the moment the hint becomes describable.\n *\n * Must be called from an injection context (a field initialiser or a\n * constructor). Returns inert signals outside a `<wr-form-field>`.\n *\n * Pass `skipSelf` from a COMPOSITE control — one whose own template renders\n * other ngwr controls. Such a component shields its subtree by re-providing\n * `WR_FORM_FIELD` as `null`, or the inner parts each announce the outer field's\n * error as their own; a component sees its own providers, so it has to read the\n * real field from one level up.\n *\n * @example\n * ```ts\n * protected readonly fieldAria = useFormFieldAria();\n * ```\n * ```html\n * <input [attr.aria-invalid]=\"fieldAria.ariaInvalid()\" [attr.aria-describedby]=\"fieldAria.describedBy()\" />\n * ```\n */\nexport function useFormFieldAria(options?: { readonly skipSelf?: boolean }): WrFormFieldAria {\n const field = inject(WR_FORM_FIELD, { optional: true, skipSelf: options?.skipSelf ?? false });\n return {\n // `hintId` is optional on the interface so an app-provided field keeps\n // compiling; one without it describes nothing but its errors, as before.\n describedBy: computed(() => field?.describedBy() ?? field?.hintId?.() ?? null),\n ariaInvalid: computed<'true' | null>(() => ((field?.errorKeys().length ?? 0) > 0 ? 'true' : null)),\n // `null` for a control that `<label for>` already reaches — pointing at the\n // same label twice would name it twice. Only the role-based controls read\n // this, and only because `for` cannot bind to a role.\n labelledBy: computed(() => field?.labelId?.() ?? null),\n };\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { createMetadataKey } from '@angular/forms/signals';\n\n/**\n * How a field is DRAWN, attached to the same Signal Forms schema that already\n * says how it is validated.\n *\n * The alternative was a second schema — one for rules, one for presentation —\n * and it was rejected before it was written: two descriptions of one form drift\n * the moment someone renames a field in one of them, and nothing would report\n * it. Angular's `metadata()` takes a typed key and a `LogicFn`, so the\n * presentation rides on the schema the validators are already in, and it is\n * REACTIVE for free: a label, a set of options or a placeholder may depend on\n * the value of another field.\n *\n * What this deliberately does NOT carry: `required`, `disabled`, `readonly`,\n * `hidden`, `min`, `max`, and every validation rule. Those are Angular's own\n * schema functions, they already drive the control through `[formField]`, and\n * duplicating them here would create a second source of truth for state the form\n * already owns. That is not only a judgement call — Angular REFUSES a `[min]` or\n * `[required]` binding on a field-bound control (NG8022), so the second source\n * of truth is a compile error rather than a drift.\n */\nexport type WrFieldKind =\n 'input' | 'textarea' | 'number' | 'select' | 'checkbox' | 'switch' | 'radio' | 'date' | 'slider';\n\n/** One choice, for the kinds that offer a list. */\nexport interface WrFieldOption {\n readonly value: unknown;\n readonly label: string;\n readonly disabled?: boolean;\n}\n\n/**\n * The presentation of one field.\n *\n * `kind` is the only required member: everything else has a sane default, and a\n * schema that says no more than `{ kind: 'input' }` still renders a labelled,\n * error-bound control — the label falls back to the field's own name.\n */\nexport interface WrFieldSpec {\n readonly kind: WrFieldKind;\n /** Defaults to the field's key, de-camel-cased — `workEmail` becomes \"Work email\". */\n readonly label?: string;\n readonly placeholder?: string;\n /** Help text under the control. Errors replace it while the field is invalid. */\n readonly hint?: string;\n /** For `select` and `radio`. Ignored by every other kind. */\n readonly options?: readonly WrFieldOption[];\n /** Native `type` for `kind: 'input'` — `email`, `password`, `url`, `tel`. */\n readonly type?: string;\n /**\n * Granularity for `number` and `slider`. The BOUNDS are deliberately absent:\n * Angular refuses a `[min]` or `[max]` binding on a `[formField]`-bound\n * control outright (NG8022), because the field owns them — write `min(path.x,\n * 18)` in the schema and the control picks it up. `step` is presentation, has\n * no schema function, and stays here.\n */\n readonly step?: number;\n /**\n * Columns this field spans in `<wr-schema-form>`'s grid. Clamped to the form's\n * own `columns`, and 1 by default — a field is one cell unless it asks to be\n * wider.\n */\n readonly span?: number;\n}\n\n/**\n * The metadata key `<wr-schema-form>` reads.\n *\n * ```ts\n * const userSchema = schema<User>(path => {\n * required(path.email);\n * email(path.email);\n * metadata(path.email, WR_FIELD, () => ({ kind: 'input', type: 'email', label: 'Work email' }));\n * metadata(path.role, WR_FIELD, () => ({ kind: 'select', options: ROLES }));\n * });\n * ```\n *\n * A field with no `WR_FIELD` metadata is not an error and is not guessed at —\n * `<wr-schema-form>` skips it, so a schema can describe more than one screen shows.\n */\nexport const WR_FIELD = createMetadataKey<WrFieldSpec>();\n\n/** `workEmail` -> `Work email`. The fallback label, and only ever a fallback. */\nexport function wrFieldLabel(key: string): string {\n const spaced = key.replace(/([a-z\\d])([A-Z])/g, '$1 $2').replace(/[_-]+/g, ' ');\n return spaced.charAt(0).toUpperCase() + spaced.slice(1).toLowerCase();\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-form.mjs","sources":["../../../projects/lib/form/form-item.ts","../../../projects/lib/form/form-errors.ts","../../../projects/lib/form/tokens.ts","../../../projects/lib/form/form-field.ts","../../../projects/lib/form/form-field.html","../../../projects/lib/form/field-aria.ts","../../../projects/lib/form/schema.ts","../../../projects/lib/form/ngwr-form.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 { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { Component, ViewEncapsulation, computed, input } from '@angular/core';\n\n/**\n * Wraps a label + control + error message into a single field row.\n *\n * Toggle `hasError` to apply error styling to the projected label and\n * any descendant input / textarea / checkbox.\n *\n * @example\n * ```html\n * <wr-form-item [hasError]=\"form.controls.email.invalid\">\n * <label>Email</label>\n * <input wrInput formControlName=\"email\" />\n * <wr-form-error>Invalid email</wr-form-error>\n * </wr-form-item>\n * ```\n *\n * @see https://ngwr.dev/reference/components/form\n */\n@Component({\n selector: 'wr-form-item',\n template: '<ng-content />',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n})\nexport class WrFormItem {\n /**\n * When `true`, applies error coloring to the projected label and inputs.\n *\n * @default false\n */\n readonly hasError = input(false, { transform: coerceBooleanProperty });\n\n protected readonly classes = computed(() => {\n const parts = ['wr-form-item'];\n if (this.hasError()) parts.push('wr-form-item--error');\n return parts.join(' ');\n });\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { InjectionToken, type EnvironmentProviders, makeEnvironmentProviders } from '@angular/core';\n\n/** Pull a number out of a validator payload without trusting its shape. */\nfunction num(error: unknown, field: string): string {\n if (error && typeof error === 'object' && field in error) {\n const value = (error as Record<string, unknown>)[field];\n if (typeof value === 'number' || typeof value === 'string') return String(value);\n }\n return '';\n}\n\n/** What a message function is handed to build its sentence. */\nexport interface WrFormErrorContext {\n /** Validator key (classic forms) or Signal Forms `kind` that produced the error. */\n readonly key: string;\n /**\n * The validator's own payload — `{ requiredLength, actualLength }` for\n * `minlength`, `{ min }` for `wrMinDate`, and so on. `true` for the\n * flag-shaped validators, which carry nothing.\n */\n readonly error: unknown;\n /** The surrounding field's `label`, so a message can name the field. */\n readonly label: string;\n}\n\n/** A message, or a function that builds one from the validator's payload. */\nexport type WrFormErrorMessage = string | ((ctx: WrFormErrorContext) => string);\n\n/** Validator key → message. Keys are matched exactly against `control.errors`. */\nexport type WrFormErrorMessages = Readonly<Record<string, WrFormErrorMessage>>;\n\n/**\n * App-wide validation copy. Empty by default; `<wr-form-field>` falls through\n * to the `ngwr/i18n` catalog and then to a built-in English sentence, so a\n * form shows a usable message with no configuration at all.\n */\nexport const WR_FORM_ERRORS = new InjectionToken<WrFormErrorMessages>('WR_FORM_ERRORS', {\n providedIn: 'root',\n factory: () => ({}),\n});\n\n/**\n * Register validation messages for the whole app.\n *\n * Only the keys you name are overridden — everything else keeps resolving\n * through the i18n catalog, so this composes with `provideWrI18n()` rather than\n * replacing it. A projected `<wr-form-error key=\"…\">` still wins over both:\n * per-field copy beats app-wide copy.\n *\n * @example\n * ```ts\n * bootstrapApplication(App, {\n * providers: [\n * provideWrFormErrors({\n * required: 'Please fill this in.',\n * minlength: ({ error }) => `At least ${(error as { requiredLength: number }).requiredLength} characters.`,\n * }),\n * ],\n * });\n * ```\n */\nexport function provideWrFormErrors(messages: WrFormErrorMessages = {}): EnvironmentProviders {\n return makeEnvironmentProviders([{ provide: WR_FORM_ERRORS, useValue: messages }]);\n}\n\n/**\n * Last-resort English, used when no app catalog and no i18n catalog answer.\n *\n * These exist so that a form with zero configuration still says something true\n * rather than rendering an empty error block. Every key here also ships as a\n * `validation.*` entry in `ngwr/i18n/{en,ru}`, which is what a localized app\n * actually reads.\n */\nexport const WR_FORM_ERROR_FALLBACKS: WrFormErrorMessages = {\n // Angular built-ins.\n required: 'This field is required.',\n requiredTrue: 'This field must be checked.',\n email: 'Enter a valid email address.',\n // The number goes LAST, so the sentence reads the same at 1 as at 80. A noun\n // straight after a count needs plural machinery this layer deliberately does\n // not have — see the note beside the same two keys in `ngwr/i18n/en`.\n minlength: ({ error }) => `Minimum length is ${num(error, 'requiredLength')}.`,\n maxlength: ({ error }) => `Maximum length is ${num(error, 'requiredLength')}.`,\n min: ({ error }) => `Enter ${num(error, 'min')} or more.`,\n max: ({ error }) => `Enter ${num(error, 'max')} or less.`,\n pattern: 'This value is not in the expected format.',\n\n // WrValidators.\n // Not \"cannot be blank\": the validator PASSES on an empty value and fails on\n // any value that holds whitespace, so the blank wording described the one case\n // that never reaches this message — over a field reading `Ada Lovelace`.\n noWhitespace: 'This value cannot contain spaces.',\n hexColor: 'Enter a hex colour, e.g. #1a2b3c.',\n url: 'Enter a valid URL.',\n cardNumber: 'Enter a valid card number.',\n cvc: ({ error }) => `Enter the ${num(error, 'length')}-digit security code.`,\n iban: 'Enter a valid IBAN.',\n match: 'The two values do not match.',\n matchFields: 'These fields do not match.',\n oneOf: 'Choose one of the allowed values.',\n minDate: 'Choose a later date.',\n maxDate: 'Choose an earlier date.',\n\n // `<wr-date-picker>` / `<wr-date-range-picker>` — text typed into the field that\n // was refused rather than committed. The picker reports these to its form as\n // parse errors; `example` is a date written in the field's own format.\n dateFormat: ({ error }) => `Expected format: ${num(error, 'example')}`,\n dateFilter: 'This date is not available.',\n};\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { InjectionToken, type Signal } from '@angular/core';\n\n/**\n * What a projected control can read from its surrounding `<wr-form-field>`.\n *\n * The field renders `<label [for]>` before it can see what was projected into\n * it, so the id has to travel the other way: the control adopts the id the\n * label already points at. Doing it through DI keeps it a render-time binding,\n * which is what SSR needs — stamping the id from `afterNextRender` would leave\n * every prerendered page with a label pointing at nothing.\n */\nexport interface WrFormFieldContext {\n /** Id the field's `<label for>` points at. */\n readonly controlId: Signal<string>;\n\n /**\n * The reverse direction, for the one case the paragraph above does not cover: a\n * projected control that already carries its own `id` keeps it, and the label has\n * to follow, or `for` names an element that does not exist and the field ends up\n * with no label at all. Called during the control's construction, so the label's\n * binding still resolves in the same render pass.\n */\n adoptControlId(id: string): void;\n\n /**\n * Validator keys currently in error, once the control is touched or dirty.\n * Empty when the field is valid or has not been interacted with.\n */\n readonly errorKeys: Signal<readonly string[]>;\n\n /** Id of the element listing the visible messages, or `null` when there are none. */\n readonly describedBy: Signal<string | null>;\n\n /**\n * Id of the field's own `<label>`, or `null` when it renders none.\n *\n * For the controls `<label for>` cannot reach. `for` only binds to a LABELABLE\n * element — button, input, meter, output, progress, select, textarea — so a\n * control whose focusable part is a `div[role=\"slider\"]`, a `role=\"button\"`\n * drop zone or a radiogroup got a label pointing at nothing: measured, five of\n * the eighteen value controls resolved `for` to no element in the document at\n * all. Those point `aria-labelledby` back at this instead, which is the\n * direction that works for a role.\n */\n readonly labelId?: Signal<string | null>;\n\n /**\n * Id of the field's hint, or `null` when it is showing none — including while\n * an error has replaced it, since the two never render together and an\n * `aria-describedby` naming an absent element is an author error.\n *\n * Separate from {@link describedBy} rather than folded into it because the two\n * carry different weight: a control keyed `aria-invalid` on \"the field is\n * describing me\" would announce itself invalid for a plain hint. Compose the\n * pair with `useFormFieldAria()` instead of reading either one directly.\n *\n * Optional so an app that provides its own `WR_FORM_FIELD` keeps compiling; a\n * field without it simply describes nothing but its errors.\n */\n readonly hintId?: Signal<string | null>;\n}\n\n/** Present only inside a `<wr-form-field>`; inject with `{ optional: true }`. */\nexport const WR_FORM_FIELD = new InjectionToken<WrFormFieldContext>('WR_FORM_FIELD');\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 {\n Component,\n DestroyRef,\n type AfterContentChecked,\n ViewEncapsulation,\n computed,\n contentChild,\n contentChildren,\n effect,\n forwardRef,\n inject,\n input,\n signal,\n} from '@angular/core';\nimport { AbstractControl, NgControl, type ValidationErrors } from '@angular/forms';\n\nimport { EMPTY, type Subscription } from 'rxjs';\n\nimport { WrI18n, useI18nText } from 'ngwr/i18n';\n\nimport { WR_FORM_ERRORS, WR_FORM_ERROR_FALLBACKS, type WrFormErrorMessage } from './form-errors';\nimport { WR_FORM_FIELD, type WrFormFieldContext } from './tokens';\n\nlet uid = 0;\n\n/** A message is either literal text or a function over the validator's payload. */\nfunction render(message: WrFormErrorMessage, key: string, error: unknown, label: string): string {\n return typeof message === 'function' ? message({ key, error, label }) : message;\n}\n\n/** Validator payloads are plain objects; anything else interpolates nothing. */\nfunction toParams(error: unknown): Record<string, unknown> | undefined {\n return error && typeof error === 'object' ? (error as Record<string, unknown>) : undefined;\n}\n\n/**\n * The two Signal Forms kinds whose spelling and payload differ from the classic\n * validator that means the same thing.\n *\n * Reactive forms emit `minlength` / `maxlength` carrying `requiredLength`;\n * Signal Forms emit `minLength` / `maxLength` carrying `minLength` / `maxLength`.\n * Nothing bridged them, so the library's FLAGSHIP forms flavour rendered an\n * empty error block for both: the key missed every message source in turn — the\n * app's own map, all twenty-two i18n catalogs, and the built-in fallbacks — and\n * `resolve` returns `''` for a miss, which the caller then filters out. A field\n * over its length limit was invalid, marked invalid, and said nothing.\n *\n * Normalised here rather than by adding two keys to twenty-two catalogs,\n * because the message is the SAME message: one sentence about a length, reached\n * by two spellings of one rule.\n */\nconst SIGNAL_FORMS_ALIASES: Readonly<Record<string, { readonly key: string; readonly from: string }>> = {\n minLength: { key: 'minlength', from: 'minLength' },\n maxLength: { key: 'maxlength', from: 'maxLength' },\n};\n\n/**\n * A Signal Forms length error, restated in the classic shape every message\n * source already understands. Anything else passes through untouched.\n */\nfunction normalizeError(key: string, error: unknown): { readonly key: string; readonly error: unknown } {\n const alias = SIGNAL_FORMS_ALIASES[key];\n if (!alias) return { key, error };\n\n const params = toParams(error);\n const bound = params?.[alias.from];\n return {\n key: alias.key,\n error: bound === undefined ? error : { ...params, requiredLength: bound },\n };\n}\n\n/**\n * One error message tied to a validator key. Renders only when the parent\n * form-field has a matching error in `control.errors`, and only once the\n * control is touched or dirty.\n *\n * @example\n * ```html\n * <wr-form-error key=\"required\">This field is required.</wr-form-error>\n * <wr-form-error key=\"email\">That doesn't look right.</wr-form-error>\n * ```\n */\n@Component({\n selector: 'wr-form-error',\n template: `<ng-content />`,\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'wr-form-error wr-form-field__error',\n role: 'alert',\n '[attr.data-key]': 'key() ?? null',\n '[class.wr-form-field__error--hidden]': '!visible()',\n },\n})\nexport class WrFormError {\n /**\n * Validator key this message corresponds to (e.g. `'required'`).\n * Optional — without a key the message always renders, which is the\n * plain inline-error usage inside `<wr-form-item>`.\n */\n readonly key = input<string>();\n\n private readonly field = inject(WR_FORM_FIELD, { optional: true });\n\n /**\n * Whether this message is the one the current error calls for.\n *\n * The parent projects every `<wr-form-error>` through a single\n * `<ng-content select>`, which cannot filter — so each message decides for\n * itself. Without this, one invalid control rendered \"Email is required.\"\n * and \"That isn't a valid email.\" side by side, which is what the docs have\n * always described as gated behaviour.\n *\n * A keyless message always shows: that is the plain inline-error usage inside\n * `<wr-form-item>`, which has no error discovery at all.\n */\n protected readonly visible = computed(() => {\n const key = this.key();\n if (!key || !this.field) return true;\n return this.field.errorKeys().includes(key);\n });\n}\n\n/**\n * Wraps a label + control + hint + error messages into a single block —\n * the layout primitive every form ends up reinventing.\n *\n * - Auto-binds `label[for]` to the projected control via a generated id\n * (or use the form-control's `[id]` if you set one).\n * - Reads the projected control's `NgControl` to surface validation\n * errors only when the control has been touched / submitted.\n * - Optional `[required]` / `[optional]` markers next to the label.\n *\n * @example\n * ```html\n * <wr-form-field label=\"Email\" hint=\"We'll never share it.\">\n * <input wrInput [formControl]=\"email\" type=\"email\" />\n * <wr-form-error key=\"required\">Email is required.</wr-form-error>\n * <wr-form-error key=\"email\">Not a valid email.</wr-form-error>\n * </wr-form-field>\n * ```\n *\n * @see https://ngwr.dev/reference/components/form-field\n */\n@Component({\n selector: 'wr-form-field',\n templateUrl: './form-field.html',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n providers: [\n {\n provide: WR_FORM_FIELD,\n // eslint-disable-next-line @angular-eslint/no-forward-ref\n useExisting: forwardRef(() => WrFormField),\n },\n ],\n})\nexport class WrFormField implements WrFormFieldContext, AfterContentChecked {\n /** Label text shown above the control. */\n readonly label = input<string>('');\n\n /** Hint text shown below the control. Hidden when an error is visible. */\n readonly hint = input<string>('');\n\n /** Show a `*` next to the label. @default false */\n readonly required = input(false, { transform: coerceBooleanProperty });\n\n /**\n * Show an \"optional\" marker next to the label — the word comes from\n * `optionalLabel`. Mutually exclusive with `required`. @default false\n */\n readonly optional = input(false, { transform: coerceBooleanProperty });\n\n /**\n * Word inside the optional marker's parentheses. Falls back to\n * `form.optional`, then `'optional'`. The parentheses are the template's, so\n * no locale has to repeat punctuation.\n */\n readonly optionalLabel = input<string | null>(null);\n\n // Unlike the `*` marker beside it, this one is NOT `aria-hidden` — it sits\n // inside the `<label>` and is read as part of the control's accessible name,\n // so an English word here reached a Russian screen reader.\n protected readonly resolvedOptional = useI18nText(this.optionalLabel, 'form.optional', 'optional');\n\n /**\n * Force a specific id on the label's `for` attribute. Auto-generated\n * otherwise, and adopted by the projected `wrInput` unless that element\n * already carries an `id` of its own.\n */\n readonly controlId = input<string>(`wr-form-field-${++uid}`);\n\n // What a projected control reported it actually kept. `null` until one does — most\n // controls simply adopt `controlId`, and only a control with its own `id` overrides\n // it from the other direction.\n private readonly adoptedId = signal<string | null>(null);\n\n /**\n * Id the `<label for>` renders. A control that came with its own `id` keeps it, so\n * the label follows that instead of the generated one — otherwise `for` points at\n * an element that is not in the document and the field is unlabelled.\n */\n protected readonly labelFor = computed(() => this.adoptedId() ?? this.controlId());\n\n /** @internal `WrFormFieldContext` — see the token's docs. */\n adoptControlId(id: string): void {\n this.adoptedId.set(id);\n }\n\n /**\n * Projected `NgControl` — used to read touched / dirty / errors.\n *\n * This catches `[formField]` too: Angular's Signal Forms directive provides\n * `NgControl` via its interop shim, so both forms flavours land here.\n */\n protected readonly ngControl = contentChild(NgControl);\n\n /**\n * Bumped on every event the projected control emits.\n *\n * `AbstractControl`'s `touched` / `dirty` / `errors` accessors are NOT\n * reactive under classic forms — Angular reads them inside `untracked()`, and\n * `errors` is a plain assigned field. A `computed` over them therefore caches\n * its first value and never recomputes, which in a zoneless app means the\n * error block never appears at all. `control.events` is the reactive source\n * Angular does expose, so the computed depends on this counter instead.\n * Signal Forms needs none of this — its interop getters read live signals —\n * and harmlessly contributes no events.\n *\n * Events are not the whole story, which is what {@link ngAfterContentChecked} is for.\n */\n private readonly revision = signal(0);\n\n /** What the last check saw on a reactive control — see {@link ngAfterContentChecked}. */\n private seen: {\n readonly errors: ValidationErrors | null;\n readonly touched: boolean;\n readonly dirty: boolean;\n } | null = null;\n\n /**\n * Catch the changes a reactive control makes WITHOUT an event.\n *\n * `updateValueAndValidity({ emitEvent: false })`, `markAsTouched({ emitEvent: false })`\n * and their siblings change `errors`, `touched` and `dirty` and emit nothing, so the\n * subscription above never hears them and the message stays whatever it was. That is\n * not only an app's own silent write: Angular reports a custom control's PARSE errors\n * to a `FormControl` exactly that way — a validator re-run with `emitEvent: false` —\n * so a `wr-date-picker` refusing typed text made its control invalid while the field\n * went on showing the message from before, or nothing — and a later pass of change\n * detection did not help, because the message was memoised on a revision only events\n * move.\n *\n * This runs whenever the view holding the field is checked, which is when the page\n * around the control changes — for the date picker, the moment its refusal turns\n * visible. It is `ngAfterContentChecked` and not `ngDoCheck` for an ordering reason\n * read out of Angular's `refreshView`: check hooks run BEFORE the view's effects, and\n * Angular's parse-error validator is re-run from an effect in that same view, so a\n * `DoCheck` saw the errors one pass late and lost the message whenever nothing\n * refreshed the view again. Content-checked hooks run after those effects and before\n * the field's own bindings. Only a change moves the revision.\n *\n * Signal Forms' interop control is skipped: it is reactive already, and its `errors`\n * getter builds a fresh object on every read, which a reference check would call a\n * change on every pass — and re-resolve every message with it.\n */\n ngAfterContentChecked(): void {\n const control = this.ngControl()?.control;\n if (!(control instanceof AbstractControl)) {\n this.seen = null;\n return;\n }\n const { errors, touched, dirty } = control;\n const seen = this.seen;\n if (seen?.errors === errors && seen.touched === touched && seen.dirty === dirty) return;\n this.seen = { errors, touched, dirty };\n // The first sighting is only the baseline: `errors` reads `ngControl()`, so the\n // message already recomputed when the control appeared.\n if (seen) this.revision.update(n => n + 1);\n }\n\n constructor() {\n let sub: Subscription | null = null;\n effect(() => {\n const control = this.ngControl()?.control;\n sub?.unsubscribe();\n sub = (control?.events ?? EMPTY).subscribe(() => this.revision.update(n => n + 1));\n });\n inject(DestroyRef).onDestroy(() => sub?.unsubscribe());\n }\n\n protected readonly errors = computed(() => {\n this.revision();\n const c = this.ngControl();\n if (!c) return null;\n if (!c.touched && !c.dirty) return null;\n return c.errors;\n });\n\n protected readonly hasError = computed(() => {\n const errs = this.errors();\n return !!errs && Object.keys(errs).length > 0;\n });\n\n /** @internal Read by the projected `<wr-form-error>` children to decide which of them renders. */\n readonly errorKeys = computed<readonly string[]>(() => Object.keys(this.errors() ?? {}));\n\n /** @internal Read by the projected control so a screen reader is pointed at the message. */\n readonly describedBy = computed(() => (this.hasError() ? `${this.controlId()}-errors` : null));\n\n /**\n * @internal Read by the projected control so the hint is announced with the field.\n *\n * The hint used to carry no id at all, so the only thing `aria-describedby`\n * could ever name was the error block: the sentence explaining what to type was\n * on screen and reached a screen-reader user through no path whatsoever, and\n * the one gate that could have said so does not exist — axe has no rule that\n * visible help text must be programmatically associated.\n *\n * `null` while an error is showing, because the template swaps the hint out for\n * the message; publishing the id anyway would point every control at an element\n * that had just left the document.\n */\n readonly hintId = computed(() => (!this.hasError() && this.hint() ? `${this.controlId()}-hint` : null));\n\n /** @internal `WrFormFieldContext` — the id a role-based control points `aria-labelledby` at. */\n readonly labelId = computed(() => (this.label() ? `${this.controlId()}-label` : null));\n\n /**\n * Render a catalog message for any error the markup does not already answer.\n *\n * On by default: a field with no `<wr-form-error>` at all is the common case,\n * and an empty error block helps nobody. Turn it off for a field whose copy is\n * entirely hand-written. @default true\n */\n readonly autoErrors = input(true, { transform: coerceBooleanProperty });\n\n private readonly projectedErrors = contentChildren(WrFormError);\n private readonly appMessages = inject(WR_FORM_ERRORS);\n private readonly i18n = inject(WrI18n, { optional: true });\n\n /**\n * Errors with no projected `<wr-form-error key>` to answer them, resolved to\n * text: the app catalog first, then the `validation.*` i18n keys, then a\n * built-in English sentence. Per-field markup always wins — it is the most\n * specific thing the author wrote.\n */\n protected readonly autoMessages = computed<readonly { key: string; text: string }[]>(() => {\n if (!this.autoErrors()) return [];\n const errors = this.errors();\n if (!errors) return [];\n\n const claimed = new Set(\n this.projectedErrors()\n .map(e => e.key())\n .filter(Boolean)\n );\n\n return Object.entries(errors)\n .filter(([key]) => !claimed.has(key))\n .map(([key, error]) => ({ key, text: this.resolve(key, error) }))\n .filter(m => m.text.length > 0);\n });\n\n private resolve(rawKey: string, rawError: unknown): string {\n // A consumer's own map is consulted under BOTH spellings — theirs first, so\n // someone who already worked around this by writing `minLength` keeps\n // winning, and the normalised one after.\n const appRaw = this.appMessages[rawKey];\n if (appRaw !== undefined) return render(appRaw, rawKey, rawError, this.label());\n\n const { key, error } = normalizeError(rawKey, rawError);\n const app = this.appMessages[key];\n if (app !== undefined) return render(app, key, error, this.label());\n\n // `t()` reads the service's revision signal, so this recomputes on a locale\n // switch; a miss returns the key itself, which is the documented signal.\n const translated = this.i18n?.t(`validation.${key}`, toParams(error));\n if (translated && translated !== `validation.${key}`) return translated;\n\n const fallback = WR_FORM_ERROR_FALLBACKS[key];\n return fallback === undefined ? '' : render(fallback, key, error, this.label());\n }\n\n protected readonly classes = computed(() => {\n const parts = ['wr-form-field'];\n if (this.hasError()) parts.push('wr-form-field--invalid');\n if (this.required()) parts.push('wr-form-field--required');\n return parts.join(' ');\n });\n}\n","@if (label()) {\n <label class=\"wr-form-field__label\" [attr.id]=\"labelId()\" [attr.for]=\"labelFor()\">\n {{ label() }}\n @if (required()) {\n <span class=\"wr-form-field__required\" aria-hidden=\"true\">*</span>\n } @else if (optional()) {\n <span class=\"wr-form-field__optional\">({{ resolvedOptional() }})</span>\n }\n </label>\n}\n\n<div class=\"wr-form-field__control\"><ng-content /></div>\n\n@if (hasError()) {\n <div class=\"wr-form-field__errors\" [attr.id]=\"describedBy()\">\n <ng-content select=\"wr-form-error\" />\n @for (message of autoMessages(); track message.key) {\n <div class=\"wr-form-error wr-form-field__error\" role=\"alert\" [attr.data-key]=\"message.key\">\n {{ message.text }}\n </div>\n }\n </div>\n} @else if (hint()) {\n <small class=\"wr-form-field__hint\" [attr.id]=\"hintId()\">{{ hint() }}</small>\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { type Signal, computed, inject } from '@angular/core';\n\nimport { WR_FORM_FIELD } from './tokens';\n\n/** What {@link useFormFieldAria} hands a control to bind on its own element. */\nexport interface WrFormFieldAria {\n /**\n * Id of the field's message block while it is showing one, of its hint\n * otherwise, and `null` when it is showing neither.\n */\n readonly describedBy: Signal<string | null>;\n /** `'true'` while the field has a validation error, `null` otherwise. */\n readonly ariaInvalid: Signal<'true' | null>;\n /**\n * Id of the field's `<label>`, for a control `<label for>` cannot reach.\n *\n * `for` binds only to a LABELABLE element, so a control whose focusable part\n * is a `div` with a role gets nothing from it — measured, `wr-rating`,\n * `wr-knob` and `wr-file-upload` all rendered a field label whose `for` named\n * no element in the document. Point `aria-labelledby` at this instead; a\n * control that IS labelable should ignore it and let `for` do the work, or the\n * name is announced twice.\n */\n readonly labelledBy: Signal<string | null>;\n}\n\n/**\n * The two attributes that make a `<wr-form-field>`'s visible text — its error\n * message, or its hint — reach a screen reader. Bind both on whichever element\n * carries the control's role.\n *\n * Without them the copy the field renders is visible and nothing else: the\n * control announces itself as valid, and the text is associated with nothing.\n * No automated gate catches that — axe has no rule that a visible error or hint\n * must be programmatically associated with its control — so this helper exists\n * to make the wiring one line per control rather than three, and the specs are\n * the gate.\n *\n * The field renders an error OR a hint, never both, so `describedBy` names\n * whichever is on screen and `aria-invalid` is keyed SEPARATELY, on the field's\n * `errorKeys()`. Deriving it from `describedBy` instead — which is what every\n * control did while a hint had no id to name — makes a field with a plain hint\n * announce its control as invalid the moment the hint becomes describable.\n *\n * Must be called from an injection context (a field initialiser or a\n * constructor). Returns inert signals outside a `<wr-form-field>`.\n *\n * Pass `skipSelf` from a COMPOSITE control — one whose own template renders\n * other ngwr controls. Such a component shields its subtree by re-providing\n * `WR_FORM_FIELD` as `null`, or the inner parts each announce the outer field's\n * error as their own; a component sees its own providers, so it has to read the\n * real field from one level up.\n *\n * @example\n * ```ts\n * protected readonly fieldAria = useFormFieldAria();\n * ```\n * ```html\n * <input [attr.aria-invalid]=\"fieldAria.ariaInvalid()\" [attr.aria-describedby]=\"fieldAria.describedBy()\" />\n * ```\n */\nexport function useFormFieldAria(options?: { readonly skipSelf?: boolean }): WrFormFieldAria {\n const field = inject(WR_FORM_FIELD, { optional: true, skipSelf: options?.skipSelf ?? false });\n return {\n // `hintId` is optional on the interface so an app-provided field keeps\n // compiling; one without it describes nothing but its errors, as before.\n describedBy: computed(() => field?.describedBy() ?? field?.hintId?.() ?? null),\n ariaInvalid: computed<'true' | null>(() => ((field?.errorKeys().length ?? 0) > 0 ? 'true' : null)),\n // `null` for a control that `<label for>` already reaches — pointing at the\n // same label twice would name it twice. Only the role-based controls read\n // this, and only because `for` cannot bind to a role.\n labelledBy: computed(() => field?.labelId?.() ?? null),\n };\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { createMetadataKey } from '@angular/forms/signals';\n\n/**\n * How a field is DRAWN, attached to the same Signal Forms schema that already\n * says how it is validated.\n *\n * The alternative was a second schema — one for rules, one for presentation —\n * and it was rejected before it was written: two descriptions of one form drift\n * the moment someone renames a field in one of them, and nothing would report\n * it. Angular's `metadata()` takes a typed key and a `LogicFn`, so the\n * presentation rides on the schema the validators are already in, and it is\n * REACTIVE for free: a label, a set of options or a placeholder may depend on\n * the value of another field.\n *\n * What this deliberately does NOT carry: `required`, `disabled`, `readonly`,\n * `hidden`, `min`, `max`, and every validation rule. Those are Angular's own\n * schema functions, they already drive the control through `[formField]`, and\n * duplicating them here would create a second source of truth for state the form\n * already owns. That is not only a judgement call — Angular REFUSES a `[min]` or\n * `[required]` binding on a field-bound control (NG8022), so the second source\n * of truth is a compile error rather than a drift.\n */\nexport type WrFieldKind =\n 'input' | 'textarea' | 'number' | 'select' | 'checkbox' | 'switch' | 'radio' | 'date' | 'slider';\n\n/** One choice, for the kinds that offer a list. */\nexport interface WrFieldOption {\n readonly value: unknown;\n readonly label: string;\n readonly disabled?: boolean;\n}\n\n/**\n * The presentation of one field.\n *\n * `kind` is the only required member: everything else has a sane default, and a\n * schema that says no more than `{ kind: 'input' }` still renders a labelled,\n * error-bound control — the label falls back to the field's own name.\n */\nexport interface WrFieldSpec {\n readonly kind: WrFieldKind;\n /** Defaults to the field's key, de-camel-cased — `workEmail` becomes \"Work email\". */\n readonly label?: string;\n readonly placeholder?: string;\n /** Help text under the control. Errors replace it while the field is invalid. */\n readonly hint?: string;\n /** For `select` and `radio`. Ignored by every other kind. */\n readonly options?: readonly WrFieldOption[];\n /** Native `type` for `kind: 'input'` — `email`, `password`, `url`, `tel`. */\n readonly type?: string;\n /**\n * Granularity for `number` and `slider`. The BOUNDS are deliberately absent:\n * Angular refuses a `[min]` or `[max]` binding on a `[formField]`-bound\n * control outright (NG8022), because the field owns them — write `min(path.x,\n * 18)` in the schema and the control picks it up. `step` is presentation, has\n * no schema function, and stays here.\n */\n readonly step?: number;\n /**\n * Columns this field spans in `<wr-schema-form>`'s grid. Clamped to the form's\n * own `columns`, and 1 by default — a field is one cell unless it asks to be\n * wider.\n */\n readonly span?: number;\n}\n\n/**\n * The metadata key `<wr-schema-form>` reads.\n *\n * ```ts\n * const userSchema = schema<User>(path => {\n * required(path.email);\n * email(path.email);\n * metadata(path.email, WR_FIELD, () => ({ kind: 'input', type: 'email', label: 'Work email' }));\n * metadata(path.role, WR_FIELD, () => ({ kind: 'select', options: ROLES }));\n * });\n * ```\n *\n * A field with no `WR_FIELD` metadata is not an error and is not guessed at —\n * `<wr-schema-form>` skips it, so a schema can describe more than one screen shows.\n */\nexport const WR_FIELD = createMetadataKey<WrFieldSpec>();\n\n/** `workEmail` -> `Work email`. The fallback label, and only ever a fallback. */\nexport function wrFieldLabel(key: string): string {\n const spaced = key.replace(/([a-z\\d])([A-Z])/g, '$1 $2').replace(/[_-]+/g, ' ');\n return spaced.charAt(0).toUpperCase() + spaced.slice(1).toLowerCase();\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-fuzzy-text-testing.mjs","sources":["../../../projects/lib/fuzzy-text/testing/wr-fuzzy-text-harness.ts","../../../projects/lib/fuzzy-text/testing/ngwr-fuzzy-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 } from '@angular/cdk/testing';\n\nimport type { WrFuzzyTextHarnessFilters } from './interfaces';\n\n/**\n * Test harness for `<wr-fuzzy-text>` — a headline drawn into a canvas, one row of pixels\n * at a time, with a random offset per row.\n *\n * **The drawing is out of reach and the accessible half is not, which is the whole shape\n * of this harness.** There is no 2D context in a unit test — `getContext('2d')` returns\n * `null`, and the component's `init()` gives up on the line after — so nothing downstream\n * of that ever happens: no font load, no animation frame, no canvas listeners, no sizing.\n * What survives is the markup, and the markup is the part that regressed: everything this\n * component rendered used to be a canvas, so a screen reader got an empty element where\n * the page showed a headline. {@link getText} and {@link isDecorative} are that fix,\n * asserted as the PAIR it has to be — a readable copy plus a hidden pixel copy. Reading\n * one without the other passes just as happily on a component that announces the headline\n * twice.\n *\n * **The canvas is selected by tag, not by a class.** It carries no BEM name, unlike the\n * two sibling animation canvases — this entry point ships no stylesheet at all, which is\n * also why {@link isTextVisuallyHidden} is a real question rather than a formality.\n *\n * Nothing about the animation is offered, and none of it is a gap that could be closed by\n * trying harder. There is no `getIntensity()` / `isFuzzing()` / `isGlitching()`: those are\n * closure variables inside `init()` that only ever manifest as pixels, and in a test the\n * function returns before they exist. No `hover()` / `click()` / `getHoverIntensity()`:\n * the pointer listeners are attached only after a real context AND a resolved\n * `document.fonts` — neither of which a unit test has — so a dispatched event would land\n * on nothing and the assertion would pass vacuously; the hit test also measures the canvas\n * box, which is all zeros. No `getCanvasSize()`, which would be asserting jsdom's untouched\n * 300×150 default rather than the component's layout maths. No `getColor()` /\n * `getFontSize()` / `getFontFamily()` / `getGradient()`: every one of those becomes a\n * canvas font string or a fill style and never reaches the DOM. No `getRenderedText()` or\n * `readPixel()` — there are no pixels, and faking a context would change what every spec\n * here is testing. And no `isReducedMotion()`: the preference is honoured by taking a\n * different DRAWING path, with identical markup, classes and attributes either way, so the\n * method would answer the same for a component that honoured it and one that ignored it.\n *\n * @example\n * ```ts\n * const headline = await loader.getHarness(WrFuzzyTextHarness.with({ text: '404' }));\n *\n * expect(await headline.getText()).toBe('404');\n * expect(await headline.isDecorative()).toBe(true);\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrFuzzyTextHarness extends ComponentHarness {\n static hostSelector = 'wr-fuzzy-text';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrFuzzyTextHarnessFilters = {}): HarnessPredicate<WrFuzzyTextHarness> {\n return new HarnessPredicate(WrFuzzyTextHarness, options).addOption('text', options.text, (harness, text) =>\n HarnessPredicate.stringMatches(harness.getText(), text)\n );\n }\n\n private readonly srOnly = this.locatorFor('.wr-fuzzy-text__sr-only');\n private readonly canvas = this.locatorForOptional('canvas');\n\n /**\n * The headline as TEXT, trimmed.\n *\n * From the screen-reader span, which is the only place the string exists as characters —\n * the visible copy is glyphs painted into a canvas. This is the single assertion that\n * separates the component from an empty box for anyone not looking at the screen, and it\n * is the one that has already regressed once.\n *\n * There is no letter-by-letter split to worry about here, unlike the other text\n * animations in the library: the span holds one text node, so what a reader announces is\n * what {@link WrFuzzyTextHarness.getText} returns.\n */\n async getText(): Promise<string> {\n return (await this.srOnly()).text();\n }\n\n /**\n * Whether the pixel copy stays out of the accessibility tree.\n *\n * The other half of {@link getText}. The canvas has no text and no name, so without its\n * `aria-hidden` a reader meets an anonymous element next to the headline it already\n * read — or, if the span ever goes away again, only the anonymous element. Asserting the\n * two together is what pins the arrangement; asserting either alone does not.\n */\n async isDecorative(): Promise<boolean> {\n const canvas = await this.canvas();\n if (!canvas) {\n throw new Error(\n 'WrFuzzyTextHarness.isDecorative(): there is no <canvas> in this headline at all, so there is nothing to ' +\n 'keep out of the accessibility tree. That is a different failure from an announced canvas — ask ' +\n 'hasCanvas() to tell the two apart.'\n );\n }\n return (await canvas.getAttribute('aria-hidden')) === 'true';\n }\n\n /**\n * Whether the drawing surface is in the markup.\n *\n * True even where it can never be painted — under SSR, in a prerender, in a browser that\n * refuses a 2D context, and in every unit test — because the element is rendered\n * unconditionally and only the drawing depends on a context. That is precisely the state\n * the readable copy exists to cover, so this is the method that says \"the fallback is\n * carrying the page right now\".\n */\n async hasCanvas(): Promise<boolean> {\n return (await this.canvas()) !== null;\n }\n\n /**\n * Whether the readable copy hides itself without a stylesheet.\n *\n * This entry point ships no CSS. The span is therefore hidden with inline declarations\n * rather than an `.sr-only` class, and that is load-bearing rather than a style choice:\n * move the block into a class and every consumer who imported no CSS sees the headline\n * twice — once as pixels, once as a stray line of markup underneath.\n *\n * Three of the declarations are checked, not one, because they fail apart: `position`\n * takes the span out of flow, the 1px box collapses it, and `clip-path` is what keeps\n * the character still reachable by a reader instead of `display: none`-ing it away.\n */\n async isTextVisuallyHidden(): Promise<boolean> {\n const span = await this.srOnly();\n const [position, width, clipPath] = await Promise.all([\n span.getCssValue('position'),\n span.getCssValue('width'),\n span.getCssValue('clip-path'),\n ]);\n return position === 'absolute' && width === '1px' && clipPath === 'inset(50%)';\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;AAAA;;;;;AAKG;AAMH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CG;AACG,MAAO,kBAAmB,SAAQ,gBAAgB,CAAA;AACtD,IAAA,OAAO,YAAY,GAAG,eAAe;;AAGrC,IAAA,OAAO,IAAI,CAAC,OAAA,GAAqC,EAAE,EAAA;AACjD,QAAA,OAAO,IAAI,gBAAgB,CAAC,kBAAkB,EAAE,OAAO,CAAC,CAAC,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,IAAI,KACrG,gBAAgB,CAAC,aAAa,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,IAAI,CAAC,CACxD;IACH;AAEiB,IAAA,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,yBAAyB,CAAC;AACnD,IAAA,MAAM,GAAG,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC;AAE3D;;;;;;;;;;;AAWG;AACH,IAAA,MAAM,OAAO,GAAA;QACX,OAAO,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE;IACrC;AAEA;;;;;;;AAOG;AACH,IAAA,MAAM,YAAY,GAAA;AAChB,QAAA,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE;QAClC,IAAI,CAAC,MAAM,EAAE;YACX,MAAM,IAAI,KAAK,CACb,0GAA0G;gBACxG,iGAAiG;AACjG,gBAAA,oCAAoC,CACvC;QACH;QACA,OAAO,CAAC,MAAM,MAAM,CAAC,YAAY,CAAC,aAAa,CAAC,MAAM,MAAM;IAC9D;AAEA;;;;;;;;AAQG;AACH,IAAA,MAAM,SAAS,GAAA;QACb,OAAO,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,MAAM,IAAI;IACvC;AAEA;;;;;;;;;;;AAWG;AACH,IAAA,MAAM,oBAAoB,GAAA;AACxB,QAAA,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE;AAChC,QAAA,MAAM,CAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;AACpD,YAAA,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC;AAC5B,YAAA,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;AACzB,YAAA,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC;AAC9B,SAAA,CAAC;QACF,OAAO,QAAQ,KAAK,UAAU,IAAI,KAAK,KAAK,KAAK,IAAI,QAAQ,KAAK,YAAY;IAChF;;;AC1IF;;AAEG;;;;"}
1
+ {"version":3,"file":"ngwr-fuzzy-text-testing.mjs","sources":["../../../projects/lib/fuzzy-text/testing/wr-fuzzy-text-harness.ts","../../../projects/lib/fuzzy-text/testing/ngwr-fuzzy-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 } from '@angular/cdk/testing';\n\nimport type { WrFuzzyTextHarnessFilters } from './interfaces';\n\n/**\n * Test harness for `<wr-fuzzy-text>` — a headline drawn into a canvas, one row of pixels\n * at a time, with a random offset per row.\n *\n * **The drawing is out of reach and the accessible half is not, which is the whole shape\n * of this harness.** There is no 2D context in a unit test — `getContext('2d')` returns\n * `null`, and the component's `init()` gives up on the line after — so nothing downstream\n * of that ever happens: no font load, no animation frame, no canvas listeners, no sizing.\n * What survives is the markup, and the markup is the part that regressed: everything this\n * component rendered used to be a canvas, so a screen reader got an empty element where\n * the page showed a headline. {@link getText} and {@link isDecorative} are that fix,\n * asserted as the PAIR it has to be — a readable copy plus a hidden pixel copy. Reading\n * one without the other passes just as happily on a component that announces the headline\n * twice.\n *\n * **The canvas is selected by tag, not by a class.** It carries no BEM name, unlike the\n * two sibling animation canvases — this entry point ships no stylesheet at all, which is\n * also why {@link isTextVisuallyHidden} is a real question rather than a formality.\n *\n * Nothing about the animation is offered, and none of it is a gap that could be closed by\n * trying harder. There is no `getIntensity()` / `isFuzzing()` / `isGlitching()`: those are\n * closure variables inside `init()` that only ever manifest as pixels, and in a test the\n * function returns before they exist. No `hover()` / `click()` / `getHoverIntensity()`:\n * the pointer listeners are attached only after a real context AND a resolved\n * `document.fonts` — neither of which a unit test has — so a dispatched event would land\n * on nothing and the assertion would pass vacuously; the hit test also measures the canvas\n * box, which is all zeros. No `getCanvasSize()`, which would be asserting jsdom's untouched\n * 300×150 default rather than the component's layout maths. No `getColor()` /\n * `getFontSize()` / `getFontFamily()` / `getGradient()`: every one of those becomes a\n * canvas font string or a fill style and never reaches the DOM. No `getRenderedText()` or\n * `readPixel()` — there are no pixels, and faking a context would change what every spec\n * here is testing. And no `isReducedMotion()`: the preference is honoured by taking a\n * different DRAWING path, with identical markup, classes and attributes either way, so the\n * method would answer the same for a component that honoured it and one that ignored it.\n *\n * @example\n * ```ts\n * const headline = await loader.getHarness(WrFuzzyTextHarness.with({ text: '404' }));\n *\n * expect(await headline.getText()).toBe('404');\n * expect(await headline.isDecorative()).toBe(true);\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrFuzzyTextHarness extends ComponentHarness {\n static hostSelector = 'wr-fuzzy-text';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrFuzzyTextHarnessFilters = {}): HarnessPredicate<WrFuzzyTextHarness> {\n return new HarnessPredicate(WrFuzzyTextHarness, options).addOption('text', options.text, (harness, text) =>\n HarnessPredicate.stringMatches(harness.getText(), text)\n );\n }\n\n private readonly srOnly = this.locatorFor('.wr-fuzzy-text__sr-only');\n private readonly canvas = this.locatorForOptional('canvas');\n\n /**\n * The headline as TEXT, trimmed.\n *\n * From the screen-reader span, which is the only place the string exists as characters —\n * the visible copy is glyphs painted into a canvas. This is the single assertion that\n * separates the component from an empty box for anyone not looking at the screen, and it\n * is the one that has already regressed once.\n *\n * There is no letter-by-letter split to worry about here, unlike the other text\n * animations in the library: the span holds one text node, so what a reader announces is\n * what {@link WrFuzzyTextHarness.getText} returns.\n */\n async getText(): Promise<string> {\n return (await this.srOnly()).text();\n }\n\n /**\n * Whether the pixel copy stays out of the accessibility tree.\n *\n * The other half of {@link getText}. The canvas has no text and no name, so without its\n * `aria-hidden` a reader meets an anonymous element next to the headline it already\n * read — or, if the span ever goes away again, only the anonymous element. Asserting the\n * two together is what pins the arrangement; asserting either alone does not.\n */\n async isDecorative(): Promise<boolean> {\n const canvas = await this.canvas();\n if (!canvas) {\n throw new Error(\n 'WrFuzzyTextHarness.isDecorative(): there is no <canvas> in this headline at all, so there is nothing to ' +\n 'keep out of the accessibility tree. That is a different failure from an announced canvas — ask ' +\n 'hasCanvas() to tell the two apart.'\n );\n }\n return (await canvas.getAttribute('aria-hidden')) === 'true';\n }\n\n /**\n * Whether the drawing surface is in the markup.\n *\n * True even where it can never be painted — under SSR, in a prerender, in a browser that\n * refuses a 2D context, and in every unit test — because the element is rendered\n * unconditionally and only the drawing depends on a context. That is precisely the state\n * the readable copy exists to cover, so this is the method that says \"the fallback is\n * carrying the page right now\".\n */\n async hasCanvas(): Promise<boolean> {\n return (await this.canvas()) !== null;\n }\n\n /**\n * Whether the readable copy hides itself without a stylesheet.\n *\n * This entry point ships no CSS. The span is therefore hidden with inline declarations\n * rather than an `.sr-only` class, and that is load-bearing rather than a style choice:\n * move the block into a class and every consumer who imported no CSS sees the headline\n * twice — once as pixels, once as a stray line of markup underneath.\n *\n * Three of the declarations are checked, not one, because they fail apart: `position`\n * takes the span out of flow, the 1px box collapses it, and `clip-path` is what keeps\n * the character still reachable by a reader instead of `display: none`-ing it away.\n */\n async isTextVisuallyHidden(): Promise<boolean> {\n const span = await this.srOnly();\n const [position, width, clipPath] = await Promise.all([\n span.getCssValue('position'),\n span.getCssValue('width'),\n span.getCssValue('clip-path'),\n ]);\n return position === 'absolute' && width === '1px' && clipPath === 'inset(50%)';\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;AAAA;;;;;AAKG;AAMH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CG;AACG,MAAO,kBAAmB,SAAQ,gBAAgB,CAAA;AACtD,IAAA,OAAO,YAAY,GAAG,eAAe;;AAGrC,IAAA,OAAO,IAAI,CAAC,OAAA,GAAqC,EAAE,EAAA;AACjD,QAAA,OAAO,IAAI,gBAAgB,CAAC,kBAAkB,EAAE,OAAO,CAAC,CAAC,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,IAAI,KACrG,gBAAgB,CAAC,aAAa,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,IAAI,CAAC,CACxD;IACH;AAEiB,IAAA,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,yBAAyB,CAAC;AACnD,IAAA,MAAM,GAAG,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC;AAE3D;;;;;;;;;;;AAWG;AACH,IAAA,MAAM,OAAO,GAAA;QACX,OAAO,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE;IACrC;AAEA;;;;;;;AAOG;AACH,IAAA,MAAM,YAAY,GAAA;AAChB,QAAA,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE;QAClC,IAAI,CAAC,MAAM,EAAE;YACX,MAAM,IAAI,KAAK,CACb,0GAA0G;gBACxG,iGAAiG;AACjG,gBAAA,oCAAoC,CACvC;QACH;QACA,OAAO,CAAC,MAAM,MAAM,CAAC,YAAY,CAAC,aAAa,CAAC,MAAM,MAAM;IAC9D;AAEA;;;;;;;;AAQG;AACH,IAAA,MAAM,SAAS,GAAA;QACb,OAAO,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,MAAM,IAAI;IACvC;AAEA;;;;;;;;;;;AAWG;AACH,IAAA,MAAM,oBAAoB,GAAA;AACxB,QAAA,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE;AAChC,QAAA,MAAM,CAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;AACpD,YAAA,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC;AAC5B,YAAA,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;AACzB,YAAA,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC;AAC9B,SAAA,CAAC;QACF,OAAO,QAAQ,KAAK,UAAU,IAAI,KAAK,KAAK,KAAK,IAAI,QAAQ,KAAK,YAAY;IAChF;;;AC1IF;;AAEG;;"}
@@ -390,10 +390,10 @@ class WrFuzzyText {
390
390
  canvas.removeEventListener('click', onClick);
391
391
  };
392
392
  }
393
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrFuzzyText, deps: [], target: i0.ɵɵFactoryTarget.Component });
394
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.6", type: WrFuzzyText, isStandalone: true, selector: "wr-fuzzy-text", inputs: { text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: true, transformFunction: null }, fontSize: { classPropertyName: "fontSize", publicName: "fontSize", isSignal: true, isRequired: false, transformFunction: null }, fontWeight: { classPropertyName: "fontWeight", publicName: "fontWeight", isSignal: true, isRequired: false, transformFunction: null }, fontFamily: { classPropertyName: "fontFamily", publicName: "fontFamily", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, gradient: { classPropertyName: "gradient", publicName: "gradient", isSignal: true, isRequired: false, transformFunction: null }, enableHover: { classPropertyName: "enableHover", publicName: "enableHover", isSignal: true, isRequired: false, transformFunction: null }, baseIntensity: { classPropertyName: "baseIntensity", publicName: "baseIntensity", isSignal: true, isRequired: false, transformFunction: null }, hoverIntensity: { classPropertyName: "hoverIntensity", publicName: "hoverIntensity", isSignal: true, isRequired: false, transformFunction: null }, fuzzRange: { classPropertyName: "fuzzRange", publicName: "fuzzRange", isSignal: true, isRequired: false, transformFunction: null }, fps: { classPropertyName: "fps", publicName: "fps", isSignal: true, isRequired: false, transformFunction: null }, direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null }, transitionDuration: { classPropertyName: "transitionDuration", publicName: "transitionDuration", isSignal: true, isRequired: false, transformFunction: null }, clickEffect: { classPropertyName: "clickEffect", publicName: "clickEffect", isSignal: true, isRequired: false, transformFunction: null }, glitchMode: { classPropertyName: "glitchMode", publicName: "glitchMode", isSignal: true, isRequired: false, transformFunction: null }, glitchInterval: { classPropertyName: "glitchInterval", publicName: "glitchInterval", isSignal: true, isRequired: false, transformFunction: null }, glitchDuration: { classPropertyName: "glitchDuration", publicName: "glitchDuration", isSignal: true, isRequired: false, transformFunction: null }, letterSpacing: { classPropertyName: "letterSpacing", publicName: "letterSpacing", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.color": "'var(--wr-color-dark)'" }, classAttribute: "wr-fuzzy-text" }, viewQueries: [{ propertyName: "canvasRef", first: true, predicate: ["canvas"], descendants: true, isSignal: true }], ngImport: i0, template: "<span class=\"wr-fuzzy-text__sr-only\" [style]=\"srOnly\">{{ text() }}</span><canvas #canvas aria-hidden=\"true\"></canvas>", isInline: true, encapsulation: i0.ViewEncapsulation.None });
393
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrFuzzyText, deps: [], target: i0.ɵɵFactoryTarget.Component });
394
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.7", type: WrFuzzyText, isStandalone: true, selector: "wr-fuzzy-text", inputs: { text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: true, transformFunction: null }, fontSize: { classPropertyName: "fontSize", publicName: "fontSize", isSignal: true, isRequired: false, transformFunction: null }, fontWeight: { classPropertyName: "fontWeight", publicName: "fontWeight", isSignal: true, isRequired: false, transformFunction: null }, fontFamily: { classPropertyName: "fontFamily", publicName: "fontFamily", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, gradient: { classPropertyName: "gradient", publicName: "gradient", isSignal: true, isRequired: false, transformFunction: null }, enableHover: { classPropertyName: "enableHover", publicName: "enableHover", isSignal: true, isRequired: false, transformFunction: null }, baseIntensity: { classPropertyName: "baseIntensity", publicName: "baseIntensity", isSignal: true, isRequired: false, transformFunction: null }, hoverIntensity: { classPropertyName: "hoverIntensity", publicName: "hoverIntensity", isSignal: true, isRequired: false, transformFunction: null }, fuzzRange: { classPropertyName: "fuzzRange", publicName: "fuzzRange", isSignal: true, isRequired: false, transformFunction: null }, fps: { classPropertyName: "fps", publicName: "fps", isSignal: true, isRequired: false, transformFunction: null }, direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null }, transitionDuration: { classPropertyName: "transitionDuration", publicName: "transitionDuration", isSignal: true, isRequired: false, transformFunction: null }, clickEffect: { classPropertyName: "clickEffect", publicName: "clickEffect", isSignal: true, isRequired: false, transformFunction: null }, glitchMode: { classPropertyName: "glitchMode", publicName: "glitchMode", isSignal: true, isRequired: false, transformFunction: null }, glitchInterval: { classPropertyName: "glitchInterval", publicName: "glitchInterval", isSignal: true, isRequired: false, transformFunction: null }, glitchDuration: { classPropertyName: "glitchDuration", publicName: "glitchDuration", isSignal: true, isRequired: false, transformFunction: null }, letterSpacing: { classPropertyName: "letterSpacing", publicName: "letterSpacing", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.color": "'var(--wr-color-dark)'" }, classAttribute: "wr-fuzzy-text" }, viewQueries: [{ propertyName: "canvasRef", first: true, predicate: ["canvas"], descendants: true, isSignal: true }], ngImport: i0, template: "<span class=\"wr-fuzzy-text__sr-only\" [style]=\"srOnly\">{{ text() }}</span><canvas #canvas aria-hidden=\"true\"></canvas>", isInline: true, encapsulation: i0.ViewEncapsulation.None });
395
395
  }
396
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrFuzzyText, decorators: [{
396
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrFuzzyText, decorators: [{
397
397
  type: Component,
398
398
  args: [{
399
399
  selector: 'wr-fuzzy-text',