ngwr 11.2.0 → 12.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (395) hide show
  1. package/README.md +85 -26
  2. package/burger/styles/_index.scss +1 -1
  3. package/button/styles/_index.scss +2 -2
  4. package/calendar/styles/_index.scss +32 -12
  5. package/calendar-heatmap/styles/_index.scss +20 -0
  6. package/carousel/styles/_index.scss +23 -1
  7. package/cascader/styles/_index.scss +15 -3
  8. package/checkbox/styles/_index.scss +2 -2
  9. package/collapse/styles/_index.scss +2 -2
  10. package/color-picker/styles/_index.scss +3 -3
  11. package/compare/styles/_index.scss +18 -2
  12. package/context-menu/styles/_index.scss +21 -2
  13. package/date-picker/styles/_index.scss +5 -5
  14. package/descriptions/styles/_index.scss +1 -1
  15. package/drag-drop/styles/_index.scss +28 -1
  16. package/drawer/styles/_index.scss +37 -0
  17. package/dropdown/styles/_index.scss +2 -2
  18. package/event-calendar/styles/_index.scss +67 -10
  19. package/fesm2022/ngwr-action-sheet.mjs +3 -3
  20. package/fesm2022/ngwr-affix.mjs +3 -3
  21. package/fesm2022/ngwr-alert.mjs +3 -3
  22. package/fesm2022/ngwr-anchor.mjs +3 -3
  23. package/fesm2022/ngwr-aurora.mjs +3 -3
  24. package/fesm2022/ngwr-avatar.mjs +3 -3
  25. package/fesm2022/ngwr-back-top.mjs +3 -3
  26. package/fesm2022/ngwr-badge.mjs +6 -6
  27. package/fesm2022/ngwr-bar-chart-testing.mjs +20 -2
  28. package/fesm2022/ngwr-bar-chart-testing.mjs.map +1 -1
  29. package/fesm2022/ngwr-bar-chart.mjs +3 -3
  30. package/fesm2022/ngwr-blur-text.mjs +3 -3
  31. package/fesm2022/ngwr-blur-text.mjs.map +1 -1
  32. package/fesm2022/ngwr-border-glow.mjs +4 -4
  33. package/fesm2022/ngwr-border-glow.mjs.map +1 -1
  34. package/fesm2022/ngwr-breadcrumbs.mjs +29 -17
  35. package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
  36. package/fesm2022/ngwr-burger.mjs +3 -3
  37. package/fesm2022/ngwr-button.mjs +6 -6
  38. package/fesm2022/ngwr-calendar-heatmap.mjs +17 -5
  39. package/fesm2022/ngwr-calendar-heatmap.mjs.map +1 -1
  40. package/fesm2022/ngwr-calendar-testing.mjs +1 -1
  41. package/fesm2022/ngwr-calendar-testing.mjs.map +1 -1
  42. package/fesm2022/ngwr-calendar.mjs +187 -9
  43. package/fesm2022/ngwr-calendar.mjs.map +1 -1
  44. package/fesm2022/ngwr-card.mjs +10 -10
  45. package/fesm2022/ngwr-card.mjs.map +1 -1
  46. package/fesm2022/ngwr-carousel.mjs +124 -24
  47. package/fesm2022/ngwr-carousel.mjs.map +1 -1
  48. package/fesm2022/ngwr-cascader.mjs +48 -5
  49. package/fesm2022/ngwr-cascader.mjs.map +1 -1
  50. package/fesm2022/ngwr-checkbox.mjs +6 -6
  51. package/fesm2022/ngwr-circular-text.mjs +4 -4
  52. package/fesm2022/ngwr-circular-text.mjs.map +1 -1
  53. package/fesm2022/ngwr-click-spark.mjs +27 -7
  54. package/fesm2022/ngwr-click-spark.mjs.map +1 -1
  55. package/fesm2022/ngwr-clipboard.mjs +3 -3
  56. package/fesm2022/ngwr-collapse.mjs +9 -9
  57. package/fesm2022/ngwr-color-picker-testing.mjs +26 -6
  58. package/fesm2022/ngwr-color-picker-testing.mjs.map +1 -1
  59. package/fesm2022/ngwr-color-picker.mjs +98 -8
  60. package/fesm2022/ngwr-color-picker.mjs.map +1 -1
  61. package/fesm2022/ngwr-command-palette.mjs +14 -5
  62. package/fesm2022/ngwr-command-palette.mjs.map +1 -1
  63. package/fesm2022/ngwr-compare.mjs +3 -3
  64. package/fesm2022/ngwr-confetti.mjs +31 -6
  65. package/fesm2022/ngwr-confetti.mjs.map +1 -1
  66. package/fesm2022/ngwr-config.mjs +9 -0
  67. package/fesm2022/ngwr-config.mjs.map +1 -1
  68. package/fesm2022/ngwr-context-menu-testing.mjs +30 -11
  69. package/fesm2022/ngwr-context-menu-testing.mjs.map +1 -1
  70. package/fesm2022/ngwr-context-menu.mjs +333 -43
  71. package/fesm2022/ngwr-context-menu.mjs.map +1 -1
  72. package/fesm2022/ngwr-cookie.mjs +3 -3
  73. package/fesm2022/ngwr-counter.mjs +25 -9
  74. package/fesm2022/ngwr-counter.mjs.map +1 -1
  75. package/fesm2022/{ngwr-date-adapter-fns.mjs → ngwr-date-adapters-fns.mjs} +37 -10
  76. package/fesm2022/ngwr-date-adapters-fns.mjs.map +1 -0
  77. package/fesm2022/{ngwr-date-adapter-luxon.mjs → ngwr-date-adapters-luxon.mjs} +5 -5
  78. package/fesm2022/ngwr-date-adapters-luxon.mjs.map +1 -0
  79. package/fesm2022/ngwr-date-picker-testing.mjs +11 -6
  80. package/fesm2022/ngwr-date-picker-testing.mjs.map +1 -1
  81. package/fesm2022/ngwr-date-picker.mjs +119 -37
  82. package/fesm2022/ngwr-date-picker.mjs.map +1 -1
  83. package/fesm2022/{ngwr-date-adapter.mjs → ngwr-date.mjs} +36 -10
  84. package/fesm2022/ngwr-date.mjs.map +1 -0
  85. package/fesm2022/ngwr-decrypt-text.mjs +3 -3
  86. package/fesm2022/ngwr-density.mjs +6 -6
  87. package/fesm2022/ngwr-descriptions.mjs +6 -6
  88. package/fesm2022/ngwr-dialog.mjs +73 -18
  89. package/fesm2022/ngwr-dialog.mjs.map +1 -1
  90. package/fesm2022/ngwr-directives.mjs +12 -12
  91. package/fesm2022/ngwr-divider.mjs +52 -5
  92. package/fesm2022/ngwr-divider.mjs.map +1 -1
  93. package/fesm2022/ngwr-donut-chart-testing.mjs +8 -4
  94. package/fesm2022/ngwr-donut-chart-testing.mjs.map +1 -1
  95. package/fesm2022/ngwr-donut-chart.mjs +7 -7
  96. package/fesm2022/ngwr-donut-chart.mjs.map +1 -1
  97. package/fesm2022/ngwr-drag-drop.mjs +160 -11
  98. package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
  99. package/fesm2022/ngwr-drawer.mjs +121 -58
  100. package/fesm2022/ngwr-drawer.mjs.map +1 -1
  101. package/fesm2022/ngwr-dropdown.mjs +26 -10
  102. package/fesm2022/ngwr-dropdown.mjs.map +1 -1
  103. package/fesm2022/ngwr-empty.mjs +3 -3
  104. package/fesm2022/ngwr-event-calendar.mjs +28 -15
  105. package/fesm2022/ngwr-event-calendar.mjs.map +1 -1
  106. package/fesm2022/ngwr-falling-text-testing.mjs +5 -3
  107. package/fesm2022/ngwr-falling-text-testing.mjs.map +1 -1
  108. package/fesm2022/ngwr-falling-text.mjs +75 -46
  109. package/fesm2022/ngwr-falling-text.mjs.map +1 -1
  110. package/fesm2022/ngwr-file-upload.mjs +3 -3
  111. package/fesm2022/ngwr-form.mjs +32 -15
  112. package/fesm2022/ngwr-form.mjs.map +1 -1
  113. package/fesm2022/ngwr-fuzzy-text.mjs +21 -11
  114. package/fesm2022/ngwr-fuzzy-text.mjs.map +1 -1
  115. package/fesm2022/ngwr-gauge.mjs +3 -3
  116. package/fesm2022/ngwr-glitch-text-testing.mjs +51 -17
  117. package/fesm2022/ngwr-glitch-text-testing.mjs.map +1 -1
  118. package/fesm2022/ngwr-glitch-text.mjs +7 -7
  119. package/fesm2022/ngwr-glitch-text.mjs.map +1 -1
  120. package/fesm2022/ngwr-gradient-text-testing.mjs +46 -11
  121. package/fesm2022/ngwr-gradient-text-testing.mjs.map +1 -1
  122. package/fesm2022/ngwr-gradient-text.mjs +4 -4
  123. package/fesm2022/ngwr-gradient-text.mjs.map +1 -1
  124. package/fesm2022/ngwr-hotkey.mjs +24 -9
  125. package/fesm2022/ngwr-hotkey.mjs.map +1 -1
  126. package/fesm2022/ngwr-i18n-en.mjs +73 -1
  127. package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
  128. package/fesm2022/ngwr-i18n-ru.mjs +55 -1
  129. package/fesm2022/ngwr-i18n-ru.mjs.map +1 -1
  130. package/fesm2022/ngwr-i18n.mjs +26 -15
  131. package/fesm2022/ngwr-i18n.mjs.map +1 -1
  132. package/fesm2022/ngwr-icon.mjs +6 -6
  133. package/fesm2022/ngwr-image-cropper-testing.mjs +53 -9
  134. package/fesm2022/ngwr-image-cropper-testing.mjs.map +1 -1
  135. package/fesm2022/ngwr-image-cropper.mjs +150 -12
  136. package/fesm2022/ngwr-image-cropper.mjs.map +1 -1
  137. package/fesm2022/ngwr-input-number-testing.mjs +15 -10
  138. package/fesm2022/ngwr-input-number-testing.mjs.map +1 -1
  139. package/fesm2022/ngwr-input-number.mjs +17 -10
  140. package/fesm2022/ngwr-input-number.mjs.map +1 -1
  141. package/fesm2022/ngwr-input-otp-testing.mjs +12 -6
  142. package/fesm2022/ngwr-input-otp-testing.mjs.map +1 -1
  143. package/fesm2022/ngwr-input-otp.mjs +24 -5
  144. package/fesm2022/ngwr-input-otp.mjs.map +1 -1
  145. package/fesm2022/ngwr-input.mjs +15 -15
  146. package/fesm2022/ngwr-keyboard.mjs +3 -3
  147. package/fesm2022/ngwr-knob.mjs +3 -3
  148. package/fesm2022/ngwr-layout.mjs +15 -15
  149. package/fesm2022/ngwr-lightbox.mjs +4 -4
  150. package/fesm2022/ngwr-lightbox.mjs.map +1 -1
  151. package/fesm2022/ngwr-line-chart.mjs +73 -26
  152. package/fesm2022/ngwr-line-chart.mjs.map +1 -1
  153. package/fesm2022/ngwr-list.mjs +7 -7
  154. package/fesm2022/ngwr-list.mjs.map +1 -1
  155. package/fesm2022/ngwr-loading-bar.mjs +7 -7
  156. package/fesm2022/ngwr-loading-bar.mjs.map +1 -1
  157. package/fesm2022/ngwr-markdown.mjs +66 -8
  158. package/fesm2022/ngwr-markdown.mjs.map +1 -1
  159. package/fesm2022/ngwr-marquee.mjs +4 -4
  160. package/fesm2022/ngwr-marquee.mjs.map +1 -1
  161. package/fesm2022/ngwr-media.mjs +3 -3
  162. package/fesm2022/ngwr-mention.mjs +108 -13
  163. package/fesm2022/ngwr-mention.mjs.map +1 -1
  164. package/fesm2022/ngwr-meta.mjs +6 -6
  165. package/fesm2022/ngwr-meter-group-testing.mjs +26 -6
  166. package/fesm2022/ngwr-meter-group-testing.mjs.map +1 -1
  167. package/fesm2022/ngwr-meter-group.mjs +3 -3
  168. package/fesm2022/ngwr-overlay.mjs +6 -6
  169. package/fesm2022/ngwr-page-header.mjs +3 -3
  170. package/fesm2022/ngwr-pagination-testing.mjs +6 -6
  171. package/fesm2022/ngwr-pagination-testing.mjs.map +1 -1
  172. package/fesm2022/ngwr-pagination.mjs +83 -16
  173. package/fesm2022/ngwr-pagination.mjs.map +1 -1
  174. package/fesm2022/ngwr-pipes.mjs +39 -26
  175. package/fesm2022/ngwr-pipes.mjs.map +1 -1
  176. package/fesm2022/ngwr-platform.mjs +9 -9
  177. package/fesm2022/ngwr-popconfirm.mjs +6 -6
  178. package/fesm2022/ngwr-popover-testing.mjs +7 -2
  179. package/fesm2022/ngwr-popover-testing.mjs.map +1 -1
  180. package/fesm2022/ngwr-popover.mjs +155 -33
  181. package/fesm2022/ngwr-popover.mjs.map +1 -1
  182. package/fesm2022/ngwr-progress.mjs +3 -3
  183. package/fesm2022/ngwr-pull-to-refresh.mjs +3 -3
  184. package/fesm2022/ngwr-qr.mjs +42 -5
  185. package/fesm2022/ngwr-qr.mjs.map +1 -1
  186. package/fesm2022/ngwr-radio.mjs +6 -6
  187. package/fesm2022/ngwr-rating.mjs +3 -3
  188. package/fesm2022/ngwr-result.mjs +21 -30
  189. package/fesm2022/ngwr-result.mjs.map +1 -1
  190. package/fesm2022/ngwr-rotating-text.mjs +3 -3
  191. package/fesm2022/ngwr-scroll.mjs +3 -3
  192. package/fesm2022/ngwr-segmented-testing.mjs +85 -1
  193. package/fesm2022/ngwr-segmented-testing.mjs.map +1 -1
  194. package/fesm2022/ngwr-segmented.mjs +123 -10
  195. package/fesm2022/ngwr-segmented.mjs.map +1 -1
  196. package/fesm2022/ngwr-select.mjs +159 -34
  197. package/fesm2022/ngwr-select.mjs.map +1 -1
  198. package/fesm2022/ngwr-shiny-text.mjs +11 -9
  199. package/fesm2022/ngwr-shiny-text.mjs.map +1 -1
  200. package/fesm2022/ngwr-sidebar.mjs +31 -16
  201. package/fesm2022/ngwr-sidebar.mjs.map +1 -1
  202. package/fesm2022/ngwr-skeleton.mjs +3 -3
  203. package/fesm2022/ngwr-slider.mjs +100 -9
  204. package/fesm2022/ngwr-slider.mjs.map +1 -1
  205. package/fesm2022/ngwr-sparkline.mjs +3 -3
  206. package/fesm2022/ngwr-speed-dial-testing.mjs +15 -13
  207. package/fesm2022/ngwr-speed-dial-testing.mjs.map +1 -1
  208. package/fesm2022/ngwr-speed-dial.mjs +27 -12
  209. package/fesm2022/ngwr-speed-dial.mjs.map +1 -1
  210. package/fesm2022/ngwr-spinner.mjs +3 -3
  211. package/fesm2022/ngwr-splash-cursor.mjs +3 -3
  212. package/fesm2022/ngwr-split-text.mjs +17 -5
  213. package/fesm2022/ngwr-split-text.mjs.map +1 -1
  214. package/fesm2022/ngwr-splitter.mjs +3 -3
  215. package/fesm2022/ngwr-spotlight-card.mjs +7 -7
  216. package/fesm2022/ngwr-spotlight-card.mjs.map +1 -1
  217. package/fesm2022/ngwr-squircle.mjs +6 -6
  218. package/fesm2022/ngwr-star-border.mjs +4 -4
  219. package/fesm2022/ngwr-star-border.mjs.map +1 -1
  220. package/fesm2022/ngwr-statistic.mjs +9 -9
  221. package/fesm2022/ngwr-stepper-testing.mjs +8 -8
  222. package/fesm2022/ngwr-stepper-testing.mjs.map +1 -1
  223. package/fesm2022/ngwr-stepper.mjs +33 -8
  224. package/fesm2022/ngwr-stepper.mjs.map +1 -1
  225. package/fesm2022/ngwr-storage.mjs +17 -5
  226. package/fesm2022/ngwr-storage.mjs.map +1 -1
  227. package/fesm2022/ngwr-switch.mjs +3 -3
  228. package/fesm2022/ngwr-table.mjs +99 -39
  229. package/fesm2022/ngwr-table.mjs.map +1 -1
  230. package/fesm2022/ngwr-tabs-testing.mjs +11 -10
  231. package/fesm2022/ngwr-tabs-testing.mjs.map +1 -1
  232. package/fesm2022/ngwr-tabs.mjs +36 -10
  233. package/fesm2022/ngwr-tabs.mjs.map +1 -1
  234. package/fesm2022/ngwr-textarea.mjs +3 -3
  235. package/fesm2022/ngwr-theme.mjs +181 -4
  236. package/fesm2022/ngwr-theme.mjs.map +1 -1
  237. package/fesm2022/ngwr-tilt-card.mjs +7 -7
  238. package/fesm2022/ngwr-tilt-card.mjs.map +1 -1
  239. package/fesm2022/ngwr-timeline.mjs +6 -6
  240. package/fesm2022/ngwr-toast.mjs +9 -9
  241. package/fesm2022/ngwr-toolbar.mjs +3 -3
  242. package/fesm2022/ngwr-tour.mjs +34 -10
  243. package/fesm2022/ngwr-tour.mjs.map +1 -1
  244. package/fesm2022/ngwr-transfer.mjs +3 -3
  245. package/fesm2022/ngwr-tree.mjs +28 -10
  246. package/fesm2022/ngwr-tree.mjs.map +1 -1
  247. package/fesm2022/ngwr-typewriter-testing.mjs +15 -1
  248. package/fesm2022/ngwr-typewriter-testing.mjs.map +1 -1
  249. package/fesm2022/ngwr-typewriter.mjs +13 -5
  250. package/fesm2022/ngwr-typewriter.mjs.map +1 -1
  251. package/fesm2022/ngwr-typography.mjs +3 -3
  252. package/fesm2022/ngwr-utils.mjs +5 -2
  253. package/fesm2022/ngwr-utils.mjs.map +1 -1
  254. package/fesm2022/ngwr-version.mjs +1 -1
  255. package/fesm2022/ngwr-version.mjs.map +1 -1
  256. package/fesm2022/ngwr-virtual-scroll.mjs +4 -4
  257. package/fesm2022/ngwr-virtual-scroll.mjs.map +1 -1
  258. package/fesm2022/ngwr-waves.mjs +4 -4
  259. package/fesm2022/ngwr-waves.mjs.map +1 -1
  260. package/fesm2022/ngwr-window.mjs +94 -24
  261. package/fesm2022/ngwr-window.mjs.map +1 -1
  262. package/file-upload/styles/_index.scss +2 -2
  263. package/glitch-text/styles/_index.scss +27 -12
  264. package/i18n/en.json +56 -6
  265. package/i18n/ru.json +56 -6
  266. package/image-cropper/styles/_index.scss +19 -0
  267. package/input/styles/_index.scss +2 -2
  268. package/input-number/styles/_index.scss +2 -2
  269. package/input-otp/styles/_index.scss +9 -2
  270. package/knob/styles/_index.scss +1 -1
  271. package/lightbox/styles/_index.scss +16 -2
  272. package/line-chart/styles/_index.scss +28 -14
  273. package/list/styles/_index.scss +1 -1
  274. package/llms-full.txt +19 -24
  275. package/llms.txt +46 -8
  276. package/markdown/styles/_index.scss +3 -3
  277. package/mcp/api.js +6 -4
  278. package/mcp/catalog.js +40 -3
  279. package/mcp/providers.js +16 -3
  280. package/mcp/tools.js +21 -1
  281. package/meter-group/styles/_index.scss +1 -1
  282. package/overlay/styles/_index.scss +33 -1
  283. package/package.json +17 -12
  284. package/pagination/styles/_index.scss +23 -1
  285. package/popover/styles/_index.scss +16 -7
  286. package/progress/styles/_index.scss +1 -1
  287. package/radio/styles/_index.scss +2 -2
  288. package/rating/styles/_index.scss +1 -1
  289. package/schematics/collection.json +1 -1
  290. package/schematics/migrations/v12/index.js +65 -0
  291. package/schematics/migrations/v7/index.js +12 -1
  292. package/schematics/migrations/v8/index.js +10 -1
  293. package/schematics/migrations.json +5 -0
  294. package/schematics/ng-add/index.js +8 -3
  295. package/schematics/provider/index.js +80 -13
  296. package/schematics/use/index.js +9 -129
  297. package/schematics/use/rule.js +206 -0
  298. package/schematics/use/symbol-map.json +4 -4
  299. package/segmented/styles/_index.scss +14 -3
  300. package/select/styles/_index.scss +14 -2
  301. package/sidebar/styles/_index.scss +12 -10
  302. package/skills/ngwr/SKILL.md +7 -5
  303. package/skills/ngwr/references/catalog.md +9 -9
  304. package/skills/ngwr/references/setup.md +10 -5
  305. package/slider/styles/_index.scss +1 -1
  306. package/speed-dial/styles/_index.scss +1 -1
  307. package/stepper/styles/_index.scss +12 -3
  308. package/switch/styles/_index.scss +2 -2
  309. package/table/styles/_index.scss +61 -12
  310. package/tabs/styles/_index.scss +1 -1
  311. package/textarea/styles/_index.scss +1 -1
  312. package/theme/styles/_colors.scss +142 -56
  313. package/theme/styles/_dark.scss +46 -3
  314. package/theme/styles/_focus.scss +28 -5
  315. package/theme/styles/_mixins.scss +1 -1
  316. package/theme/styles/_variables.scss +67 -0
  317. package/transfer/styles/_index.scss +26 -3
  318. package/tree/styles/_index.scss +29 -6
  319. package/types/ngwr-bar-chart-testing.d.ts +9 -1
  320. package/types/ngwr-blur-text.d.ts +8 -4
  321. package/types/ngwr-breadcrumbs.d.ts +17 -10
  322. package/types/ngwr-calendar-testing.d.ts +1 -1
  323. package/types/ngwr-calendar.d.ts +66 -0
  324. package/types/ngwr-carousel.d.ts +85 -6
  325. package/types/ngwr-cascader.d.ts +17 -0
  326. package/types/ngwr-click-spark.d.ts +4 -0
  327. package/types/ngwr-color-picker-testing.d.ts +8 -0
  328. package/types/ngwr-color-picker.d.ts +21 -1
  329. package/types/ngwr-confetti.d.ts +8 -0
  330. package/types/ngwr-config.d.ts +10 -1
  331. package/types/ngwr-context-menu-testing.d.ts +24 -11
  332. package/types/ngwr-context-menu.d.ts +56 -0
  333. package/types/ngwr-counter.d.ts +1 -0
  334. package/types/{ngwr-date-adapter-fns.d.ts → ngwr-date-adapters-fns.d.ts} +33 -6
  335. package/types/{ngwr-date-adapter-luxon.d.ts → ngwr-date-adapters-luxon.d.ts} +1 -1
  336. package/types/ngwr-date-picker-testing.d.ts +11 -6
  337. package/types/ngwr-date-picker.d.ts +8 -4
  338. package/types/{ngwr-date-adapter.d.ts → ngwr-date.d.ts} +24 -5
  339. package/types/ngwr-dialog.d.ts +38 -1
  340. package/types/ngwr-divider.d.ts +25 -0
  341. package/types/ngwr-donut-chart-testing.d.ts +7 -3
  342. package/types/ngwr-donut-chart.d.ts +3 -3
  343. package/types/ngwr-drag-drop.d.ts +56 -2
  344. package/types/ngwr-drawer.d.ts +56 -5
  345. package/types/ngwr-event-calendar.d.ts +8 -2
  346. package/types/ngwr-falling-text-testing.d.ts +5 -3
  347. package/types/ngwr-falling-text.d.ts +1 -1
  348. package/types/ngwr-form.d.ts +12 -2
  349. package/types/ngwr-glitch-text-testing.d.ts +37 -8
  350. package/types/ngwr-gradient-text-testing.d.ts +16 -3
  351. package/types/ngwr-i18n.d.ts +13 -4
  352. package/types/ngwr-image-cropper-testing.d.ts +49 -10
  353. package/types/ngwr-image-cropper.d.ts +70 -5
  354. package/types/ngwr-input-number-testing.d.ts +15 -10
  355. package/types/ngwr-input-number.d.ts +11 -4
  356. package/types/ngwr-input-otp-testing.d.ts +12 -6
  357. package/types/ngwr-input-otp.d.ts +15 -1
  358. package/types/ngwr-line-chart.d.ts +20 -3
  359. package/types/ngwr-markdown.d.ts +11 -0
  360. package/types/ngwr-mention.d.ts +32 -0
  361. package/types/ngwr-meter-group-testing.d.ts +12 -2
  362. package/types/ngwr-overlay.d.ts +1 -0
  363. package/types/ngwr-pagination-testing.d.ts +4 -4
  364. package/types/ngwr-pagination.d.ts +11 -0
  365. package/types/ngwr-pipes.d.ts +1 -1
  366. package/types/ngwr-popover-testing.d.ts +7 -2
  367. package/types/ngwr-popover.d.ts +1 -0
  368. package/types/ngwr-result.d.ts +6 -0
  369. package/types/ngwr-segmented-testing.d.ts +53 -0
  370. package/types/ngwr-segmented.d.ts +107 -5
  371. package/types/ngwr-select.d.ts +68 -6
  372. package/types/ngwr-shiny-text.d.ts +4 -2
  373. package/types/ngwr-sidebar.d.ts +14 -5
  374. package/types/ngwr-slider.d.ts +69 -1
  375. package/types/ngwr-speed-dial-testing.d.ts +15 -11
  376. package/types/ngwr-speed-dial.d.ts +22 -3
  377. package/types/ngwr-split-text.d.ts +9 -0
  378. package/types/ngwr-stepper-testing.d.ts +5 -5
  379. package/types/ngwr-stepper.d.ts +8 -0
  380. package/types/ngwr-storage.d.ts +1 -0
  381. package/types/ngwr-table.d.ts +104 -11
  382. package/types/ngwr-tabs-testing.d.ts +11 -10
  383. package/types/ngwr-tabs.d.ts +2 -0
  384. package/types/ngwr-theme.d.ts +82 -1
  385. package/types/ngwr-tour.d.ts +22 -4
  386. package/types/ngwr-tree.d.ts +5 -4
  387. package/types/ngwr-typewriter-testing.d.ts +10 -0
  388. package/types/ngwr-utils.d.ts +5 -2
  389. package/types/ngwr-version.d.ts +1 -1
  390. package/types/ngwr-window.d.ts +39 -11
  391. package/typography/styles/_index.scss +1 -1
  392. package/window/styles/_index.scss +72 -26
  393. package/fesm2022/ngwr-date-adapter-fns.mjs.map +0 -1
  394. package/fesm2022/ngwr-date-adapter-luxon.mjs.map +0 -1
  395. package/fesm2022/ngwr-date-adapter.mjs.map +0 -1
@@ -48,6 +48,16 @@ interface WrDrawerOptions<D = unknown> {
48
48
  readonly closeOnBackdropClick?: boolean;
49
49
  /** When `true`, the Escape key closes the drawer. @default true */
50
50
  readonly closeOnEscape?: boolean;
51
+ /**
52
+ * When `true`, the drawer closes as soon as the URL changes — the Back button
53
+ * and any `router.navigate()` alike. Nothing else ties a drawer to the route
54
+ * it was opened on, so turning this off leaves the panel, its backdrop, its
55
+ * focus trap and the page-wide scroll block over whatever page the app
56
+ * navigates to. Turn it off only for a drawer that OWNS the navigation (a
57
+ * filter panel that keeps its state in the query string).
58
+ * @default true
59
+ */
60
+ readonly closeOnNavigation?: boolean;
51
61
  /**
52
62
  * Render a dismiss (×) button in the panel's top-right corner. Set `false`
53
63
  * when the content supplies its own close affordance. @default true
@@ -125,12 +135,33 @@ declare class WrDrawer {
125
135
  readonly closeLabel: _angular_core.InputSignal<string | null>;
126
136
  protected readonly resolvedCloseLabel: _angular_core.Signal<string>;
127
137
  protected readonly panelTpl: _angular_core.Signal<TemplateRef<any>>;
138
+ /**
139
+ * A projected `[wrDrawerTitle]`, if the consumer gave one.
140
+ *
141
+ * The dismiss button is corner chrome positioned at a fixed
142
+ * `inset-block-start` chosen to centre it on the TITLE's first line. With no
143
+ * title the content starts at the top of the panel and runs underneath it: on
144
+ * a bare `<wr-drawer><nav /></wr-drawer>` the button covered the first menu
145
+ * row by 24×16 px, and `elementFromPoint` at the button's centre returned the
146
+ * button, so that corner of the first item was unclickable. The panel has to
147
+ * know, because only the panel can reserve the space.
148
+ */
149
+ private readonly projectedTitle;
128
150
  protected panelClass(): string;
129
151
  private swipeStartX;
130
152
  private swipeStartY;
131
153
  private swiping;
132
154
  protected onSwipeStart(event: PointerEvent): void;
133
155
  protected onSwipeMove(event: PointerEvent, panel: HTMLElement): void;
156
+ /**
157
+ * A cancelled pointer is an ABANDONED swipe, not a completed one — the system
158
+ * took the gesture away (a call, a system gesture, an orientation change) and
159
+ * no `pointerup` ever arrives. Routing it through `onSwipeEnd` dismissed the
160
+ * drawer on an interruption the user did not ask for and, because the overlay
161
+ * is disposed with the dragged offset applied, could not take back. Same rule
162
+ * `wr-pull-to-refresh` states for `touchcancel`.
163
+ */
164
+ protected onSwipeCancel(panel: HTMLElement): void;
134
165
  protected onSwipeEnd(event: PointerEvent, panel: HTMLElement): void;
135
166
  /** Axis + sign of the closing direction for the current position. */
136
167
  private closeAxis;
@@ -158,7 +189,7 @@ declare class WrDrawer {
158
189
  private openOverlay;
159
190
  private closeOverlay;
160
191
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<WrDrawer, never>;
161
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<WrDrawer, "wr-drawer", never, { "open": { "alias": "open"; "required": false; "isSignal": true; }; "position": { "alias": "position"; "required": false; "isSignal": true; }; "width": { "alias": "width"; "required": false; "isSignal": true; }; "height": { "alias": "height"; "required": false; "isSignal": true; }; "maxHeight": { "alias": "maxHeight"; "required": false; "isSignal": true; }; "rounded": { "alias": "rounded"; "required": false; "isSignal": true; }; "showHandle": { "alias": "showHandle"; "required": false; "isSignal": true; }; "safeArea": { "alias": "safeArea"; "required": false; "isSignal": true; }; "hasBackdrop": { "alias": "hasBackdrop"; "required": false; "isSignal": true; }; "closeOnBackdropClick": { "alias": "closeOnBackdropClick"; "required": false; "isSignal": true; }; "closeOnEscape": { "alias": "closeOnEscape"; "required": false; "isSignal": true; }; "closable": { "alias": "closable"; "required": false; "isSignal": true; }; "closeLabel": { "alias": "closeLabel"; "required": false; "isSignal": true; }; }, { "open": "openChange"; }, never, ["*"], true, never>;
192
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<WrDrawer, "wr-drawer", never, { "open": { "alias": "open"; "required": false; "isSignal": true; }; "position": { "alias": "position"; "required": false; "isSignal": true; }; "width": { "alias": "width"; "required": false; "isSignal": true; }; "height": { "alias": "height"; "required": false; "isSignal": true; }; "maxHeight": { "alias": "maxHeight"; "required": false; "isSignal": true; }; "rounded": { "alias": "rounded"; "required": false; "isSignal": true; }; "showHandle": { "alias": "showHandle"; "required": false; "isSignal": true; }; "safeArea": { "alias": "safeArea"; "required": false; "isSignal": true; }; "hasBackdrop": { "alias": "hasBackdrop"; "required": false; "isSignal": true; }; "closeOnBackdropClick": { "alias": "closeOnBackdropClick"; "required": false; "isSignal": true; }; "closeOnEscape": { "alias": "closeOnEscape"; "required": false; "isSignal": true; }; "closable": { "alias": "closable"; "required": false; "isSignal": true; }; "closeLabel": { "alias": "closeLabel"; "required": false; "isSignal": true; }; }, { "open": "openChange"; }, ["projectedTitle"], ["*"], true, never>;
162
193
  }
163
194
 
164
195
  /**
@@ -265,14 +296,34 @@ declare class WrDrawerManager {
265
296
  private readonly focusTrapFactory;
266
297
  private readonly isBrowser;
267
298
  private readonly i18n;
299
+ private readonly location;
268
300
  open<C, R = unknown, D = unknown>(component: ComponentType<C>, options?: WrDrawerOptions<D>): WrDrawerRef<C, R>;
301
+ /**
302
+ * Tie the drawer's lifetime to the URL it was opened on — the same treatment
303
+ * `WrDialog` gets, and for the same reason.
304
+ *
305
+ * Nothing else does. The overlay belongs to a root service and is dismissed
306
+ * only by the backdrop, Escape, the appended × or an explicit `close()`, so
307
+ * navigating away left the panel, its backdrop, its focus trap and the
308
+ * page-wide scroll block sitting over a page the user never opened them on.
309
+ *
310
+ * `onUrlChange`, not `Location.subscribe()` — which is what CDK's own
311
+ * `disposeOnNavigation` uses: `subscribe` fires on popstate alone, so an in-app
312
+ * `router.navigate()` left the drawer standing. And `drawerRef.close()` rather
313
+ * than disposing the overlay behind the ref's back, which would never emit
314
+ * `closed`, never destroy the focus trap, and leave `awaitClose()` pending.
315
+ */
316
+ private watchNavigation;
269
317
  /**
270
318
  * The dismiss button's accessible name.
271
319
  *
272
- * Resolved per open, not once at injection: this is a root service, so a
273
- * `readI18nText` field — which is what `WrDialog` uses — would be evaluated
274
- * before an async catalog had loaded and then freeze that answer for the life
275
- * of the app.
320
+ * Resolved per open, not stored as a plain string at injection: this is a root
321
+ * service, so a one-shot read — which is what `WrDialog` used to have, and moved
322
+ * off for this reason — would run before an async catalog had loaded and then
323
+ * freeze that answer for the life of the app. (`readI18nText` hands back a signal
324
+ * now, so it would no longer freeze; the name still has to be pushed onto the
325
+ * button per open either way.) `WrDialog.closeLabel()` is the matching precedent,
326
+ * not the counter-example.
276
327
  *
277
328
  * The miss check is the point. `t()` hands back the KEY when the catalog has
278
329
  * no entry, and `WrI18n` is root-provided with an empty catalog by default —
@@ -101,8 +101,14 @@ interface TimeChip {
101
101
  readonly top: number;
102
102
  /** Height as a multiple of the cell, ×100. */
103
103
  readonly height: number;
104
- /** Horizontal share of the column, both 0–100. */
105
- readonly left: number;
104
+ /**
105
+ * Lane offset from the column's inline START, 0–100 — not from its physical
106
+ * left. Concurrent events are laid out in reading order, so under `dir="rtl"`
107
+ * lane 0 belongs at the right; a physical `left` would read the cluster
108
+ * back-to-front, which is the one thing in this component that was not logical.
109
+ */
110
+ readonly inlineStart: number;
111
+ /** Lane width as a share of the column, 0–100. */
106
112
  readonly width: number;
107
113
  readonly continuesBefore: boolean;
108
114
  readonly continuesAfter: boolean;
@@ -45,9 +45,11 @@ interface WrFallingTextHarnessFilters extends BaseHarnessFilters {
45
45
  * implementation would satisfy every naive test but not this one.
46
46
  *
47
47
  * **Nothing positional is offered, and that is not a jsdom concession.** The words'
48
- * `transform` values are one frame of a loop that never stops, seeded by `Math.random()`,
49
- * so they are not reproducible even in a real browser; there is no rest state to call
50
- * settled; the drag path needs `setPointerCapture` and AABB hit-testing over boxes that
48
+ * `transform` values are one frame of a physics loop seeded by `Math.random()`, so they
49
+ * are not reproducible even in a real browser; the loop parks once no word's transform
50
+ * changes any more, but where it parks is a different arrangement every run, and words
51
+ * packed tightly enough to keep jostling never reach that point at all; the drag path
52
+ * needs `setPointerCapture` and AABB hit-testing over boxes that
51
53
  * a unit test measures as 0×0 at the origin, where every word contains every point. Nor
52
54
  * is `[gravity]` or `[trigger]` readable — neither reaches the DOM, and answering them
53
55
  * would mean reaching into the component instance. There is no `isReducedMotion()`
@@ -52,7 +52,7 @@ declare class WrFallingText {
52
52
  }[]>;
53
53
  constructor();
54
54
  private start;
55
- /** Apply the body's position + angle to the DOM. */
55
+ /** Apply the body's position + angle to the DOM. `false` when it has not moved. */
56
56
  private commit;
57
57
  private toLocal;
58
58
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<WrFallingText, never>;
@@ -133,8 +133,18 @@ declare class WrFormField implements WrFormFieldContext {
133
133
  readonly hint: _angular_core.InputSignal<string>;
134
134
  /** Show a `*` next to the label. @default false */
135
135
  readonly required: _angular_core.InputSignalWithTransform<boolean, any>;
136
- /** Show `(optional)` next to the label. Mutually exclusive with `required`. @default false */
136
+ /**
137
+ * Show an "optional" marker next to the label — the word comes from
138
+ * `optionalLabel`. Mutually exclusive with `required`. @default false
139
+ */
137
140
  readonly optional: _angular_core.InputSignalWithTransform<boolean, any>;
141
+ /**
142
+ * Word inside the optional marker's parentheses. Falls back to
143
+ * `form.optional`, then `'optional'`. The parentheses are the template's, so
144
+ * no locale has to repeat punctuation.
145
+ */
146
+ readonly optionalLabel: _angular_core.InputSignal<string | null>;
147
+ protected readonly resolvedOptional: _angular_core.Signal<string>;
138
148
  /**
139
149
  * Force a specific id on the label's `for` attribute. Auto-generated
140
150
  * otherwise, and adopted by the projected `wrInput` unless that element
@@ -201,7 +211,7 @@ declare class WrFormField implements WrFormFieldContext {
201
211
  private resolve;
202
212
  protected readonly classes: _angular_core.Signal<string>;
203
213
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<WrFormField, never>;
204
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<WrFormField, "wr-form-field", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "optional": { "alias": "optional"; "required": false; "isSignal": true; }; "controlId": { "alias": "controlId"; "required": false; "isSignal": true; }; "autoErrors": { "alias": "autoErrors"; "required": false; "isSignal": true; }; }, {}, ["ngControl", "projectedErrors"], ["*", "wr-form-error"], true, never>;
214
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<WrFormField, "wr-form-field", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "optional": { "alias": "optional"; "required": false; "isSignal": true; }; "optionalLabel": { "alias": "optionalLabel"; "required": false; "isSignal": true; }; "controlId": { "alias": "controlId"; "required": false; "isSignal": true; }; "autoErrors": { "alias": "autoErrors"; "required": false; "isSignal": true; }; }, {}, ["ngControl", "projectedErrors"], ["*", "wr-form-error"], true, never>;
205
215
  }
206
216
 
207
217
  /**
@@ -45,10 +45,15 @@ interface WrGlitchTextColourSplit {
45
45
  *
46
46
  * **The one thing worth testing here is the pairing.** The two torn clones are
47
47
  * `::before` / `::after` pseudo-elements whose glyphs come from `content:
48
- * attr(data-text)`, so the string has to be in the host's text node AND in the host's
49
- * `data-text` attribute. Drop either binding and the visible text stays flawless while
50
- * the effect disappears — no error, no missing element, nothing else in the DOM
51
- * changes. {@link isCloneTextInSync} is that assertion in one call.
48
+ * attr(data-text)`, so the string has to be in `__label`'s text node AND in the
49
+ * `data-text` attribute on `__clones`. Drop either binding and the visible text stays
50
+ * flawless while the effect disappears — no error, no missing element, nothing else in
51
+ * the DOM changes. {@link isCloneTextInSync} is that assertion in one call.
52
+ *
53
+ * **Why they are two elements**, which is also why `data-text` is not on the host:
54
+ * generated content is exposed to the accessibility tree, so pseudos on the host made
55
+ * the string announce three times. `__clones` carries the `aria-hidden`;
56
+ * {@link isCloneLayerHidden} is the assertion that keeps it there.
52
57
  *
53
58
  * **Everything else the harness reads is an inline custom property**, because that is
54
59
  * everything the component writes: the two clone durations, the two colour-split
@@ -85,18 +90,22 @@ interface WrGlitchTextColourSplit {
85
90
  */
86
91
  declare class WrGlitchTextHarness extends ComponentHarness {
87
92
  static hostSelector: string;
93
+ /** The readable copy of the string — the only part of the component in the a11y tree. */
94
+ private readonly label;
95
+ /** The `aria-hidden` layer the two pseudo-clones hang off. */
96
+ private readonly clones;
88
97
  /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */
89
98
  static with(options?: WrGlitchTextHarnessFilters): HarnessPredicate<WrGlitchTextHarness>;
90
99
  /**
91
100
  * The rendered text, trimmed.
92
101
  *
93
102
  * The half a sighted user reads, and the half every other check would notice
94
- * breaking. The component interpolates the input straight onto the host, so there is
95
- * no inner element to query.
103
+ * breaking. Read off `__label`, which is the whole of the component's accessible
104
+ * content — the clone layer beside it is `aria-hidden` and empty in the DOM.
96
105
  */
97
106
  getText(): Promise<string>;
98
107
  /**
99
- * The string the two clone layers draw from — the host's `data-text`.
108
+ * The string the two clone layers draw from — `data-text` on `__clones`.
100
109
  *
101
110
  * The half nothing else notices. `content: attr(data-text)` is how both pseudo-clones
102
111
  * get their glyphs, so this attribute IS the effect. `null` means the mirror is gone
@@ -108,12 +117,23 @@ declare class WrGlitchTextHarness extends ComponentHarness {
108
117
  *
109
118
  * The component's defining silent failure, as a single assertion — two separate reads
110
119
  * are two things a spec can forget to write together. Compared raw on both sides,
111
- * with no trimming: the template is the bare interpolation, so the text node and the
120
+ * with no trimming: `__label` holds the bare interpolation, so its text node and the
112
121
  * attribute are byte-identical or the mirror is broken. An empty `text` is legal and
113
122
  * counts as in sync — `data-text=""` is a mirror of nothing, not a missing binding,
114
123
  * which is why {@link getCloneText} reports the absent case as `null` instead.
115
124
  */
116
125
  isCloneTextInSync(): Promise<boolean>;
126
+ /**
127
+ * Whether the clone layer is still hidden from assistive technology.
128
+ *
129
+ * The reason the component is two elements rather than one. `content: attr(data-text)`
130
+ * is exposed to the accessibility tree, so with the pseudos on the host the string was
131
+ * announced three times and a wrapping heading or link computed its name as
132
+ * "404 404 404". Nothing visual changes if the `aria-hidden` is dropped, and neither
133
+ * a11y gate in this repo can see it: `check:a11y` reads prerendered HTML with no
134
+ * stylesheets, and axe has no rule for duplicated generated content.
135
+ */
136
+ isCloneLayerHidden(): Promise<boolean>;
117
137
  /**
118
138
  * Whether the effect idles until the pointer arrives (`enableOnHover`).
119
139
  *
@@ -164,6 +184,15 @@ declare class WrGlitchTextHarness extends ComponentHarness {
164
184
  * the whole reason this reports the absent case as `null` instead of as a colour.
165
185
  */
166
186
  getSliceBackground(): Promise<string | null>;
187
+ /**
188
+ * One custom property off the host's `style` ATTRIBUTE.
189
+ *
190
+ * Not `getCssValue()`, which is `getComputedStyle`: with the entry point's own
191
+ * stylesheet loaded that resolves the sheet's declaration, so the method
192
+ * answers plausibly at exactly the moment the host binding — the thing under
193
+ * test — is what broke. The attribute holds only what the component wrote.
194
+ */
195
+ private inlineVar;
167
196
  /** One of the host's inline duration properties, as a number of seconds. */
168
197
  private seconds;
169
198
  }
@@ -38,6 +38,15 @@ interface WrGradientTextHarnessFilters extends BaseHarnessFilters {
38
38
  * included, because the duplicate is the thing worth asserting and stripping it would
39
39
  * hide the day it goes missing.
40
40
  *
41
+ * **The three custom properties are read off the `style` ATTRIBUTE, not through
42
+ * `getCssValue()`, and that is not a jsdom concession.** `.wr-gradient-text` declares
43
+ * its own `--wr-gradient-text-image`, `-size` and `-duration`, spelling out the same
44
+ * defaults the component computes — the three built-in stops with their wrap stop,
45
+ * `300% 100%`, `8s`. So with the stylesheet loaded a computed read answers with a
46
+ * perfectly healthy-looking value at exactly the moment the host binding is what broke,
47
+ * and every throw below goes unreachable. What the component wrote is the only value
48
+ * nothing else can forge.
49
+ *
41
50
  * **Direction is two facts, not one.** The modifier class says which way the gradient
42
51
  * travels and {@link getBackgroundSize} says which axis it was stretched along, and they
43
52
  * are computed separately: a direction change that forgets the size leaves every class
@@ -111,8 +120,9 @@ declare class WrGradientTextHarness extends ComponentHarness {
111
120
  * shows up here as four entries rather than one.
112
121
  *
113
122
  * Throws rather than guessing when the property holds something that is not a
114
- * `linear-gradient()` — an empty read means the host binding is gone, and a list of
115
- * fragments parsed out of the wreckage would look like a colour set.
123
+ * `linear-gradient()`, because a list of fragments parsed out of the wreckage would
124
+ * look like a colour set. A host that publishes no gradient at all throws one step
125
+ * earlier, from {@link getGradient}.
116
126
  */
117
127
  getColors(): Promise<string[]>;
118
128
  /**
@@ -130,7 +140,8 @@ declare class WrGradientTextHarness extends ComponentHarness {
130
140
  *
131
141
  * Proves the input reaches CSS at all, `numAttr` coercion included — a string attribute
132
142
  * arrives as a number and garbage falls back to the documented default. Throws when the
133
- * property holds no number, which is the only way the read can fail.
143
+ * property holds something that is not a number of seconds; a host that publishes no
144
+ * duration at all throws from the read itself.
134
145
  */
135
146
  getAnimationDurationSeconds(): Promise<number>;
136
147
  /**
@@ -167,6 +178,8 @@ declare class WrGradientTextHarness extends ComponentHarness {
167
178
  * arriving, which is the half that can go wrong in TypeScript.
168
179
  */
169
180
  pausesOnHover(): Promise<boolean>;
181
+ /** One of the host's own custom properties. See the class note on why this is not `getCssValue()`. */
182
+ private published;
170
183
  }
171
184
 
172
185
  export { WrGradientTextHarness };
@@ -380,11 +380,20 @@ declare function provideWrI18nHttpLoader(config: WrI18nHttpLoaderConfig): Provid
380
380
  */
381
381
  declare function useI18nText(binding: Signal<string | null | undefined>, key: string, fallback: string): Signal<string>;
382
382
  /**
383
- * Like {@link useI18nText} but takes a literal value (not a Signal) — for
384
- * computed `aria-label`s that already mix a static piece with a dynamic
385
- * value. Returns the resolved string once, at injection time.
383
+ * {@link useI18nText} without a binding to forward — for a built-in string the
384
+ * component exposes no override input for. Same reactivity, same fallback
385
+ * rules; the only difference is the missing first argument.
386
+ *
387
+ * It used to return a plain `string`, resolved once at injection time, and
388
+ * that was wrong in the ordinary case rather than an edge one: `WrI18n` writes
389
+ * every loader-backed catalog from `firstValueFrom(...).then(...)`, so even a
390
+ * static loader serving an object literal lands a microtask AFTER the first
391
+ * change-detection pass. Every component built in that pass read an empty
392
+ * catalog and froze its English fallback for the life of the app — in one
393
+ * `<wr-date-picker>` the field said "Открыть календарь" and the calendar
394
+ * button beside it "Open calendar", off the same key.
386
395
  */
387
- declare function readI18nText(key: string, fallback: string): string;
396
+ declare function readI18nText(key: string, fallback: string): Signal<string>;
388
397
  /**
389
398
  * Build a per-call formatter for parametrized labels (e.g. ARIA labels
390
399
  * that interpolate a per-row value: `"Remove {{label}}"`). Returns a
@@ -1,4 +1,4 @@
1
- import { BaseHarnessFilters, ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';
1
+ import { BaseHarnessFilters, TestKey, ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';
2
2
  import { WrCropHandle } from 'ngwr/image-cropper';
3
3
 
4
4
  /**
@@ -25,6 +25,14 @@ interface WrImageCropperHarnessFilters extends BaseHarnessFilters {
25
25
  * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
26
26
  */
27
27
 
28
+ declare const ARROWS: {
29
+ readonly left: TestKey.LEFT_ARROW;
30
+ readonly right: TestKey.RIGHT_ARROW;
31
+ readonly up: TestKey.UP_ARROW;
32
+ readonly down: TestKey.DOWN_ARROW;
33
+ };
34
+ /** The four directions the crop window's keyboard model understands. */
35
+ type WrCropArrow = keyof typeof ARROWS;
28
36
  /** Where the crop window sits over the DISPLAYED image, in CSS pixels. */
29
37
  interface WrCropWindowBox {
30
38
  readonly x: number;
@@ -41,13 +49,16 @@ interface WrCropWindowBox {
41
49
  * `naturalWidth`, converts between display and source pixels, and moves the crop
42
50
  * window with pointer deltas. jsdom measures nothing — every rect is 0×0 and
43
51
  * `naturalWidth` is 0 — so an image never "loads", the crop UI never renders, and a
44
- * synthetic drag divides by zero. There is deliberately no `moveCrop()` or
45
- * `resizeCrop()`: either would write `NaN` and report success.
52
+ * synthetic drag divides by zero. There is deliberately no drag method: it would
53
+ * write `NaN` and report success.
46
54
  *
47
55
  * What a spec CAN do is give the image a box and a natural size itself, then call
48
56
  * {@link dispatchImageLoad} — the two numbers `onImageLoad` reads are the whole
49
57
  * stub, and from there {@link getCropBox} and {@link getHandles} are real answers,
50
- * because the component writes the crop window's geometry as inline pixels.
58
+ * because the component writes the crop window's geometry as inline pixels. The
59
+ * KEYBOARD path needs the same stub to get the crop UI up, but nothing beyond it:
60
+ * its step is a constant rather than a pointer delta, so {@link pressArrow} lands
61
+ * on a number a spec can name.
51
62
  *
52
63
  * ```ts
53
64
  * // In your spec, before dispatching the load:
@@ -57,11 +68,13 @@ interface WrCropWindowBox {
57
68
  * Object.defineProperty(img, 'naturalHeight', { value: 800 });
58
69
  * ```
59
70
  *
60
- * **There is also nothing to click.** The cropper renders no buttons: a consumer
61
- * takes the result by calling `crop()` on the component through a `viewChild`, and
62
- * reads `cropRect()` the same way. Those are component API rather than DOM, so they
63
- * are outside what a harness can reach at all — which is worth knowing rather than
64
- * discovering.
71
+ * **There is nothing to click.** The cropper renders no buttons: the result
72
+ * arrives on the `(cropped)` output, which emits a `Blob` after each drag end or
73
+ * each run of arrow keys, and a consumer who wants a one-off read calls `toBlob()` /
74
+ * `toDataUrl()` — or `cropRect()` for the geometry — on the component through a
75
+ * `viewChild`. An output and three instance members: component API rather than DOM,
76
+ * so all of it is outside what a harness can reach at all, which is worth knowing
77
+ * rather than discovering.
65
78
  *
66
79
  * @example
67
80
  * ```ts
@@ -127,8 +140,34 @@ declare class WrImageCropperHarness extends ComponentHarness {
127
140
  getHandles(): Promise<WrCropHandle[]>;
128
141
  /** Whether the dimming backdrop with the cut-out is drawn. */
129
142
  hasBackdrop(): Promise<boolean>;
143
+ /**
144
+ * Press an arrow key on the crop window — one display pixel, or ten with
145
+ * `shift`; `alt` resizes from the east / south edge instead of moving.
146
+ *
147
+ * Sent to the crop window, where the component listens, so it does not depend on
148
+ * jsdom having managed to focus anything. `sendKeys` fires keyup as well as
149
+ * keydown, which is what makes `(cropped)` emit — the component treats a run of
150
+ * arrows as one gesture, the way a drag is one.
151
+ */
152
+ pressArrow(arrow: WrCropArrow, modifiers?: {
153
+ alt?: boolean;
154
+ shift?: boolean;
155
+ }): Promise<void>;
156
+ /** The crop window's accessible name. Comes from the catalog. */
157
+ getCropWindowLabel(): Promise<string | null>;
158
+ /**
159
+ * The last thing the live region announced — the crop rect in SOURCE pixels,
160
+ * as `x, y, width × height`.
161
+ *
162
+ * Empty until a key has moved the crop: a pointer drag deliberately says nothing
163
+ * (it would flood the region and the sighted user can see it), and the initial
164
+ * crop is not news. Two questions, not one — {@link getCropBox} reads the window's
165
+ * DISPLAY geometry, and a component that moved the box without announcing it
166
+ * would still pass that one.
167
+ */
168
+ getAnnouncement(): Promise<string>;
130
169
  private requireReady;
131
170
  }
132
171
 
133
172
  export { WrImageCropperHarness };
134
- export type { WrImageCropperHarnessFilters };
173
+ export type { WrCropArrow, WrCropWindowBox, WrImageCropperHarnessFilters };
@@ -30,8 +30,12 @@ interface RectPx {
30
30
  * the crop window or any of its eight handles. Optionally lock the crop
31
31
  * to a fixed `[aspectRatio]`.
32
32
  *
33
- * `(cropped)` fires after each drag end with a freshly-rendered `Blob`
34
- * of the cropped region. For one-off reads use `toBlob()` / `toDataUrl()`.
33
+ * The crop window is also the one tab stop: arrow keys move it, Alt with an
34
+ * arrow key resizes it, and Shift makes either step ten pixels instead of one.
35
+ *
36
+ * `(cropped)` fires after each drag end — or each run of arrow keys — with a
37
+ * freshly-rendered `Blob` of the cropped region. For one-off reads use
38
+ * `toBlob()` / `toDataUrl()`.
35
39
  *
36
40
  * @example
37
41
  * ```html
@@ -62,6 +66,15 @@ declare class WrImageCropper {
62
66
  protected readonly imgEl: _angular_core.Signal<ElementRef<HTMLImageElement>>;
63
67
  /** Resolved object URL for `src` (so File / Blob render in `<img>`). */
64
68
  protected readonly emptyText: _angular_core.Signal<string>;
69
+ /** Accessible name of the crop window — the component's only tab stop. */
70
+ protected readonly resolvedWindowLabel: _angular_core.Signal<string>;
71
+ /** The key model, referenced by the window's `aria-describedby`. */
72
+ protected readonly resolvedKeyHelp: _angular_core.Signal<string>;
73
+ /** Id linking the crop window to the help text. Random rather than counted:
74
+ * the crop UI only exists after a real image load, so it never prerenders. */
75
+ protected readonly helpId: string;
76
+ /** Live-region text — written by the keyboard path only (see `onWindowKeydown`). */
77
+ protected readonly announcement: _angular_core.WritableSignal<string>;
65
78
  protected readonly objectUrl: _angular_core.WritableSignal<string | null>;
66
79
  /** Previous object URL we created — kept off-signal so the resolve
67
80
  * effect doesn't depend on its own writes (which would loop). */
@@ -78,6 +91,8 @@ declare class WrImageCropper {
78
91
  }>;
79
92
  /** Crop rect in display coordinates. */
80
93
  protected readonly cropDisplay: _angular_core.WritableSignal<RectPx>;
94
+ /** Watches the rendered image box — see `watchResize`. */
95
+ private resizeObserver;
81
96
  /** Currently active drag handle. */
82
97
  private active;
83
98
  private startPointer;
@@ -91,18 +106,68 @@ declare class WrImageCropper {
91
106
  *
92
107
  * `display` is the field that gates everything downstream — the crop UI renders on
93
108
  * `display().w > 0` and `cropRect` returns zeros without it — so it is the only one
94
- * a test can observe. The other two are reset for coherence: anything that learns to
95
- * set `display` from elsewhere (a resize observer is the obvious candidate for this
96
- * component) would otherwise resurrect a crop measured against the previous image.
109
+ * a test can observe. The other two are reset for coherence: the resize observer
110
+ * below also writes `display`, and left alone they would resurrect a crop measured
111
+ * against the previous image (which is why `onResize` refuses to run on a zeroed
112
+ * `display` — see there).
97
113
  */
98
114
  private resetGeometry;
99
115
  protected onImageLoad(): void;
116
+ /**
117
+ * Keep `display` on the box the image is actually rendered at.
118
+ *
119
+ * The stylesheet sizes the image responsively — `max-width: 100%`,
120
+ * `max-height: 70dvh`, `height: auto` — so the single measurement taken in the
121
+ * `(load)` handler stops being true as soon as the container or the viewport
122
+ * changes. Everything the user sees and touches is in DISPLAY pixels: the crop
123
+ * window's inline `left` / `top` / `width` / `height`, the backdrop cut-out, and
124
+ * the bounds `applyMove` / `applyResize` clamp against. Measured once, a narrowed
125
+ * window leaves the crop painted past the edge of the image and draggable off it.
126
+ *
127
+ * Re-observed per load rather than once, because a new `src` may mount a new
128
+ * `<img>`; the old observation would then be on a detached element.
129
+ */
130
+ private watchResize;
131
+ /**
132
+ * Rescale the crop by however much the image did, so the user keeps the region
133
+ * they picked instead of having it re-centred: `cropRect()` — the source-pixel
134
+ * value a consumer acts on — comes out the same across the resize.
135
+ */
136
+ private onResize;
100
137
  /** Compute a sensible initial crop — centered, respecting aspectRatio. */
101
138
  private initialCrop;
102
139
  protected readonly handles: readonly WrCropHandle[];
103
140
  protected onPointerDown(handle: WrCropHandle, event: PointerEvent): void;
104
141
  protected onPointerMove(event: PointerEvent): void;
105
142
  protected onPointerUp(event: PointerEvent): void;
143
+ /** Whether a key has moved the crop since the last `keyup`. */
144
+ private keyboardDirty;
145
+ /**
146
+ * The component's only keyboard path. Arrow keys move the crop window; Alt
147
+ * with an arrow key resizes it from the east / south edge; Shift makes either
148
+ * one ten display pixels instead of one — the coarse modifier `wr-slider`,
149
+ * `wr-knob` and `wr-splitter` all use, which is why Alt and not Shift carries
150
+ * the mode switch here.
151
+ *
152
+ * Nothing mirrors under `dir="rtl"`: the image is not flipped and the window
153
+ * is placed with a physical `left`, so ArrowLeft moves the crop visually left
154
+ * in both directions.
155
+ *
156
+ * Both branches go through `applyMove` / `applyResize`, so the `aspectRatio`
157
+ * lock, the `minWidth` / `minHeight` floors and the canvas bounds hold for a
158
+ * keystroke exactly as they do for a drag. Those two measure from `startRect`
159
+ * rather than from the live rect, so it is re-seeded per keystroke — a 1px
160
+ * delta against the rect from the first press would make a held arrow stall
161
+ * after one pixel instead of accumulating.
162
+ */
163
+ protected onWindowKeydown(event: KeyboardEvent): void;
164
+ /**
165
+ * Emit once per gesture, not once per keystroke. A held arrow repeats its
166
+ * keydown many times a second and each `emitCropped` renders a canvas and
167
+ * encodes a Blob; `keyup` fires once when the run ends, which is the keyboard's
168
+ * equivalent of the `pointerup` the drag path emits on.
169
+ */
170
+ protected onWindowKeyup(): void;
106
171
  private applyMove;
107
172
  private applyResize;
108
173
  /** Render the current crop as a Blob. */
@@ -173,13 +173,17 @@ declare class WrInputNumberHarness extends ComponentHarness {
173
173
  /** The field's placeholder. */
174
174
  getPlaceholder(): Promise<string>;
175
175
  /**
176
- * The field's accessible name, or `null` when it has none of its own.
176
+ * The field's `aria-label`, or `null` when it carries none.
177
177
  *
178
178
  * Read from the native input, not from the host: an `aria-label` on a component
179
179
  * element does not reach the control inside it, which is why the component
180
- * takes an `ariaLabel` input and forwards it here (falling back to the
181
- * placeholder). Inside a `<wr-form-field>` the name comes from the label's
182
- * `for`, and `null` here is then correct rather than a missing name.
180
+ * takes an `ariaLabel` input and forwards it here.
181
+ *
182
+ * NOT the accessible name — `null` is the usual answer and usually correct.
183
+ * Nothing is forwarded unless `[ariaLabel]` is bound: inside a
184
+ * `<wr-form-field>` the name comes from the label's `for`, and standalone it
185
+ * comes from the `placeholder` (see {@link getPlaceholder}), neither of which
186
+ * is an attribute on this element.
183
187
  */
184
188
  getAriaLabel(): Promise<string | null>;
185
189
  /**
@@ -212,12 +216,13 @@ declare class WrInputNumberHarness extends ComponentHarness {
212
216
  /**
213
217
  * One of the two stepper buttons, BY POSITION — ▲ first, ▼ second.
214
218
  *
215
- * Not by `aria-label`: those strings ("Increment" / "Decrement") are still
216
- * hard-coded English, so keying on them would make this harness the thing that
217
- * breaks when they move into the i18n catalog — the same call
218
- * `WrTimePanelHarness` makes about its own columns. Order is the layout
219
- * contract, and the spec pins it by asserting which way each button moves the
220
- * value.
219
+ * Not by `aria-label`: those strings resolve through the i18n catalog
220
+ * (`inputNumber.increment` / `.decrement`) and an `[incrementLabel]` /
221
+ * `[decrementLabel]` binding overrides them, so keying on them would make this
222
+ * harness answer in whatever locale the app under test is configured for — the
223
+ * same call `WrTimePanelHarness` makes about its own columns. Order is the
224
+ * layout contract, and the spec pins it by asserting which way each button
225
+ * moves the value.
221
226
  */
222
227
  private stepButton;
223
228
  }
@@ -14,7 +14,7 @@ import { WrInputSize } from 'ngwr/input';
14
14
  * re-formats with grouping + fixed decimals on blur.
15
15
  *
16
16
  * Locale comes from Angular's `LOCALE_ID` — input-number intentionally does
17
- * NOT depend on `ngwr/date-adapter` so it can be used in date-free apps.
17
+ * NOT depend on `ngwr/date` so it can be used in date-free apps.
18
18
  *
19
19
  * @example
20
20
  * ```html
@@ -73,9 +73,16 @@ declare class WrInputNumber implements FormValueControl<number | null> {
73
73
  /** Placeholder shown when the input is empty. */
74
74
  readonly placeholder: _angular_core.InputSignal<string>;
75
75
  /**
76
- * Accessible name for the field. Falls back to the placeholder — inside a
77
- * `<wr-form-field>` the projected `wrInput` picks up the label's id and needs
78
- * neither, but standalone the text field has no name at all.
76
+ * Accessible name for the field. Unset, the field is named by whatever labels
77
+ * it — there is deliberately no fallback here.
78
+ *
79
+ * It used to mirror the `placeholder`, and an `aria-label` OUTRANKS a
80
+ * `<label>` in the accname order: inside a `<wr-form-field label="Quantity">`
81
+ * the very input that adopts the field's id announced the placeholder ("0")
82
+ * instead, and a placeholder disappears as soon as the user types. Standalone
83
+ * nothing was lost by dropping it — an input with no other name already falls
84
+ * back to its own `placeholder` attribute, which is the name axe's `label`
85
+ * rule accepts too.
79
86
  */
80
87
  readonly ariaLabel: _angular_core.InputSignal<string | null>;
81
88
  protected readonly resolvedAriaLabel: _angular_core.Signal<string | null>;