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
@@ -135,10 +135,10 @@ class WrStatistic {
135
135
  return `${sign}${d}${this.deltaSuffix()}`;
136
136
  }, /* @ts-ignore */
137
137
  ...(ngDevMode ? [{ debugName: "deltaText" }] : /* istanbul ignore next */ []));
138
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrStatistic, deps: [], target: i0.ɵɵFactoryTarget.Component });
139
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: WrStatistic, isStandalone: true, selector: "wr-statistic", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, prefix: { classPropertyName: "prefix", publicName: "prefix", isSignal: true, isRequired: false, transformFunction: null }, suffix: { classPropertyName: "suffix", publicName: "suffix", isSignal: true, isRequired: false, transformFunction: null }, precision: { classPropertyName: "precision", publicName: "precision", isSignal: true, isRequired: false, transformFunction: null }, animate: { classPropertyName: "animate", publicName: "animate", isSignal: true, isRequired: false, transformFunction: null }, duration: { classPropertyName: "duration", publicName: "duration", isSignal: true, isRequired: false, transformFunction: null }, delta: { classPropertyName: "delta", publicName: "delta", isSignal: true, isRequired: false, transformFunction: null }, deltaSuffix: { classPropertyName: "deltaSuffix", publicName: "deltaSuffix", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "wr-statistic" }, ngImport: i0, template: "@if (label()) {\n <div class=\"wr-statistic__label\">{{ label() }}</div>\n}\n<div class=\"wr-statistic__value\">\n @if (prefix()) {\n <span class=\"wr-statistic__prefix\">{{ prefix() }}</span>\n }\n @if (animated()) {\n <wr-count-up\n class=\"wr-statistic__number\"\n [from]=\"animateFrom()\"\n [to]=\"numericValue() ?? 0\"\n [decimals]=\"precision()\"\n [duration]=\"duration()\"\n />\n } @else {\n <span class=\"wr-statistic__number\">{{ displayValue() }}</span>\n }\n @if (suffix()) {\n <span class=\"wr-statistic__suffix\">{{ suffix() }}</span>\n }\n</div>\n@if (hasDelta()) {\n <div [class]=\"`wr-statistic__delta wr-statistic__delta--${deltaDirection()}`\">\n @if (deltaDirection() === 'up') {\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <path d=\"M5 1 L9 8 L1 8 Z\" fill=\"currentColor\" />\n </svg>\n } @else if (deltaDirection() === 'down') {\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <path d=\"M5 9 L9 2 L1 2 Z\" fill=\"currentColor\" />\n </svg>\n }\n <span>{{ deltaText() }}</span>\n </div>\n}\n", dependencies: [{ kind: "component", type: WrCountUp, selector: "wr-count-up", inputs: ["from", "to", "duration", "delay", "easing", "trigger", "direction", "decimals", "prefix", "suffix", "grouping"], outputs: ["started", "completed"] }], encapsulation: i0.ViewEncapsulation.None });
138
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrStatistic, deps: [], target: i0.ɵɵFactoryTarget.Component });
139
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: WrStatistic, isStandalone: true, selector: "wr-statistic", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, prefix: { classPropertyName: "prefix", publicName: "prefix", isSignal: true, isRequired: false, transformFunction: null }, suffix: { classPropertyName: "suffix", publicName: "suffix", isSignal: true, isRequired: false, transformFunction: null }, precision: { classPropertyName: "precision", publicName: "precision", isSignal: true, isRequired: false, transformFunction: null }, animate: { classPropertyName: "animate", publicName: "animate", isSignal: true, isRequired: false, transformFunction: null }, duration: { classPropertyName: "duration", publicName: "duration", isSignal: true, isRequired: false, transformFunction: null }, delta: { classPropertyName: "delta", publicName: "delta", isSignal: true, isRequired: false, transformFunction: null }, deltaSuffix: { classPropertyName: "deltaSuffix", publicName: "deltaSuffix", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "wr-statistic" }, ngImport: i0, template: "@if (label()) {\n <div class=\"wr-statistic__label\">{{ label() }}</div>\n}\n<div class=\"wr-statistic__value\">\n @if (prefix()) {\n <span class=\"wr-statistic__prefix\">{{ prefix() }}</span>\n }\n @if (animated()) {\n <wr-count-up\n class=\"wr-statistic__number\"\n [from]=\"animateFrom()\"\n [to]=\"numericValue() ?? 0\"\n [decimals]=\"precision()\"\n [duration]=\"duration()\"\n />\n } @else {\n <span class=\"wr-statistic__number\">{{ displayValue() }}</span>\n }\n @if (suffix()) {\n <span class=\"wr-statistic__suffix\">{{ suffix() }}</span>\n }\n</div>\n@if (hasDelta()) {\n <div [class]=\"`wr-statistic__delta wr-statistic__delta--${deltaDirection()}`\">\n @if (deltaDirection() === 'up') {\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <path d=\"M5 1 L9 8 L1 8 Z\" fill=\"currentColor\" />\n </svg>\n } @else if (deltaDirection() === 'down') {\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <path d=\"M5 9 L9 2 L1 2 Z\" fill=\"currentColor\" />\n </svg>\n }\n <span>{{ deltaText() }}</span>\n </div>\n}\n", dependencies: [{ kind: "component", type: WrCountUp, selector: "wr-count-up", inputs: ["from", "to", "duration", "delay", "easing", "trigger", "direction", "decimals", "prefix", "suffix", "grouping"], outputs: ["started", "completed"] }], encapsulation: i0.ViewEncapsulation.None });
140
140
  }
141
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrStatistic, decorators: [{
141
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrStatistic, decorators: [{
142
142
  type: Component,
143
143
  args: [{ selector: 'wr-statistic', encapsulation: ViewEncapsulation.None, host: { class: 'wr-statistic' }, imports: [WrCountUp], template: "@if (label()) {\n <div class=\"wr-statistic__label\">{{ label() }}</div>\n}\n<div class=\"wr-statistic__value\">\n @if (prefix()) {\n <span class=\"wr-statistic__prefix\">{{ prefix() }}</span>\n }\n @if (animated()) {\n <wr-count-up\n class=\"wr-statistic__number\"\n [from]=\"animateFrom()\"\n [to]=\"numericValue() ?? 0\"\n [decimals]=\"precision()\"\n [duration]=\"duration()\"\n />\n } @else {\n <span class=\"wr-statistic__number\">{{ displayValue() }}</span>\n }\n @if (suffix()) {\n <span class=\"wr-statistic__suffix\">{{ suffix() }}</span>\n }\n</div>\n@if (hasDelta()) {\n <div [class]=\"`wr-statistic__delta wr-statistic__delta--${deltaDirection()}`\">\n @if (deltaDirection() === 'up') {\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <path d=\"M5 1 L9 8 L1 8 Z\" fill=\"currentColor\" />\n </svg>\n } @else if (deltaDirection() === 'down') {\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <path d=\"M5 9 L9 2 L1 2 Z\" fill=\"currentColor\" />\n </svg>\n }\n <span>{{ deltaText() }}</span>\n </div>\n}\n" }]
144
144
  }], ctorParameters: () => [], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], prefix: [{ type: i0.Input, args: [{ isSignal: true, alias: "prefix", required: false }] }], suffix: [{ type: i0.Input, args: [{ isSignal: true, alias: "suffix", required: false }] }], precision: [{ type: i0.Input, args: [{ isSignal: true, alias: "precision", required: false }] }], animate: [{ type: i0.Input, args: [{ isSignal: true, alias: "animate", required: false }] }], duration: [{ type: i0.Input, args: [{ isSignal: true, alias: "duration", required: false }] }], delta: [{ type: i0.Input, args: [{ isSignal: true, alias: "delta", required: false }] }], deltaSuffix: [{ type: i0.Input, args: [{ isSignal: true, alias: "deltaSuffix", required: false }] }] } });
@@ -290,10 +290,10 @@ class WrStatisticCountdown {
290
290
  this.countdownEnd.emit();
291
291
  }
292
292
  }
293
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrStatisticCountdown, deps: [], target: i0.ɵɵFactoryTarget.Component });
294
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: WrStatisticCountdown, isStandalone: true, selector: "wr-statistic-countdown", inputs: { target: { classPropertyName: "target", publicName: "target", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, endText: { classPropertyName: "endText", publicName: "endText", isSignal: true, isRequired: false, transformFunction: null }, tickMs: { classPropertyName: "tickMs", publicName: "tickMs", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { countdownEnd: "countdownEnd" }, host: { classAttribute: "wr-statistic" }, ngImport: i0, template: "@if (label()) {\n <div class=\"wr-statistic__label\">{{ label() }}</div>\n}\n<div class=\"wr-statistic__value\">\n <span class=\"wr-statistic__number\">{{ display() }}</span>\n</div>\n", encapsulation: i0.ViewEncapsulation.None });
293
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrStatisticCountdown, deps: [], target: i0.ɵɵFactoryTarget.Component });
294
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: WrStatisticCountdown, isStandalone: true, selector: "wr-statistic-countdown", inputs: { target: { classPropertyName: "target", publicName: "target", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, endText: { classPropertyName: "endText", publicName: "endText", isSignal: true, isRequired: false, transformFunction: null }, tickMs: { classPropertyName: "tickMs", publicName: "tickMs", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { countdownEnd: "countdownEnd" }, host: { classAttribute: "wr-statistic" }, ngImport: i0, template: "@if (label()) {\n <div class=\"wr-statistic__label\">{{ label() }}</div>\n}\n<div class=\"wr-statistic__value\">\n <span class=\"wr-statistic__number\">{{ display() }}</span>\n</div>\n", encapsulation: i0.ViewEncapsulation.None });
295
295
  }
296
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrStatisticCountdown, decorators: [{
296
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrStatisticCountdown, decorators: [{
297
297
  type: Component,
298
298
  args: [{ selector: 'wr-statistic-countdown', encapsulation: ViewEncapsulation.None, host: { class: 'wr-statistic' }, template: "@if (label()) {\n <div class=\"wr-statistic__label\">{{ label() }}</div>\n}\n<div class=\"wr-statistic__value\">\n <span class=\"wr-statistic__number\">{{ display() }}</span>\n</div>\n" }]
299
299
  }], ctorParameters: () => [], propDecorators: { target: [{ type: i0.Input, args: [{ isSignal: true, alias: "target", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], endText: [{ type: i0.Input, args: [{ isSignal: true, alias: "endText", required: false }] }], tickMs: [{ type: i0.Input, args: [{ isSignal: true, alias: "tickMs", required: false }] }], countdownEnd: [{ type: i0.Output, args: ["countdownEnd"] }] } });
@@ -336,10 +336,10 @@ class WrStatisticGroup {
336
336
  * width allows. @default 0
337
337
  */
338
338
  columns = input(0, { ...(ngDevMode ? { debugName: "columns" } : /* istanbul ignore next */ {}), transform: (v) => Math.max(0, coerceNumberProperty(v, 0)) });
339
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrStatisticGroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
340
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.1", type: WrStatisticGroup, isStandalone: true, selector: "wr-statistic-group", inputs: { min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.--wr-statistic-group-min": "min()", "style.--wr-statistic-group-columns": "columns() || null" }, classAttribute: "wr-statistic-group" }, ngImport: i0, template: '<div class="wr-statistic-group__grid"><ng-content /></div>', isInline: true, encapsulation: i0.ViewEncapsulation.None });
339
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrStatisticGroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
340
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.4", type: WrStatisticGroup, isStandalone: true, selector: "wr-statistic-group", inputs: { min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.--wr-statistic-group-min": "min()", "style.--wr-statistic-group-columns": "columns() || null" }, classAttribute: "wr-statistic-group" }, ngImport: i0, template: '<div class="wr-statistic-group__grid"><ng-content /></div>', isInline: true, encapsulation: i0.ViewEncapsulation.None });
341
341
  }
342
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrStatisticGroup, decorators: [{
342
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrStatisticGroup, decorators: [{
343
343
  type: Component,
344
344
  args: [{
345
345
  selector: 'wr-statistic-group',
@@ -280,11 +280,11 @@ class WrStepperHarness extends ComponentHarness {
280
280
  * The index of the step the wizard is showing, from the header announcing
281
281
  * `aria-current="step"`.
282
282
  *
283
- * Throws when no header does, which is a state a stepper can genuinely be in: the
284
- * `active` model is two-way, `WrStepper.goTo()` clamps an out-of-range index but a
285
- * host writing `active` directly does not, and an index past the last step leaves
286
- * every header un-current and every step body hidden. A `-1` here would be read as
287
- * "the first step" by the next line of a spec.
283
+ * Throws when no header does, which is a state a stepper can genuinely be in: one
284
+ * with no `<wr-step>` children renders its (empty) header strip and no body. A `-1`
285
+ * here would be read as "the first step" by the next line of a spec. An
286
+ * out-of-range `active` is NOT such a state — `WrStepper` clamps the two-way model
287
+ * back into the step list, not only inside `goTo()`.
288
288
  */
289
289
  async getActiveIndex() {
290
290
  const steps = await this.getSteps();
@@ -292,9 +292,9 @@ class WrStepperHarness extends ComponentHarness {
292
292
  if (await steps[index].isActive())
293
293
  return index;
294
294
  }
295
- throw new Error('WrStepperHarness.getActiveIndex(): no header announces `aria-current="step"` — this stepper either has ' +
296
- 'no <wr-step> children, or its bound `active` index points outside them, which also hides every step ' +
297
- 'body. `WrStepper.goTo()` clamps such an index; a host writing `active` itself does not.');
295
+ throw new Error('WrStepperHarness.getActiveIndex(): no header announces `aria-current="step"` — this stepper has ' +
296
+ 'no <wr-step> children, so there is no step for it to be on. An out-of-range `active` cannot ' +
297
+ 'produce this: WrStepper clamps the bound index to the step list.');
298
298
  }
299
299
  /** The label of the step the wizard is showing. Throws when there is no current step. */
300
300
  async getActiveLabel() {
@@ -1 +1 @@
1
- {"version":3,"file":"ngwr-stepper-testing.mjs","sources":["../../../projects/lib/stepper/testing/wr-stepper-harness-text.ts","../../../projects/lib/stepper/testing/wr-step-harness.ts","../../../projects/lib/stepper/testing/wr-stepper-harness.ts","../../../projects/lib/stepper/testing/ngwr-stepper-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\n/**\n * Collapse the whitespace inside a header or a step body to the line a user reads.\n *\n * `TestElement.text()` only trims the ends, and neither of the two things read here\n * is one text node: a header's label span holds the label, the \"optional\" badge and\n * the description as siblings, and a step body is whatever the consumer projected.\n * The template's own indentation is not the problem — Angular's default\n * `preserveWhitespaces: false` drops whitespace-only text nodes at compile time —\n * but a value carrying a newline is, and so is a consumer app compiled with\n * `preserveWhitespaces: true`. Every run becomes one space so a spec can assert the\n * rendered line either way.\n */\nexport function wrStepperHarnessText(text: string): string {\n return text.replace(/\\s+/g, ' ').trim();\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 { ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';\n\nimport type { WrStepHarnessFilters } from './interfaces';\nimport { wrStepperHarnessText } from './wr-stepper-harness-text';\n\n/**\n * Test harness for one step of a `<wr-stepper>` — the step as the HEADER STRIP\n * publishes it: its label, its state, and the one control that navigates to it.\n *\n * A step is two pieces of DOM in two different places. The `<wr-step>` the consumer\n * wrote is projected into the stepper's body region; the header this harness hosts on\n * is generated next to it, in the `<ol>` above. Nothing links the two — no\n * `aria-controls`, no id on the body — so `WrStepperHarness.getActiveStepText()` is\n * where the body is read, and this answers what the wizard says about the step.\n *\n * Two states that look alike here are deliberately separate, because the component\n * treats them separately: {@link isDisabled} is the step's own `disabled` input\n * (switched off, whatever else happens), and {@link isReachable} is whether a click\n * would land right now — which a `linear` stepper takes away from every step ahead of\n * the gate without disabling any of them.\n *\n * @example\n * ```ts\n * const [review] = await stepper.getSteps({ label: 'Review' });\n *\n * expect(await review.isOptional()).toBe(true);\n * expect(await review.isReachable()).toBe(false);\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrStepHarness extends ComponentHarness {\n /**\n * The header `<li>`, which is the whole step as far as the strip is concerned.\n *\n * Not `.wr-stepper__header-button`: the state modifiers (`--active`, `--completed`,\n * `--disabled`) land on the `<li>`, and the button is a child of it.\n */\n static hostSelector = '.wr-stepper__header';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrStepHarnessFilters = {}): HarnessPredicate<WrStepHarness> {\n return new HarnessPredicate(WrStepHarness, options)\n .addOption('label', options.label, (harness, label) => HarnessPredicate.stringMatches(harness.getLabel(), label))\n .addOption('active', options.active, async (harness, active) => (await harness.isActive()) === active)\n .addOption(\n 'completed',\n options.completed,\n async (harness, completed) => (await harness.isCompleted()) === completed\n )\n .addOption('disabled', options.disabled, async (harness, disabled) => (await harness.isDisabled()) === disabled)\n .addOption(\n 'reachable',\n options.reachable,\n async (harness, reachable) => (await harness.isReachable()) === reachable\n )\n .addOption('optional', options.optional, async (harness, optional) => (await harness.isOptional()) === optional);\n }\n\n private readonly button = this.locatorFor('button.wr-stepper__header-button');\n\n /**\n * The step's label, and only the label.\n *\n * The \"optional\" badge and the description are siblings of the label text inside\n * the same span, so both are excluded — a step addressed by label should be\n * addressable whether or not it also carries a description.\n */\n async getLabel(): Promise<string> {\n const label = await this.locatorFor('.wr-stepper__label')();\n return wrStepperHarnessText(await label.text({ exclude: '.wr-stepper__optional, .wr-stepper__description' }));\n }\n\n /** The secondary line under the label, or `null` when the step defines none. */\n async getDescription(): Promise<string | null> {\n const description = await this.locatorForOptional('.wr-stepper__description')();\n return description ? wrStepperHarnessText(await description.text()) : null;\n }\n\n /** Whether the header flags the step as optional. */\n async isOptional(): Promise<boolean> {\n return (await this.locatorForOptional('.wr-stepper__optional')()) !== null;\n }\n\n /**\n * What a screen reader announces for the header button.\n *\n * The indicator is excluded because it is `aria-hidden`: the step number and the\n * completed tick are decoration, deliberately, since the label and\n * `aria-current=\"step\"` already carry what they would repeat. What IS announced is\n * the label plus the \"optional\" badge and the description — so this is the method\n * that notices when one of those stops being part of the name.\n */\n async getAccessibleName(): Promise<string> {\n const button = await this.button();\n return wrStepperHarnessText(await button.text({ exclude: '.wr-stepper__indicator' }));\n }\n\n /**\n * Whether this is the step the wizard is showing.\n *\n * From `aria-current=\"step\"` rather than the `--active` class, because that is the\n * only place the wizard's position is published to a screen reader, and the two can\n * only ever disagree by way of a bug.\n */\n async isActive(): Promise<boolean> {\n return (await (await this.button()).getAttribute('aria-current')) === 'step';\n }\n\n /**\n * Whether the step is shown as done.\n *\n * Read from the `--completed` class, and there is no ARIA alternative to prefer:\n * completion reaches the page as that class plus a tick glyph that is\n * `aria-hidden`, so a screen-reader user hears the label and nothing else. The\n * class is the whole of what exists.\n *\n * Completion is derived from the active index — every step before it — unless a\n * step's own `completed` input overrides it, which is how a `linear` wizard opens\n * its gate. So a step after the active one can be completed too.\n */\n async isCompleted(): Promise<boolean> {\n return (await this.host()).hasClass('wr-stepper__header--completed');\n }\n\n /**\n * Whether the step is switched off by its own `disabled` input.\n *\n * The `--disabled` class is exactly that input, which is why it is read here rather\n * than the button's `disabled`: the button is also disabled for a step that is\n * merely behind a `linear` gate, and those are different facts about the wizard.\n * See {@link isReachable} for the one about right now.\n */\n async isDisabled(): Promise<boolean> {\n return (await this.host()).hasClass('wr-stepper__header--disabled');\n }\n\n /**\n * Whether a click on this header would move the wizard here.\n *\n * Read from the button's `disabled` PROPERTY, because that is the enforcement and\n * not the paint: the component disables the header for a step its own input\n * switched off AND for one a `linear` gate has not opened yet. It is also what puts\n * the header in or out of the tab order — a `disabled` button cannot be focused at\n * all, so an unreachable step is off the keyboard entirely rather than focusable and\n * inert the way `aria-disabled` would leave it.\n */\n async isReachable(): Promise<boolean> {\n return !(await (await this.button()).getProperty<boolean>('disabled'));\n }\n\n /**\n * Navigate to this step by clicking its header, the way a user does.\n *\n * A click, not a keypress: the header is a real `<button>`, so Enter and Space\n * activate it through the browser's native activation — behaviour jsdom does not\n * implement, leaving nothing for a key to drive. A no-arg CDK click needs no\n * coordinate and no hit test, so the absent layout costs nothing here.\n *\n * Throws when the header refuses, rather than clicking and resolving quietly: the\n * component's guard would drop the click and the wizard would still be showing the\n * old step three assertions later. Reach for `WrStepperHarness.goTo()` when you\n * want the failure to name WHICH earlier step is holding the gate shut.\n */\n async select(): Promise<void> {\n if (!(await this.isReachable())) {\n throw new Error(\n `WrStepHarness.select(): the header for \"${await this.getLabel()}\" refuses a click — the step carries ` +\n '`disabled`, or the stepper is `linear` and an earlier step has not reported itself complete.'\n );\n }\n await (await this.button()).click();\n }\n\n /** Move keyboard focus to the header. A header that is not reachable cannot take it. */\n async focus(): Promise<void> {\n return (await this.button()).focus();\n }\n\n /** Whether the header currently has focus. */\n async isFocused(): Promise<boolean> {\n return (await this.button()).isFocused();\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 { ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';\n\nimport type { WrStepHarnessFilters, WrStepperHarnessFilters } from './interfaces';\nimport { WrStepHarness } from './wr-step-harness';\nimport { wrStepperHarnessText } from './wr-stepper-harness-text';\n\n/**\n * Test harness for `<wr-stepper>` — the root of a two-part family with\n * {@link WrStepHarness}, which is one step of it.\n *\n * Steps are addressed by their index or their LABEL, the two things a consumer can\n * see; there is no key or id on a `<wr-step>` to address it by.\n *\n * Navigation here always goes through the HEADER STRIP, because that is the only\n * control the component renders — a wizard's Next and Back buttons are the\n * consumer's own, and they call `WrStepper.next()` / `prev()`. That distinction is\n * not cosmetic: the imperative API does NOT consult `linear`, so it walks straight\n * past a gate that refuses the equivalent header click. {@link next} and\n * {@link goTo} therefore refuse exactly where a user would be refused, and a spec\n * covering the wizard's own buttons should drive those buttons (through their own\n * harness) instead of these.\n *\n * @example\n * ```ts\n * const wizard = await loader.getHarness(WrStepperHarness);\n *\n * expect(await wizard.getStepLabels()).toEqual(['Account', 'Address', 'Review']);\n * expect(await wizard.canGoTo(2)).toBe(false);\n * await wizard.goToLabel('Address');\n * expect(await wizard.getActiveStepText()).toBe('Address body');\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrStepperHarness extends ComponentHarness {\n static hostSelector = 'wr-stepper';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrStepperHarnessFilters = {}): HarnessPredicate<WrStepperHarness> {\n return new HarnessPredicate(WrStepperHarness, options)\n .addOption('stepLabel', options.stepLabel, async (harness, label) => {\n for (const stepLabel of await harness.getStepLabels()) {\n if (await HarnessPredicate.stringMatches(stepLabel, label)) return true;\n }\n return false;\n })\n .addOption(\n 'orientation',\n options.orientation,\n async (harness, orientation) => (await harness.getOrientation()) === orientation\n )\n .addOption('linear', options.linear, async (harness, linear) => (await harness.isLinear()) === linear);\n }\n\n private readonly headerList = this.locatorFor('ol.wr-stepper__headers');\n\n /**\n * The layout direction the stepper was ASKED for.\n *\n * Unusually for this library both values carry a class, so neither is read as the\n * absence of the other. What the class cannot tell you is how the strip actually\n * laid itself out: a `responsive` horizontal stepper drops to the vertical layout\n * when its own box is too narrow, and that reflow is a container query — the class\n * never changes. No unit test can see the difference in any case, jsdom having no\n * layout at all; assert the opt-in with {@link isResponsive} instead.\n */\n async getOrientation(): Promise<'horizontal' | 'vertical'> {\n return (await (await this.host()).hasClass('wr-stepper--vertical')) ? 'vertical' : 'horizontal';\n }\n\n /** Whether the stepper locks the steps after the last completed one. */\n async isLinear(): Promise<boolean> {\n return (await this.host()).hasClass('wr-stepper--linear');\n }\n\n /** Whether the stepper may reflow to the vertical layout in a narrow container. */\n async isResponsive(): Promise<boolean> {\n return (await this.host()).hasClass('wr-stepper--responsive');\n }\n\n /**\n * The role the header strip announces — `list`.\n *\n * An `<ol>` is a list already, so the explicit role looks redundant and is not: the\n * stylesheet removes the markers, and Safari drops list semantics from a list with\n * `list-style: none`. Losing it costs the \"list, 3 items\" a VoiceOver user hears,\n * which is how they learn how long the wizard is before starting it.\n */\n async getListRole(): Promise<string | null> {\n return (await this.headerList()).getAttribute('role');\n }\n\n /** The wizard's steps, in order. */\n async getSteps(filters: WrStepHarnessFilters = {}): Promise<WrStepHarness[]> {\n return this.locatorForAll(WrStepHarness.with(filters))();\n }\n\n /** The label of every step, in order. */\n async getStepLabels(): Promise<string[]> {\n const steps = await this.getSteps();\n return Promise.all(steps.map(step => step.getLabel()));\n }\n\n /**\n * The index of the step the wizard is showing, from the header announcing\n * `aria-current=\"step\"`.\n *\n * Throws when no header does, which is a state a stepper can genuinely be in: the\n * `active` model is two-way, `WrStepper.goTo()` clamps an out-of-range index but a\n * host writing `active` directly does not, and an index past the last step leaves\n * every header un-current and every step body hidden. A `-1` here would be read as\n * \"the first step\" by the next line of a spec.\n */\n async getActiveIndex(): Promise<number> {\n const steps = await this.getSteps();\n for (let index = 0; index < steps.length; index++) {\n if (await steps[index].isActive()) return index;\n }\n\n throw new Error(\n 'WrStepperHarness.getActiveIndex(): no header announces `aria-current=\"step\"` — this stepper either has ' +\n 'no <wr-step> children, or its bound `active` index points outside them, which also hides every step ' +\n 'body. `WrStepper.goTo()` clamps such an index; a host writing `active` itself does not.'\n );\n }\n\n /** The label of the step the wizard is showing. Throws when there is no current step. */\n async getActiveLabel(): Promise<string> {\n const steps = await this.getSteps();\n return steps[await this.getActiveIndex()].getLabel();\n }\n\n /** The labels of the steps shown as done, in order. Derived completion and overrides both. */\n async getCompletedLabels(): Promise<string[]> {\n const steps = await this.getSteps({ completed: true });\n return Promise.all(steps.map(step => step.getLabel()));\n }\n\n /**\n * The labels of the headers a Tab press can reach, in order.\n *\n * A stepper does NOT rove focus: unlike a tab strip, the header list is not one tab\n * stop with arrow keys inside it — every reachable header is its own stop, and the\n * component authors no `tabindex` at all. So the question \"which step is active\" has\n * two different answers, and this is the other one: the current step is not\n * necessarily in this list. A step disabled by its own input keeps\n * `aria-current=\"step\"` while its button drops out of the tab order entirely, and a\n * `linear` stepper takes every locked header off the keyboard the same way.\n */\n async getTabStopLabels(): Promise<string[]> {\n const steps = await this.getSteps({ reachable: true });\n return Promise.all(steps.map(step => step.getLabel()));\n }\n\n /** The label of the header that currently has focus, or `null` when focus is elsewhere. */\n async getFocusedLabel(): Promise<string | null> {\n for (const step of await this.getSteps()) {\n if (await step.isFocused()) return step.getLabel();\n }\n return null;\n }\n\n /**\n * Whether the wizard would let a user navigate to this step right now — the question\n * a `linear` stepper exists to answer `false` to.\n *\n * Throws for an index that is not a step, rather than answering `false`: \"you cannot\n * go there\" and \"there is no there\" are different findings.\n */\n async canGoTo(index: number): Promise<boolean> {\n return (await this.stepAt(index)).isReachable();\n }\n\n /**\n * Navigate to the step at `index` by clicking its header.\n *\n * Throws when the wizard refuses, naming the cause — the step's own `disabled`, or\n * the `linear` gate and which earlier step is holding it shut. Silence would be\n * worse than a failure here: the component drops a click on a locked header without\n * a sound, so a spec would go on to assert against the step it was already showing.\n */\n async goTo(index: number): Promise<void> {\n const step = await this.stepAt(index);\n\n if (!(await step.isReachable())) {\n throw new Error(\n `WrStepperHarness.goTo(${index}): the header for \"${await step.getLabel()}\" refuses a click — ` +\n `${await this.refusal(index)}. Note that \\`WrStepper.goTo()\\` and \\`next()\\` move anyway: the gate is ` +\n \"on the header click, so a wizard's own Next button has to check for itself.\"\n );\n }\n\n await step.select();\n\n if (!(await step.isActive())) {\n throw new Error(\n `WrStepperHarness.goTo(${index}): the header for \"${await step.getLabel()}\" was clicked and the wizard ` +\n 'is still showing another step — its `active` model reached nothing, so a two-way `[(active)]` binding ' +\n 'is overwriting it or the click is not wired.'\n );\n }\n }\n\n /**\n * Navigate to the step with this label — a string matches exactly, a RegExp is\n * tested. Throws naming the labels that do exist when nothing matches.\n */\n async goToLabel(label: string | RegExp): Promise<void> {\n const labels = await this.getStepLabels();\n for (let index = 0; index < labels.length; index++) {\n if (await HarnessPredicate.stringMatches(labels[index], label)) return this.goTo(index);\n }\n\n throw new Error(\n `WrStepperHarness.goToLabel(): no step is labelled ${JSON.stringify(String(label))}. This wizard has: ` +\n `${labels.join(', ')}.`\n );\n }\n\n /**\n * Move to the next step through its header — subject to the same gate a user is.\n *\n * In a `linear` wizard that gate is shut until the CURRENT step reports itself\n * complete (its own `completed` input; derived completion only ever covers steps\n * before the active one), so this throws there. That is not the harness being\n * strict: it is the header a user has, and the reason a linear wizard needs its own\n * Next button, which calls `WrStepper.next()` and is not gated at all.\n *\n * Throws on the last step, where the component's own `next()` clamps in silence.\n */\n async next(): Promise<void> {\n const index = await this.getActiveIndex();\n const steps = await this.getSteps();\n\n if (index === steps.length - 1) {\n throw new Error(\n `WrStepperHarness.next(): the wizard is already on its last step (\"${await steps[index].getLabel()}\") — ` +\n 'there is nothing after it. `WrStepper.next()` clamps silently instead of saying so.'\n );\n }\n\n await this.goTo(index + 1);\n }\n\n /**\n * Move to the previous step through its header. Throws on the first step, where\n * `WrStepper.prev()` clamps in silence.\n *\n * Going back is normally allowed even in a `linear` wizard — every step at or before\n * the active one is reachable — but a step its own input disabled stays out of\n * reach in both directions.\n */\n async previous(): Promise<void> {\n const index = await this.getActiveIndex();\n\n if (index === 0) {\n throw new Error(\n 'WrStepperHarness.previous(): the wizard is already on its first step — there is nothing before it. ' +\n '`WrStepper.prev()` clamps silently instead of saying so.'\n );\n }\n\n await this.goTo(index - 1);\n }\n\n /**\n * The text of the step body the wizard is showing.\n *\n * Which body shows is CSS-only: every `<wr-step>` renders, and the stepper hides all\n * but one with `display: none` through the `--active` class. So this reads the class,\n * and in a unit test it has to — jsdom loads no stylesheet, which makes\n * `fixture.nativeElement.textContent` the text of ALL the steps at once and any\n * \"is the body showing\" assertion built on it meaningless.\n */\n async getActiveStepText(): Promise<string> {\n const active = await this.locatorForOptional('.wr-stepper__body .wr-step--active')();\n if (!active) {\n throw new Error(\n 'WrStepperHarness.getActiveStepText(): no step body is showing — the bound `active` index is outside ' +\n 'the step list, or this stepper has no <wr-step> children.'\n );\n }\n return wrStepperHarnessText(await active.text());\n }\n\n /**\n * The text of EVERY step body, in order, showing or not.\n *\n * The list being complete is the point: a step is hidden by a class rather than\n * dropped by an `@if`, so it mounts once and keeps its state — a half-filled form on\n * step 1 is still filled after a trip to step 3. Anything that turned the body into\n * a conditional block would keep every other assertion in a spec passing and quietly\n * reset the wizard.\n */\n async getStepTexts(): Promise<string[]> {\n const bodies = await this.locatorForAll('.wr-stepper__body > wr-step')();\n return Promise.all(bodies.map(async body => wrStepperHarnessText(await body.text())));\n }\n\n /** The step at `index`, or a failure that says how long the wizard is. */\n private async stepAt(index: number): Promise<WrStepHarness> {\n const steps = await this.getSteps();\n const step = steps[index];\n if (!step) {\n throw new Error(\n `WrStepperHarness: there is no step ${index} — this wizard has ${steps.length} ` +\n `${steps.length === 1 ? 'step' : 'steps'}${steps.length ? `: ${(await this.getStepLabels()).join(', ')}` : ''}.`\n );\n }\n return step;\n }\n\n /** Why the header at `index` is refusing a click, in the component's own order of causes. */\n private async refusal(index: number): Promise<string> {\n const steps = await this.getSteps();\n\n // The step's own input wins in the component too: `isReachable()` answers `false`\n // for a disabled step before it ever looks at the gate.\n if (await steps[index].isDisabled()) return 'the step carries `disabled`';\n\n if (await this.isLinear()) {\n for (let before = 0; before < index; before++) {\n if (!(await steps[before].isCompleted())) {\n return (\n 'the stepper is `linear` and step ' +\n `${before + 1} (\"${await steps[before].getLabel()}\") has not reported itself complete`\n );\n }\n }\n }\n\n return 'its header button is disabled';\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ngwr-stepper-testing.mjs","sources":["../../../projects/lib/stepper/testing/wr-stepper-harness-text.ts","../../../projects/lib/stepper/testing/wr-step-harness.ts","../../../projects/lib/stepper/testing/wr-stepper-harness.ts","../../../projects/lib/stepper/testing/ngwr-stepper-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\n/**\n * Collapse the whitespace inside a header or a step body to the line a user reads.\n *\n * `TestElement.text()` only trims the ends, and neither of the two things read here\n * is one text node: a header's label span holds the label, the \"optional\" badge and\n * the description as siblings, and a step body is whatever the consumer projected.\n * The template's own indentation is not the problem — Angular's default\n * `preserveWhitespaces: false` drops whitespace-only text nodes at compile time —\n * but a value carrying a newline is, and so is a consumer app compiled with\n * `preserveWhitespaces: true`. Every run becomes one space so a spec can assert the\n * rendered line either way.\n */\nexport function wrStepperHarnessText(text: string): string {\n return text.replace(/\\s+/g, ' ').trim();\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 { ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';\n\nimport type { WrStepHarnessFilters } from './interfaces';\nimport { wrStepperHarnessText } from './wr-stepper-harness-text';\n\n/**\n * Test harness for one step of a `<wr-stepper>` — the step as the HEADER STRIP\n * publishes it: its label, its state, and the one control that navigates to it.\n *\n * A step is two pieces of DOM in two different places. The `<wr-step>` the consumer\n * wrote is projected into the stepper's body region; the header this harness hosts on\n * is generated next to it, in the `<ol>` above. Nothing links the two — no\n * `aria-controls`, no id on the body — so `WrStepperHarness.getActiveStepText()` is\n * where the body is read, and this answers what the wizard says about the step.\n *\n * Two states that look alike here are deliberately separate, because the component\n * treats them separately: {@link isDisabled} is the step's own `disabled` input\n * (switched off, whatever else happens), and {@link isReachable} is whether a click\n * would land right now — which a `linear` stepper takes away from every step ahead of\n * the gate without disabling any of them.\n *\n * @example\n * ```ts\n * const [review] = await stepper.getSteps({ label: 'Review' });\n *\n * expect(await review.isOptional()).toBe(true);\n * expect(await review.isReachable()).toBe(false);\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrStepHarness extends ComponentHarness {\n /**\n * The header `<li>`, which is the whole step as far as the strip is concerned.\n *\n * Not `.wr-stepper__header-button`: the state modifiers (`--active`, `--completed`,\n * `--disabled`) land on the `<li>`, and the button is a child of it.\n */\n static hostSelector = '.wr-stepper__header';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrStepHarnessFilters = {}): HarnessPredicate<WrStepHarness> {\n return new HarnessPredicate(WrStepHarness, options)\n .addOption('label', options.label, (harness, label) => HarnessPredicate.stringMatches(harness.getLabel(), label))\n .addOption('active', options.active, async (harness, active) => (await harness.isActive()) === active)\n .addOption(\n 'completed',\n options.completed,\n async (harness, completed) => (await harness.isCompleted()) === completed\n )\n .addOption('disabled', options.disabled, async (harness, disabled) => (await harness.isDisabled()) === disabled)\n .addOption(\n 'reachable',\n options.reachable,\n async (harness, reachable) => (await harness.isReachable()) === reachable\n )\n .addOption('optional', options.optional, async (harness, optional) => (await harness.isOptional()) === optional);\n }\n\n private readonly button = this.locatorFor('button.wr-stepper__header-button');\n\n /**\n * The step's label, and only the label.\n *\n * The \"optional\" badge and the description are siblings of the label text inside\n * the same span, so both are excluded — a step addressed by label should be\n * addressable whether or not it also carries a description.\n */\n async getLabel(): Promise<string> {\n const label = await this.locatorFor('.wr-stepper__label')();\n return wrStepperHarnessText(await label.text({ exclude: '.wr-stepper__optional, .wr-stepper__description' }));\n }\n\n /** The secondary line under the label, or `null` when the step defines none. */\n async getDescription(): Promise<string | null> {\n const description = await this.locatorForOptional('.wr-stepper__description')();\n return description ? wrStepperHarnessText(await description.text()) : null;\n }\n\n /** Whether the header flags the step as optional. */\n async isOptional(): Promise<boolean> {\n return (await this.locatorForOptional('.wr-stepper__optional')()) !== null;\n }\n\n /**\n * What a screen reader announces for the header button.\n *\n * The indicator is excluded because it is `aria-hidden`: the step number and the\n * completed tick are decoration, deliberately, since the label and\n * `aria-current=\"step\"` already carry what they would repeat. What IS announced is\n * the label plus the \"optional\" badge and the description — so this is the method\n * that notices when one of those stops being part of the name.\n */\n async getAccessibleName(): Promise<string> {\n const button = await this.button();\n return wrStepperHarnessText(await button.text({ exclude: '.wr-stepper__indicator' }));\n }\n\n /**\n * Whether this is the step the wizard is showing.\n *\n * From `aria-current=\"step\"` rather than the `--active` class, because that is the\n * only place the wizard's position is published to a screen reader, and the two can\n * only ever disagree by way of a bug.\n */\n async isActive(): Promise<boolean> {\n return (await (await this.button()).getAttribute('aria-current')) === 'step';\n }\n\n /**\n * Whether the step is shown as done.\n *\n * Read from the `--completed` class, and there is no ARIA alternative to prefer:\n * completion reaches the page as that class plus a tick glyph that is\n * `aria-hidden`, so a screen-reader user hears the label and nothing else. The\n * class is the whole of what exists.\n *\n * Completion is derived from the active index — every step before it — unless a\n * step's own `completed` input overrides it, which is how a `linear` wizard opens\n * its gate. So a step after the active one can be completed too.\n */\n async isCompleted(): Promise<boolean> {\n return (await this.host()).hasClass('wr-stepper__header--completed');\n }\n\n /**\n * Whether the step is switched off by its own `disabled` input.\n *\n * The `--disabled` class is exactly that input, which is why it is read here rather\n * than the button's `disabled`: the button is also disabled for a step that is\n * merely behind a `linear` gate, and those are different facts about the wizard.\n * See {@link isReachable} for the one about right now.\n */\n async isDisabled(): Promise<boolean> {\n return (await this.host()).hasClass('wr-stepper__header--disabled');\n }\n\n /**\n * Whether a click on this header would move the wizard here.\n *\n * Read from the button's `disabled` PROPERTY, because that is the enforcement and\n * not the paint: the component disables the header for a step its own input\n * switched off AND for one a `linear` gate has not opened yet. It is also what puts\n * the header in or out of the tab order — a `disabled` button cannot be focused at\n * all, so an unreachable step is off the keyboard entirely rather than focusable and\n * inert the way `aria-disabled` would leave it.\n */\n async isReachable(): Promise<boolean> {\n return !(await (await this.button()).getProperty<boolean>('disabled'));\n }\n\n /**\n * Navigate to this step by clicking its header, the way a user does.\n *\n * A click, not a keypress: the header is a real `<button>`, so Enter and Space\n * activate it through the browser's native activation — behaviour jsdom does not\n * implement, leaving nothing for a key to drive. A no-arg CDK click needs no\n * coordinate and no hit test, so the absent layout costs nothing here.\n *\n * Throws when the header refuses, rather than clicking and resolving quietly: the\n * component's guard would drop the click and the wizard would still be showing the\n * old step three assertions later. Reach for `WrStepperHarness.goTo()` when you\n * want the failure to name WHICH earlier step is holding the gate shut.\n */\n async select(): Promise<void> {\n if (!(await this.isReachable())) {\n throw new Error(\n `WrStepHarness.select(): the header for \"${await this.getLabel()}\" refuses a click — the step carries ` +\n '`disabled`, or the stepper is `linear` and an earlier step has not reported itself complete.'\n );\n }\n await (await this.button()).click();\n }\n\n /** Move keyboard focus to the header. A header that is not reachable cannot take it. */\n async focus(): Promise<void> {\n return (await this.button()).focus();\n }\n\n /** Whether the header currently has focus. */\n async isFocused(): Promise<boolean> {\n return (await this.button()).isFocused();\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 { ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';\n\nimport type { WrStepHarnessFilters, WrStepperHarnessFilters } from './interfaces';\nimport { WrStepHarness } from './wr-step-harness';\nimport { wrStepperHarnessText } from './wr-stepper-harness-text';\n\n/**\n * Test harness for `<wr-stepper>` — the root of a two-part family with\n * {@link WrStepHarness}, which is one step of it.\n *\n * Steps are addressed by their index or their LABEL, the two things a consumer can\n * see; there is no key or id on a `<wr-step>` to address it by.\n *\n * Navigation here always goes through the HEADER STRIP, because that is the only\n * control the component renders — a wizard's Next and Back buttons are the\n * consumer's own, and they call `WrStepper.next()` / `prev()`. That distinction is\n * not cosmetic: the imperative API does NOT consult `linear`, so it walks straight\n * past a gate that refuses the equivalent header click. {@link next} and\n * {@link goTo} therefore refuse exactly where a user would be refused, and a spec\n * covering the wizard's own buttons should drive those buttons (through their own\n * harness) instead of these.\n *\n * @example\n * ```ts\n * const wizard = await loader.getHarness(WrStepperHarness);\n *\n * expect(await wizard.getStepLabels()).toEqual(['Account', 'Address', 'Review']);\n * expect(await wizard.canGoTo(2)).toBe(false);\n * await wizard.goToLabel('Address');\n * expect(await wizard.getActiveStepText()).toBe('Address body');\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrStepperHarness extends ComponentHarness {\n static hostSelector = 'wr-stepper';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrStepperHarnessFilters = {}): HarnessPredicate<WrStepperHarness> {\n return new HarnessPredicate(WrStepperHarness, options)\n .addOption('stepLabel', options.stepLabel, async (harness, label) => {\n for (const stepLabel of await harness.getStepLabels()) {\n if (await HarnessPredicate.stringMatches(stepLabel, label)) return true;\n }\n return false;\n })\n .addOption(\n 'orientation',\n options.orientation,\n async (harness, orientation) => (await harness.getOrientation()) === orientation\n )\n .addOption('linear', options.linear, async (harness, linear) => (await harness.isLinear()) === linear);\n }\n\n private readonly headerList = this.locatorFor('ol.wr-stepper__headers');\n\n /**\n * The layout direction the stepper was ASKED for.\n *\n * Unusually for this library both values carry a class, so neither is read as the\n * absence of the other. What the class cannot tell you is how the strip actually\n * laid itself out: a `responsive` horizontal stepper drops to the vertical layout\n * when its own box is too narrow, and that reflow is a container query — the class\n * never changes. No unit test can see the difference in any case, jsdom having no\n * layout at all; assert the opt-in with {@link isResponsive} instead.\n */\n async getOrientation(): Promise<'horizontal' | 'vertical'> {\n return (await (await this.host()).hasClass('wr-stepper--vertical')) ? 'vertical' : 'horizontal';\n }\n\n /** Whether the stepper locks the steps after the last completed one. */\n async isLinear(): Promise<boolean> {\n return (await this.host()).hasClass('wr-stepper--linear');\n }\n\n /** Whether the stepper may reflow to the vertical layout in a narrow container. */\n async isResponsive(): Promise<boolean> {\n return (await this.host()).hasClass('wr-stepper--responsive');\n }\n\n /**\n * The role the header strip announces — `list`.\n *\n * An `<ol>` is a list already, so the explicit role looks redundant and is not: the\n * stylesheet removes the markers, and Safari drops list semantics from a list with\n * `list-style: none`. Losing it costs the \"list, 3 items\" a VoiceOver user hears,\n * which is how they learn how long the wizard is before starting it.\n */\n async getListRole(): Promise<string | null> {\n return (await this.headerList()).getAttribute('role');\n }\n\n /** The wizard's steps, in order. */\n async getSteps(filters: WrStepHarnessFilters = {}): Promise<WrStepHarness[]> {\n return this.locatorForAll(WrStepHarness.with(filters))();\n }\n\n /** The label of every step, in order. */\n async getStepLabels(): Promise<string[]> {\n const steps = await this.getSteps();\n return Promise.all(steps.map(step => step.getLabel()));\n }\n\n /**\n * The index of the step the wizard is showing, from the header announcing\n * `aria-current=\"step\"`.\n *\n * Throws when no header does, which is a state a stepper can genuinely be in: one\n * with no `<wr-step>` children renders its (empty) header strip and no body. A `-1`\n * here would be read as \"the first step\" by the next line of a spec. An\n * out-of-range `active` is NOT such a state — `WrStepper` clamps the two-way model\n * back into the step list, not only inside `goTo()`.\n */\n async getActiveIndex(): Promise<number> {\n const steps = await this.getSteps();\n for (let index = 0; index < steps.length; index++) {\n if (await steps[index].isActive()) return index;\n }\n\n throw new Error(\n 'WrStepperHarness.getActiveIndex(): no header announces `aria-current=\"step\"` — this stepper has ' +\n 'no <wr-step> children, so there is no step for it to be on. An out-of-range `active` cannot ' +\n 'produce this: WrStepper clamps the bound index to the step list.'\n );\n }\n\n /** The label of the step the wizard is showing. Throws when there is no current step. */\n async getActiveLabel(): Promise<string> {\n const steps = await this.getSteps();\n return steps[await this.getActiveIndex()].getLabel();\n }\n\n /** The labels of the steps shown as done, in order. Derived completion and overrides both. */\n async getCompletedLabels(): Promise<string[]> {\n const steps = await this.getSteps({ completed: true });\n return Promise.all(steps.map(step => step.getLabel()));\n }\n\n /**\n * The labels of the headers a Tab press can reach, in order.\n *\n * A stepper does NOT rove focus: unlike a tab strip, the header list is not one tab\n * stop with arrow keys inside it — every reachable header is its own stop, and the\n * component authors no `tabindex` at all. So the question \"which step is active\" has\n * two different answers, and this is the other one: the current step is not\n * necessarily in this list. A step disabled by its own input keeps\n * `aria-current=\"step\"` while its button drops out of the tab order entirely, and a\n * `linear` stepper takes every locked header off the keyboard the same way.\n */\n async getTabStopLabels(): Promise<string[]> {\n const steps = await this.getSteps({ reachable: true });\n return Promise.all(steps.map(step => step.getLabel()));\n }\n\n /** The label of the header that currently has focus, or `null` when focus is elsewhere. */\n async getFocusedLabel(): Promise<string | null> {\n for (const step of await this.getSteps()) {\n if (await step.isFocused()) return step.getLabel();\n }\n return null;\n }\n\n /**\n * Whether the wizard would let a user navigate to this step right now — the question\n * a `linear` stepper exists to answer `false` to.\n *\n * Throws for an index that is not a step, rather than answering `false`: \"you cannot\n * go there\" and \"there is no there\" are different findings.\n */\n async canGoTo(index: number): Promise<boolean> {\n return (await this.stepAt(index)).isReachable();\n }\n\n /**\n * Navigate to the step at `index` by clicking its header.\n *\n * Throws when the wizard refuses, naming the cause — the step's own `disabled`, or\n * the `linear` gate and which earlier step is holding it shut. Silence would be\n * worse than a failure here: the component drops a click on a locked header without\n * a sound, so a spec would go on to assert against the step it was already showing.\n */\n async goTo(index: number): Promise<void> {\n const step = await this.stepAt(index);\n\n if (!(await step.isReachable())) {\n throw new Error(\n `WrStepperHarness.goTo(${index}): the header for \"${await step.getLabel()}\" refuses a click — ` +\n `${await this.refusal(index)}. Note that \\`WrStepper.goTo()\\` and \\`next()\\` move anyway: the gate is ` +\n \"on the header click, so a wizard's own Next button has to check for itself.\"\n );\n }\n\n await step.select();\n\n if (!(await step.isActive())) {\n throw new Error(\n `WrStepperHarness.goTo(${index}): the header for \"${await step.getLabel()}\" was clicked and the wizard ` +\n 'is still showing another step — its `active` model reached nothing, so a two-way `[(active)]` binding ' +\n 'is overwriting it or the click is not wired.'\n );\n }\n }\n\n /**\n * Navigate to the step with this label — a string matches exactly, a RegExp is\n * tested. Throws naming the labels that do exist when nothing matches.\n */\n async goToLabel(label: string | RegExp): Promise<void> {\n const labels = await this.getStepLabels();\n for (let index = 0; index < labels.length; index++) {\n if (await HarnessPredicate.stringMatches(labels[index], label)) return this.goTo(index);\n }\n\n throw new Error(\n `WrStepperHarness.goToLabel(): no step is labelled ${JSON.stringify(String(label))}. This wizard has: ` +\n `${labels.join(', ')}.`\n );\n }\n\n /**\n * Move to the next step through its header — subject to the same gate a user is.\n *\n * In a `linear` wizard that gate is shut until the CURRENT step reports itself\n * complete (its own `completed` input; derived completion only ever covers steps\n * before the active one), so this throws there. That is not the harness being\n * strict: it is the header a user has, and the reason a linear wizard needs its own\n * Next button, which calls `WrStepper.next()` and is not gated at all.\n *\n * Throws on the last step, where the component's own `next()` clamps in silence.\n */\n async next(): Promise<void> {\n const index = await this.getActiveIndex();\n const steps = await this.getSteps();\n\n if (index === steps.length - 1) {\n throw new Error(\n `WrStepperHarness.next(): the wizard is already on its last step (\"${await steps[index].getLabel()}\") — ` +\n 'there is nothing after it. `WrStepper.next()` clamps silently instead of saying so.'\n );\n }\n\n await this.goTo(index + 1);\n }\n\n /**\n * Move to the previous step through its header. Throws on the first step, where\n * `WrStepper.prev()` clamps in silence.\n *\n * Going back is normally allowed even in a `linear` wizard — every step at or before\n * the active one is reachable — but a step its own input disabled stays out of\n * reach in both directions.\n */\n async previous(): Promise<void> {\n const index = await this.getActiveIndex();\n\n if (index === 0) {\n throw new Error(\n 'WrStepperHarness.previous(): the wizard is already on its first step — there is nothing before it. ' +\n '`WrStepper.prev()` clamps silently instead of saying so.'\n );\n }\n\n await this.goTo(index - 1);\n }\n\n /**\n * The text of the step body the wizard is showing.\n *\n * Which body shows is CSS-only: every `<wr-step>` renders, and the stepper hides all\n * but one with `display: none` through the `--active` class. So this reads the class,\n * and in a unit test it has to — jsdom loads no stylesheet, which makes\n * `fixture.nativeElement.textContent` the text of ALL the steps at once and any\n * \"is the body showing\" assertion built on it meaningless.\n */\n async getActiveStepText(): Promise<string> {\n const active = await this.locatorForOptional('.wr-stepper__body .wr-step--active')();\n if (!active) {\n throw new Error(\n 'WrStepperHarness.getActiveStepText(): no step body is showing — the bound `active` index is outside ' +\n 'the step list, or this stepper has no <wr-step> children.'\n );\n }\n return wrStepperHarnessText(await active.text());\n }\n\n /**\n * The text of EVERY step body, in order, showing or not.\n *\n * The list being complete is the point: a step is hidden by a class rather than\n * dropped by an `@if`, so it mounts once and keeps its state — a half-filled form on\n * step 1 is still filled after a trip to step 3. Anything that turned the body into\n * a conditional block would keep every other assertion in a spec passing and quietly\n * reset the wizard.\n */\n async getStepTexts(): Promise<string[]> {\n const bodies = await this.locatorForAll('.wr-stepper__body > wr-step')();\n return Promise.all(bodies.map(async body => wrStepperHarnessText(await body.text())));\n }\n\n /** The step at `index`, or a failure that says how long the wizard is. */\n private async stepAt(index: number): Promise<WrStepHarness> {\n const steps = await this.getSteps();\n const step = steps[index];\n if (!step) {\n throw new Error(\n `WrStepperHarness: there is no step ${index} — this wizard has ${steps.length} ` +\n `${steps.length === 1 ? 'step' : 'steps'}${steps.length ? `: ${(await this.getStepLabels()).join(', ')}` : ''}.`\n );\n }\n return step;\n }\n\n /** Why the header at `index` is refusing a click, in the component's own order of causes. */\n private async refusal(index: number): Promise<string> {\n const steps = await this.getSteps();\n\n // The step's own input wins in the component too: `isReachable()` answers `false`\n // for a disabled step before it ever looks at the gate.\n if (await steps[index].isDisabled()) return 'the step carries `disabled`';\n\n if (await this.isLinear()) {\n for (let before = 0; before < index; before++) {\n if (!(await steps[before].isCompleted())) {\n return (\n 'the stepper is `linear` and step ' +\n `${before + 1} (\"${await steps[before].getLabel()}\") has not reported itself complete`\n );\n }\n }\n }\n\n return 'its header button is disabled';\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { coerceBooleanProperty } from '@angular/cdk/coercion';
2
2
  import * as i0 from '@angular/core';
3
3
  import { InjectionToken, input, signal, inject, computed, ViewEncapsulation, Component, model, contentChildren, effect, forwardRef } from '@angular/core';
4
+ import { useI18nText } from 'ngwr/i18n';
4
5
 
5
6
  /**
6
7
  * @license
@@ -54,10 +55,10 @@ class WrStep {
54
55
  stepper = inject(WR_STEPPER);
55
56
  isActive = computed(() => this._index() === this.stepper.active(), /* @ts-ignore */
56
57
  ...(ngDevMode ? [{ debugName: "isActive" }] : /* istanbul ignore next */ []));
57
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrStep, deps: [], target: i0.ɵɵFactoryTarget.Component });
58
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.1", type: WrStep, isStandalone: true, selector: "wr-step", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, optional: { classPropertyName: "optional", publicName: "optional", isSignal: true, isRequired: false, transformFunction: null }, completed: { classPropertyName: "completed", publicName: "completed", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.wr-step--active": "isActive()" }, classAttribute: "wr-step" }, ngImport: i0, template: '<ng-content />', isInline: true, encapsulation: i0.ViewEncapsulation.None });
58
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrStep, deps: [], target: i0.ɵɵFactoryTarget.Component });
59
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.4", type: WrStep, isStandalone: true, selector: "wr-step", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, optional: { classPropertyName: "optional", publicName: "optional", isSignal: true, isRequired: false, transformFunction: null }, completed: { classPropertyName: "completed", publicName: "completed", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.wr-step--active": "isActive()" }, classAttribute: "wr-step" }, ngImport: i0, template: '<ng-content />', isInline: true, encapsulation: i0.ViewEncapsulation.None });
59
60
  }
60
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrStep, decorators: [{
61
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrStep, decorators: [{
61
62
  type: Component,
62
63
  args: [{
63
64
  selector: 'wr-step',
@@ -76,6 +77,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImpor
76
77
  * Use of this source code is governed by an MIT-style license that can be
77
78
  * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
78
79
  */
80
+ /** A label with no consumer input to forward — see `optionalLabel` below. */
81
+ const NO_OVERRIDE = signal(null).asReadonly();
79
82
  /**
80
83
  * Multi-step wizard container. Children are `<wr-step>` components — the
81
84
  * stepper renders one numbered header per step (with connectors) and the
@@ -113,6 +116,14 @@ class WrStepper {
113
116
  responsive = input(false, { ...(ngDevMode ? { debugName: "responsive" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
114
117
  steps = contentChildren(WrStep, /* @ts-ignore */
115
118
  ...(ngDevMode ? [{ debugName: "steps" }] : /* istanbul ignore next */ []));
119
+ /**
120
+ * The "optional" badge sits INSIDE the header button's label span, so the word
121
+ * is part of the step's accessible name — a hard-coded literal announced English
122
+ * to every locale, not just showed it. Catalog-only rather than an input: the
123
+ * badge is one word shared by every step, and an app that wants other wording
124
+ * overrides `stepper.optional` once instead of on every `<wr-step>`.
125
+ */
126
+ optionalLabel = useI18nText(NO_OVERRIDE, 'stepper.optional', 'optional');
116
127
  classes = computed(() => {
117
128
  const parts = ['wr-stepper', `wr-stepper--${this.orientation()}`];
118
129
  if (this.linear())
@@ -127,6 +138,20 @@ class WrStepper {
127
138
  effect(() => {
128
139
  this.steps().forEach((step, i) => step._index.set(i));
129
140
  });
141
+ // `active` is a plain `model`, so `[(active)]` and an `@if`-shrunk step list
142
+ // both write into it unchecked — only `goTo` clamped. Out of range no step
143
+ // matches `.wr-step--active`, and since `.wr-step` is `display: none` until it
144
+ // does, the stepper renders its header row over an empty body with no header
145
+ // carrying `aria-current="step"`. Same guard as `wr-carousel`; the `last < 0`
146
+ // return keeps it quiet until `contentChildren` resolves.
147
+ effect(() => {
148
+ const last = this.steps().length - 1;
149
+ if (last < 0)
150
+ return;
151
+ const clamped = Math.min(Math.max(0, this.active()), last);
152
+ if (clamped !== this.active())
153
+ this.active.set(clamped);
154
+ });
130
155
  }
131
156
  /** Is the step at `index` considered completed? */
132
157
  isCompleted(index) {
@@ -167,16 +192,16 @@ class WrStepper {
167
192
  prev() {
168
193
  this.goTo(this.active() - 1);
169
194
  }
170
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrStepper, deps: [], target: i0.ɵɵFactoryTarget.Component });
171
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: WrStepper, isStandalone: true, selector: "wr-stepper", inputs: { active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, linear: { classPropertyName: "linear", publicName: "linear", isSignal: true, isRequired: false, transformFunction: null }, responsive: { classPropertyName: "responsive", publicName: "responsive", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { active: "activeChange" }, host: { properties: { "class": "classes()" } }, providers: [
195
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrStepper, deps: [], target: i0.ɵɵFactoryTarget.Component });
196
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: WrStepper, isStandalone: true, selector: "wr-stepper", inputs: { active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, linear: { classPropertyName: "linear", publicName: "linear", isSignal: true, isRequired: false, transformFunction: null }, responsive: { classPropertyName: "responsive", publicName: "responsive", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { active: "activeChange" }, host: { properties: { "class": "classes()" } }, providers: [
172
197
  {
173
198
  provide: WR_STEPPER,
174
199
  // eslint-disable-next-line @angular-eslint/no-forward-ref
175
200
  useExisting: forwardRef(() => WrStepper),
176
201
  },
177
- ], queries: [{ propertyName: "steps", predicate: WrStep, isSignal: true }], ngImport: i0, template: "<ol class=\"wr-stepper__headers\" role=\"list\">\n @for (step of steps(); track $index) {\n <li\n class=\"wr-stepper__header\"\n [class.wr-stepper__header--active]=\"$index === active()\"\n [class.wr-stepper__header--completed]=\"isCompleted($index)\"\n [class.wr-stepper__header--reachable]=\"isReachable($index)\"\n [class.wr-stepper__header--disabled]=\"step.disabled()\"\n >\n <button\n type=\"button\"\n class=\"wr-stepper__header-button\"\n [disabled]=\"!isReachable($index) || step.disabled()\"\n [attr.aria-current]=\"$index === active() ? 'step' : null\"\n (click)=\"onHeaderClick($index)\"\n >\n <span class=\"wr-stepper__indicator\" aria-hidden=\"true\">\n @if (isCompleted($index)) {\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\">\n <path\n d=\"M3 7.5 L6 10.5 L11 4.5\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.75\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n } @else {\n {{ $index + 1 }}\n }\n </span>\n <span class=\"wr-stepper__label\">\n {{ step.label() }}\n @if (step.optional()) {\n <small class=\"wr-stepper__optional\">optional</small>\n }\n @if (step.description()) {\n <small class=\"wr-stepper__description\">{{ step.description() }}</small>\n }\n </span>\n </button>\n @if (!$last) {\n <span class=\"wr-stepper__connector\" aria-hidden=\"true\"></span>\n }\n </li>\n }\n</ol>\n\n<div class=\"wr-stepper__body\">\n <ng-content />\n</div>\n", encapsulation: i0.ViewEncapsulation.None });
202
+ ], queries: [{ propertyName: "steps", predicate: WrStep, isSignal: true }], ngImport: i0, template: "<ol class=\"wr-stepper__headers\" role=\"list\">\n @for (step of steps(); track $index) {\n <li\n class=\"wr-stepper__header\"\n [class.wr-stepper__header--active]=\"$index === active()\"\n [class.wr-stepper__header--completed]=\"isCompleted($index)\"\n [class.wr-stepper__header--reachable]=\"isReachable($index)\"\n [class.wr-stepper__header--disabled]=\"step.disabled()\"\n >\n <button\n type=\"button\"\n class=\"wr-stepper__header-button\"\n [disabled]=\"!isReachable($index) || step.disabled()\"\n [attr.aria-current]=\"$index === active() ? 'step' : null\"\n (click)=\"onHeaderClick($index)\"\n >\n <span class=\"wr-stepper__indicator\" aria-hidden=\"true\">\n @if (isCompleted($index)) {\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\">\n <path\n d=\"M3 7.5 L6 10.5 L11 4.5\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.75\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n } @else {\n {{ $index + 1 }}\n }\n </span>\n <span class=\"wr-stepper__label\">\n {{ step.label() }}\n @if (step.optional()) {\n <small class=\"wr-stepper__optional\">{{ optionalLabel() }}</small>\n }\n @if (step.description()) {\n <small class=\"wr-stepper__description\">{{ step.description() }}</small>\n }\n </span>\n </button>\n @if (!$last) {\n <span class=\"wr-stepper__connector\" aria-hidden=\"true\"></span>\n }\n </li>\n }\n</ol>\n\n<div class=\"wr-stepper__body\">\n <ng-content />\n</div>\n", encapsulation: i0.ViewEncapsulation.None });
178
203
  }
179
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrStepper, decorators: [{
204
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrStepper, decorators: [{
180
205
  type: Component,
181
206
  args: [{ selector: 'wr-stepper', encapsulation: ViewEncapsulation.None, host: { '[class]': 'classes()' }, providers: [
182
207
  {
@@ -184,7 +209,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImpor
184
209
  // eslint-disable-next-line @angular-eslint/no-forward-ref
185
210
  useExisting: forwardRef(() => WrStepper),
186
211
  },
187
- ], template: "<ol class=\"wr-stepper__headers\" role=\"list\">\n @for (step of steps(); track $index) {\n <li\n class=\"wr-stepper__header\"\n [class.wr-stepper__header--active]=\"$index === active()\"\n [class.wr-stepper__header--completed]=\"isCompleted($index)\"\n [class.wr-stepper__header--reachable]=\"isReachable($index)\"\n [class.wr-stepper__header--disabled]=\"step.disabled()\"\n >\n <button\n type=\"button\"\n class=\"wr-stepper__header-button\"\n [disabled]=\"!isReachable($index) || step.disabled()\"\n [attr.aria-current]=\"$index === active() ? 'step' : null\"\n (click)=\"onHeaderClick($index)\"\n >\n <span class=\"wr-stepper__indicator\" aria-hidden=\"true\">\n @if (isCompleted($index)) {\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\">\n <path\n d=\"M3 7.5 L6 10.5 L11 4.5\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.75\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n } @else {\n {{ $index + 1 }}\n }\n </span>\n <span class=\"wr-stepper__label\">\n {{ step.label() }}\n @if (step.optional()) {\n <small class=\"wr-stepper__optional\">optional</small>\n }\n @if (step.description()) {\n <small class=\"wr-stepper__description\">{{ step.description() }}</small>\n }\n </span>\n </button>\n @if (!$last) {\n <span class=\"wr-stepper__connector\" aria-hidden=\"true\"></span>\n }\n </li>\n }\n</ol>\n\n<div class=\"wr-stepper__body\">\n <ng-content />\n</div>\n" }]
212
+ ], template: "<ol class=\"wr-stepper__headers\" role=\"list\">\n @for (step of steps(); track $index) {\n <li\n class=\"wr-stepper__header\"\n [class.wr-stepper__header--active]=\"$index === active()\"\n [class.wr-stepper__header--completed]=\"isCompleted($index)\"\n [class.wr-stepper__header--reachable]=\"isReachable($index)\"\n [class.wr-stepper__header--disabled]=\"step.disabled()\"\n >\n <button\n type=\"button\"\n class=\"wr-stepper__header-button\"\n [disabled]=\"!isReachable($index) || step.disabled()\"\n [attr.aria-current]=\"$index === active() ? 'step' : null\"\n (click)=\"onHeaderClick($index)\"\n >\n <span class=\"wr-stepper__indicator\" aria-hidden=\"true\">\n @if (isCompleted($index)) {\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\">\n <path\n d=\"M3 7.5 L6 10.5 L11 4.5\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.75\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n } @else {\n {{ $index + 1 }}\n }\n </span>\n <span class=\"wr-stepper__label\">\n {{ step.label() }}\n @if (step.optional()) {\n <small class=\"wr-stepper__optional\">{{ optionalLabel() }}</small>\n }\n @if (step.description()) {\n <small class=\"wr-stepper__description\">{{ step.description() }}</small>\n }\n </span>\n </button>\n @if (!$last) {\n <span class=\"wr-stepper__connector\" aria-hidden=\"true\"></span>\n }\n </li>\n }\n</ol>\n\n<div class=\"wr-stepper__body\">\n <ng-content />\n</div>\n" }]
188
213
  }], ctorParameters: () => [], propDecorators: { active: [{ type: i0.Input, args: [{ isSignal: true, alias: "active", required: false }] }, { type: i0.Output, args: ["activeChange"] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], linear: [{ type: i0.Input, args: [{ isSignal: true, alias: "linear", required: false }] }], responsive: [{ type: i0.Input, args: [{ isSignal: true, alias: "responsive", required: false }] }], steps: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => WrStep), { isSignal: true }] }] } });
189
214
 
190
215
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"ngwr-stepper.mjs","sources":["../../../projects/lib/stepper/tokens.ts","../../../projects/lib/stepper/step.ts","../../../projects/lib/stepper/stepper.ts","../../../projects/lib/stepper/stepper.html","../../../projects/lib/stepper/ngwr-stepper.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { InjectionToken, type Signal } from '@angular/core';\n\n/** Surface a {@link WrStepper} provides for its child `<wr-step>`s. */\nexport interface WrStepperContext {\n /** Index of the currently visible step. */\n readonly active: Signal<number>;\n /** Linear mode — steps after the latest completed one are locked. */\n readonly linear: Signal<boolean>;\n}\n\nexport const WR_STEPPER = new InjectionToken<WrStepperContext>('WR_STEPPER');\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { Component, ViewEncapsulation, computed, inject, input, signal } from '@angular/core';\n\nimport { WR_STEPPER } from './tokens';\n\n/**\n * One step in a {@link WrStepper}. Project as a child:\n *\n * ```html\n * <wr-stepper>\n * <wr-step label=\"Account\"> … </wr-step>\n * <wr-step label=\"Profile\" description=\"Optional\"> … </wr-step>\n * </wr-stepper>\n * ```\n *\n * The stepper hides every step except the active one via a host class —\n * each step still mounts once, so component state survives navigation.\n *\n * @see https://ngwr.dev/reference/components/stepper\n */\n@Component({\n selector: 'wr-step',\n template: '<ng-content />',\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'wr-step',\n '[class.wr-step--active]': 'isActive()',\n },\n})\nexport class WrStep {\n /** Header label. */\n readonly label = input<string>('');\n\n /** Secondary text shown under the label. */\n readonly description = input<string>('');\n\n /** Marks the step as optional in the header. */\n readonly optional = input(false, { transform: coerceBooleanProperty });\n\n /**\n * Override completion state. When unset, the stepper auto-derives it\n * from the active index (any step before `active` is completed).\n */\n readonly completed = input<boolean | null>(null);\n\n /** Disables the header — also blocks header clicks. */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n /** Stepper-assigned index. Set by the parent when contentChildren updates. */\n readonly _index = signal(-1);\n\n private readonly stepper = inject(WR_STEPPER);\n\n protected readonly isActive = computed(() => this._index() === this.stepper.active());\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 { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport {\n Component,\n ViewEncapsulation,\n computed,\n contentChildren,\n effect,\n forwardRef,\n input,\n model,\n} from '@angular/core';\n\nimport { WrStep } from './step';\nimport { WR_STEPPER, type WrStepperContext } from './tokens';\n\n/**\n * Multi-step wizard container. Children are `<wr-step>` components — the\n * stepper renders one numbered header per step (with connectors) and the\n * body of the currently active one.\n *\n * Two-way bind `[(active)]` to the active step index. Set `linear=\"true\"`\n * to forbid jumping past incomplete steps.\n *\n * @example\n * ```html\n * <wr-stepper [(active)]=\"step\" linear>\n * <wr-step label=\"Account\">…</wr-step>\n * <wr-step label=\"Profile\">…</wr-step>\n * <wr-step label=\"Confirm\">…</wr-step>\n * </wr-stepper>\n * ```\n *\n * @see https://ngwr.dev/reference/components/stepper\n */\n@Component({\n selector: 'wr-stepper',\n templateUrl: './stepper.html',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n providers: [\n {\n provide: WR_STEPPER,\n // eslint-disable-next-line @angular-eslint/no-forward-ref\n useExisting: forwardRef(() => WrStepper),\n },\n ],\n})\nexport class WrStepper implements WrStepperContext {\n /** Index of the currently visible step. */\n readonly active = model(0);\n\n /** Layout direction. @default 'horizontal' */\n readonly orientation = input<'horizontal' | 'vertical'>('horizontal');\n\n /** Lock steps after the latest completed one. @default false */\n readonly linear = input(false, { transform: coerceBooleanProperty });\n\n /**\n * Drop a horizontal stepper to a vertical layout when its own box is too\n * narrow for the row (a container query on its own width, not the\n * viewport — so it adapts inside a narrow column or side panel). No effect\n * when `orientation` is already `vertical`. @default false\n */\n readonly responsive = input(false, { transform: coerceBooleanProperty });\n\n protected readonly steps = contentChildren(WrStep);\n\n protected readonly classes = computed(() => {\n const parts = ['wr-stepper', `wr-stepper--${this.orientation()}`];\n if (this.linear()) parts.push('wr-stepper--linear');\n if (this.responsive()) parts.push('wr-stepper--responsive');\n return parts.join(' ');\n });\n\n constructor() {\n // Push each step's index down so it can compute its own active state.\n effect(() => {\n this.steps().forEach((step, i) => step._index.set(i));\n });\n }\n\n /** Is the step at `index` considered completed? */\n protected isCompleted(index: number): boolean {\n const override = this.steps()[index]?.completed();\n if (override !== null && override !== undefined) return override;\n return index < this.active();\n }\n\n /** Is the step at `index` reachable for direct header clicks? */\n protected isReachable(index: number): boolean {\n if (this.steps()[index]?.disabled()) return false;\n if (!this.linear()) return true;\n if (index <= this.active()) return true;\n for (let i = 0; i < index; i++) {\n if (!this.isCompleted(i)) return false;\n }\n return true;\n }\n\n protected onHeaderClick(index: number): void {\n if (this.isReachable(index)) this.goTo(index);\n }\n\n // Imperative API\n\n goTo(index: number): void {\n const last = this.steps().length - 1;\n if (last < 0) return;\n const clamped = Math.min(Math.max(0, index), last);\n this.active.set(clamped);\n }\n\n next(): void {\n this.goTo(this.active() + 1);\n }\n\n prev(): void {\n this.goTo(this.active() - 1);\n }\n}\n","<ol class=\"wr-stepper__headers\" role=\"list\">\n @for (step of steps(); track $index) {\n <li\n class=\"wr-stepper__header\"\n [class.wr-stepper__header--active]=\"$index === active()\"\n [class.wr-stepper__header--completed]=\"isCompleted($index)\"\n [class.wr-stepper__header--reachable]=\"isReachable($index)\"\n [class.wr-stepper__header--disabled]=\"step.disabled()\"\n >\n <button\n type=\"button\"\n class=\"wr-stepper__header-button\"\n [disabled]=\"!isReachable($index) || step.disabled()\"\n [attr.aria-current]=\"$index === active() ? 'step' : null\"\n (click)=\"onHeaderClick($index)\"\n >\n <span class=\"wr-stepper__indicator\" aria-hidden=\"true\">\n @if (isCompleted($index)) {\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\">\n <path\n d=\"M3 7.5 L6 10.5 L11 4.5\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.75\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n } @else {\n {{ $index + 1 }}\n }\n </span>\n <span class=\"wr-stepper__label\">\n {{ step.label() }}\n @if (step.optional()) {\n <small class=\"wr-stepper__optional\">optional</small>\n }\n @if (step.description()) {\n <small class=\"wr-stepper__description\">{{ step.description() }}</small>\n }\n </span>\n </button>\n @if (!$last) {\n <span class=\"wr-stepper__connector\" aria-hidden=\"true\"></span>\n }\n </li>\n }\n</ol>\n\n<div class=\"wr-stepper__body\">\n <ng-content />\n</div>\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-stepper.mjs","sources":["../../../projects/lib/stepper/tokens.ts","../../../projects/lib/stepper/step.ts","../../../projects/lib/stepper/stepper.ts","../../../projects/lib/stepper/stepper.html","../../../projects/lib/stepper/ngwr-stepper.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { InjectionToken, type Signal } from '@angular/core';\n\n/** Surface a {@link WrStepper} provides for its child `<wr-step>`s. */\nexport interface WrStepperContext {\n /** Index of the currently visible step. */\n readonly active: Signal<number>;\n /** Linear mode — steps after the latest completed one are locked. */\n readonly linear: Signal<boolean>;\n}\n\nexport const WR_STEPPER = new InjectionToken<WrStepperContext>('WR_STEPPER');\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { Component, ViewEncapsulation, computed, inject, input, signal } from '@angular/core';\n\nimport { WR_STEPPER } from './tokens';\n\n/**\n * One step in a {@link WrStepper}. Project as a child:\n *\n * ```html\n * <wr-stepper>\n * <wr-step label=\"Account\"> … </wr-step>\n * <wr-step label=\"Profile\" description=\"Optional\"> … </wr-step>\n * </wr-stepper>\n * ```\n *\n * The stepper hides every step except the active one via a host class —\n * each step still mounts once, so component state survives navigation.\n *\n * @see https://ngwr.dev/reference/components/stepper\n */\n@Component({\n selector: 'wr-step',\n template: '<ng-content />',\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'wr-step',\n '[class.wr-step--active]': 'isActive()',\n },\n})\nexport class WrStep {\n /** Header label. */\n readonly label = input<string>('');\n\n /** Secondary text shown under the label. */\n readonly description = input<string>('');\n\n /** Marks the step as optional in the header. */\n readonly optional = input(false, { transform: coerceBooleanProperty });\n\n /**\n * Override completion state. When unset, the stepper auto-derives it\n * from the active index (any step before `active` is completed).\n */\n readonly completed = input<boolean | null>(null);\n\n /** Disables the header — also blocks header clicks. */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n /** Stepper-assigned index. Set by the parent when contentChildren updates. */\n readonly _index = signal(-1);\n\n private readonly stepper = inject(WR_STEPPER);\n\n protected readonly isActive = computed(() => this._index() === this.stepper.active());\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 { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport {\n Component,\n ViewEncapsulation,\n computed,\n contentChildren,\n effect,\n forwardRef,\n input,\n model,\n signal,\n} from '@angular/core';\n\nimport { useI18nText } from 'ngwr/i18n';\n\nimport { WrStep } from './step';\nimport { WR_STEPPER, type WrStepperContext } from './tokens';\n\n/** A label with no consumer input to forward — see `optionalLabel` below. */\nconst NO_OVERRIDE = signal<string | null>(null).asReadonly();\n\n/**\n * Multi-step wizard container. Children are `<wr-step>` components — the\n * stepper renders one numbered header per step (with connectors) and the\n * body of the currently active one.\n *\n * Two-way bind `[(active)]` to the active step index. Set `linear=\"true\"`\n * to forbid jumping past incomplete steps.\n *\n * @example\n * ```html\n * <wr-stepper [(active)]=\"step\" linear>\n * <wr-step label=\"Account\">…</wr-step>\n * <wr-step label=\"Profile\">…</wr-step>\n * <wr-step label=\"Confirm\">…</wr-step>\n * </wr-stepper>\n * ```\n *\n * @see https://ngwr.dev/reference/components/stepper\n */\n@Component({\n selector: 'wr-stepper',\n templateUrl: './stepper.html',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n providers: [\n {\n provide: WR_STEPPER,\n // eslint-disable-next-line @angular-eslint/no-forward-ref\n useExisting: forwardRef(() => WrStepper),\n },\n ],\n})\nexport class WrStepper implements WrStepperContext {\n /** Index of the currently visible step. */\n readonly active = model(0);\n\n /** Layout direction. @default 'horizontal' */\n readonly orientation = input<'horizontal' | 'vertical'>('horizontal');\n\n /** Lock steps after the latest completed one. @default false */\n readonly linear = input(false, { transform: coerceBooleanProperty });\n\n /**\n * Drop a horizontal stepper to a vertical layout when its own box is too\n * narrow for the row (a container query on its own width, not the\n * viewport — so it adapts inside a narrow column or side panel). No effect\n * when `orientation` is already `vertical`. @default false\n */\n readonly responsive = input(false, { transform: coerceBooleanProperty });\n\n protected readonly steps = contentChildren(WrStep);\n\n /**\n * The \"optional\" badge sits INSIDE the header button's label span, so the word\n * is part of the step's accessible name — a hard-coded literal announced English\n * to every locale, not just showed it. Catalog-only rather than an input: the\n * badge is one word shared by every step, and an app that wants other wording\n * overrides `stepper.optional` once instead of on every `<wr-step>`.\n */\n protected readonly optionalLabel = useI18nText(NO_OVERRIDE, 'stepper.optional', 'optional');\n\n protected readonly classes = computed(() => {\n const parts = ['wr-stepper', `wr-stepper--${this.orientation()}`];\n if (this.linear()) parts.push('wr-stepper--linear');\n if (this.responsive()) parts.push('wr-stepper--responsive');\n return parts.join(' ');\n });\n\n constructor() {\n // Push each step's index down so it can compute its own active state.\n effect(() => {\n this.steps().forEach((step, i) => step._index.set(i));\n });\n\n // `active` is a plain `model`, so `[(active)]` and an `@if`-shrunk step list\n // both write into it unchecked — only `goTo` clamped. Out of range no step\n // matches `.wr-step--active`, and since `.wr-step` is `display: none` until it\n // does, the stepper renders its header row over an empty body with no header\n // carrying `aria-current=\"step\"`. Same guard as `wr-carousel`; the `last < 0`\n // return keeps it quiet until `contentChildren` resolves.\n effect(() => {\n const last = this.steps().length - 1;\n if (last < 0) return;\n const clamped = Math.min(Math.max(0, this.active()), last);\n if (clamped !== this.active()) this.active.set(clamped);\n });\n }\n\n /** Is the step at `index` considered completed? */\n protected isCompleted(index: number): boolean {\n const override = this.steps()[index]?.completed();\n if (override !== null && override !== undefined) return override;\n return index < this.active();\n }\n\n /** Is the step at `index` reachable for direct header clicks? */\n protected isReachable(index: number): boolean {\n if (this.steps()[index]?.disabled()) return false;\n if (!this.linear()) return true;\n if (index <= this.active()) return true;\n for (let i = 0; i < index; i++) {\n if (!this.isCompleted(i)) return false;\n }\n return true;\n }\n\n protected onHeaderClick(index: number): void {\n if (this.isReachable(index)) this.goTo(index);\n }\n\n // Imperative API\n\n goTo(index: number): void {\n const last = this.steps().length - 1;\n if (last < 0) return;\n const clamped = Math.min(Math.max(0, index), last);\n this.active.set(clamped);\n }\n\n next(): void {\n this.goTo(this.active() + 1);\n }\n\n prev(): void {\n this.goTo(this.active() - 1);\n }\n}\n","<ol class=\"wr-stepper__headers\" role=\"list\">\n @for (step of steps(); track $index) {\n <li\n class=\"wr-stepper__header\"\n [class.wr-stepper__header--active]=\"$index === active()\"\n [class.wr-stepper__header--completed]=\"isCompleted($index)\"\n [class.wr-stepper__header--reachable]=\"isReachable($index)\"\n [class.wr-stepper__header--disabled]=\"step.disabled()\"\n >\n <button\n type=\"button\"\n class=\"wr-stepper__header-button\"\n [disabled]=\"!isReachable($index) || step.disabled()\"\n [attr.aria-current]=\"$index === active() ? 'step' : null\"\n (click)=\"onHeaderClick($index)\"\n >\n <span class=\"wr-stepper__indicator\" aria-hidden=\"true\">\n @if (isCompleted($index)) {\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\">\n <path\n d=\"M3 7.5 L6 10.5 L11 4.5\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.75\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n } @else {\n {{ $index + 1 }}\n }\n </span>\n <span class=\"wr-stepper__label\">\n {{ step.label() }}\n @if (step.optional()) {\n <small class=\"wr-stepper__optional\">{{ optionalLabel() }}</small>\n }\n @if (step.description()) {\n <small class=\"wr-stepper__description\">{{ step.description() }}</small>\n }\n </span>\n </button>\n @if (!$last) {\n <span class=\"wr-stepper__connector\" aria-hidden=\"true\"></span>\n }\n </li>\n }\n</ol>\n\n<div class=\"wr-stepper__body\">\n <ng-content />\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;AAAA;;;;;AAKG;MAYU,UAAU,GAAG,IAAI,cAAc,CAAmB,YAAY;;ACjB3E;;;;;AAKG;AAOH;;;;;;;;;;;;;;AAcG;MAUU,MAAM,CAAA;;IAER,KAAK,GAAG,KAAK,CAAS,EAAE;8EAAC;;IAGzB,WAAW,GAAG,KAAK,CAAS,EAAE;oFAAC;;IAG/B,QAAQ,GAAG,KAAK,CAAC,KAAK,gFAAI,SAAS,EAAE,qBAAqB,EAAA,CAAG;AAEtE;;;AAGG;IACM,SAAS,GAAG,KAAK,CAAiB,IAAI;kFAAC;;IAGvC,QAAQ,GAAG,KAAK,CAAC,KAAK,gFAAI,SAAS,EAAE,qBAAqB,EAAA,CAAG;;AAG7D,IAAA,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC;+EAAC;AAEX,IAAA,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC;AAE1B,IAAA,QAAQ,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE;iFAAC;uGAxB1E,MAAM,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAN,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAM,mzBAPP,gBAAgB,EAAA,QAAA,EAAA,IAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;2FAOf,MAAM,EAAA,UAAA,EAAA,CAAA;kBATlB,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,SAAS;AACnB,oBAAA,QAAQ,EAAE,gBAAgB;oBAC1B,aAAa,EAAE,iBAAiB,CAAC,IAAI;AACrC,oBAAA,IAAI,EAAE;AACJ,wBAAA,KAAK,EAAE,SAAS;AAChB,wBAAA,yBAAyB,EAAE,YAAY;AACxC,qBAAA;AACF,iBAAA;;;ACnCD;;;;;AAKG;AAoBH;AACA,MAAM,WAAW,GAAG,MAAM,CAAgB,IAAI,CAAC,CAAC,UAAU,EAAE;AAE5D;;;;;;;;;;;;;;;;;;AAkBG;MAcU,SAAS,CAAA;;IAEX,MAAM,GAAG,KAAK,CAAC,CAAC;+EAAC;;IAGjB,WAAW,GAAG,KAAK,CAA4B,YAAY;oFAAC;;IAG5D,MAAM,GAAG,KAAK,CAAC,KAAK,8EAAI,SAAS,EAAE,qBAAqB,EAAA,CAAG;AAEpE;;;;;AAKG;IACM,UAAU,GAAG,KAAK,CAAC,KAAK,kFAAI,SAAS,EAAE,qBAAqB,EAAA,CAAG;IAErD,KAAK,GAAG,eAAe,CAAC,MAAM;8EAAC;AAElD;;;;;;AAMG;IACgB,aAAa,GAAG,WAAW,CAAC,WAAW,EAAE,kBAAkB,EAAE,UAAU,CAAC;AAExE,IAAA,OAAO,GAAG,QAAQ,CAAC,MAAK;AACzC,QAAA,MAAM,KAAK,GAAG,CAAC,YAAY,EAAE,CAAA,YAAA,EAAe,IAAI,CAAC,WAAW,EAAE,CAAA,CAAE,CAAC;QACjE,IAAI,IAAI,CAAC,MAAM,EAAE;AAAE,YAAA,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC;QACnD,IAAI,IAAI,CAAC,UAAU,EAAE;AAAE,YAAA,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC;AAC3D,QAAA,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;IACxB,CAAC;gFAAC;AAEF,IAAA,WAAA,GAAA;;QAEE,MAAM,CAAC,MAAK;YACV,IAAI,CAAC,KAAK,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACvD,QAAA,CAAC,CAAC;;;;;;;QAQF,MAAM,CAAC,MAAK;YACV,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,MAAM,GAAG,CAAC;YACpC,IAAI,IAAI,GAAG,CAAC;gBAAE;YACd,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,IAAI,CAAC;AAC1D,YAAA,IAAI,OAAO,KAAK,IAAI,CAAC,MAAM,EAAE;AAAE,gBAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC;AACzD,QAAA,CAAC,CAAC;IACJ;;AAGU,IAAA,WAAW,CAAC,KAAa,EAAA;AACjC,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE;AACjD,QAAA,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,KAAK,SAAS;AAAE,YAAA,OAAO,QAAQ;AAChE,QAAA,OAAO,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE;IAC9B;;AAGU,IAAA,WAAW,CAAC,KAAa,EAAA;QACjC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE;AAAE,YAAA,OAAO,KAAK;AACjD,QAAA,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;AAAE,YAAA,OAAO,IAAI;AAC/B,QAAA,IAAI,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE;AAAE,YAAA,OAAO,IAAI;AACvC,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE;AAC9B,YAAA,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;AAAE,gBAAA,OAAO,KAAK;QACxC;AACA,QAAA,OAAO,IAAI;IACb;AAEU,IAAA,aAAa,CAAC,KAAa,EAAA;AACnC,QAAA,IAAI,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;AAAE,YAAA,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;IAC/C;;AAIA,IAAA,IAAI,CAAC,KAAa,EAAA;QAChB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,MAAM,GAAG,CAAC;QACpC,IAAI,IAAI,GAAG,CAAC;YAAE;AACd,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,IAAI,CAAC;AAClD,QAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC;IAC1B;IAEA,IAAI,GAAA;QACF,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC9B;IAEA,IAAI,GAAA;QACF,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC9B;uGA7FW,SAAS,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAT,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,SAAS,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,YAAA,EAAA,MAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,MAAA,EAAA,cAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,OAAA,EAAA,WAAA,EAAA,EAAA,EAAA,SAAA,EART;AACT,YAAA;AACE,gBAAA,OAAO,EAAE,UAAU;;AAEnB,gBAAA,WAAW,EAAE,UAAU,CAAC,MAAM,SAAS,CAAC;AACzC,aAAA;SACF,EAAA,OAAA,EAAA,CAAA,EAAA,YAAA,EAAA,OAAA,EAAA,SAAA,EAoB0C,MAAM,6CC9EnD,ixDAoDA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;2FDQa,SAAS,EAAA,UAAA,EAAA,CAAA;kBAbrB,SAAS;+BACE,YAAY,EAAA,aAAA,EAEP,iBAAiB,CAAC,IAAI,EAAA,IAAA,EAC/B,EAAE,SAAS,EAAE,WAAW,EAAE,EAAA,SAAA,EACrB;AACT,wBAAA;AACE,4BAAA,OAAO,EAAE,UAAU;;AAEnB,4BAAA,WAAW,EAAE,UAAU,CAAC,eAAe,CAAC;AACzC,yBAAA;AACF,qBAAA,EAAA,QAAA,EAAA,ixDAAA,EAAA;siBAoB0C,MAAM,CAAA,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,EAAA,CAAA;;AE9EnD;;AAEG;;;;"}
@@ -1,6 +1,6 @@
1
1
  import { isPlatformBrowser } from '@angular/common';
2
2
  import * as i0 from '@angular/core';
3
- import { InjectionToken, inject, PLATFORM_ID, signal, Service, makeEnvironmentProviders } from '@angular/core';
3
+ import { InjectionToken, inject, DestroyRef, PLATFORM_ID, signal, Service, makeEnvironmentProviders } from '@angular/core';
4
4
 
5
5
  /**
6
6
  * @license
@@ -131,6 +131,7 @@ function isEnvelope(x) {
131
131
  class WrStorage {
132
132
  engine = inject(WR_STORAGE_ENGINE);
133
133
  config = inject(WR_STORAGE_CONFIG);
134
+ destroyRef = inject(DestroyRef);
134
135
  isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
135
136
  /**
136
137
  * Per-key watchers. Shared so multiple `watch(k)` calls reuse one signal.
@@ -278,7 +279,7 @@ class WrStorage {
278
279
  if (!this.isBrowser || this.listenerInstalled)
279
280
  return;
280
281
  this.listenerInstalled = true;
281
- window.addEventListener('storage', (event) => {
282
+ const handler = (event) => {
282
283
  // `storage` only fires for `localStorage` / `sessionStorage`, and
283
284
  // only for changes from OTHER tabs. Local writes are handled by
284
285
  // `notify()` in `set`/`remove`/`clear`.
@@ -292,12 +293,23 @@ class WrStorage {
292
293
  if (p && !event.key.startsWith(p))
293
294
  return;
294
295
  this.notify(p ? event.key.slice(p.length) : event.key);
296
+ };
297
+ window.addEventListener('storage', handler);
298
+ // The listener belongs to THIS injector. Root-provided it lives as long as
299
+ // the page, but a route or component that lists `WrStorage` in its own
300
+ // `providers` used to leave the handler on the window after its injector was
301
+ // gone — still driving the watcher signals of a destroyed instance, and
302
+ // holding the instance and every signal in it reachable for the life of the
303
+ // page. Same bug `WrHotkey` already fixed once.
304
+ this.destroyRef.onDestroy(() => {
305
+ window.removeEventListener('storage', handler);
306
+ this.listenerInstalled = false;
295
307
  });
296
308
  }
297
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrStorage, deps: [], target: i0.ɵɵFactoryTarget.Service });
298
- static ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.1", ngImport: i0, type: WrStorage });
309
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrStorage, deps: [], target: i0.ɵɵFactoryTarget.Service });
310
+ static ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.4", ngImport: i0, type: WrStorage });
299
311
  }
300
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrStorage, decorators: [{
312
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrStorage, decorators: [{
301
313
  type: Service
302
314
  }] });
303
315