ngwr 11.1.0 → 12.0.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 (481) hide show
  1. package/README.md +7 -7
  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/circular-text/styles/_index.scss +11 -0
  10. package/collapse/styles/_index.scss +2 -2
  11. package/color-picker/styles/_index.scss +3 -3
  12. package/command-palette/styles/_index.scss +12 -0
  13. package/compare/styles/_index.scss +18 -2
  14. package/context-menu/styles/_index.scss +21 -2
  15. package/date-picker/styles/_index.scss +5 -5
  16. package/descriptions/styles/_index.scss +1 -1
  17. package/drag-drop/styles/_index.scss +28 -1
  18. package/drawer/styles/_index.scss +37 -0
  19. package/dropdown/styles/_index.scss +2 -2
  20. package/event-calendar/styles/_index.scss +67 -10
  21. package/fesm2022/ngwr-action-sheet-testing.mjs +313 -0
  22. package/fesm2022/ngwr-action-sheet-testing.mjs.map +1 -0
  23. package/fesm2022/ngwr-action-sheet.mjs +3 -3
  24. package/fesm2022/ngwr-affix.mjs +3 -3
  25. package/fesm2022/ngwr-alert.mjs +3 -3
  26. package/fesm2022/ngwr-anchor.mjs +3 -3
  27. package/fesm2022/ngwr-aurora.mjs +3 -3
  28. package/fesm2022/ngwr-avatar.mjs +3 -3
  29. package/fesm2022/ngwr-back-top.mjs +3 -3
  30. package/fesm2022/ngwr-badge.mjs +6 -6
  31. package/fesm2022/ngwr-bar-chart-testing.mjs +107 -0
  32. package/fesm2022/ngwr-bar-chart-testing.mjs.map +1 -0
  33. package/fesm2022/ngwr-bar-chart.mjs +3 -3
  34. package/fesm2022/ngwr-blur-text-testing.mjs +203 -0
  35. package/fesm2022/ngwr-blur-text-testing.mjs.map +1 -0
  36. package/fesm2022/ngwr-blur-text.mjs +18 -4
  37. package/fesm2022/ngwr-blur-text.mjs.map +1 -1
  38. package/fesm2022/ngwr-border-glow-testing.mjs +325 -0
  39. package/fesm2022/ngwr-border-glow-testing.mjs.map +1 -0
  40. package/fesm2022/ngwr-border-glow.mjs +4 -4
  41. package/fesm2022/ngwr-border-glow.mjs.map +1 -1
  42. package/fesm2022/ngwr-breadcrumbs.mjs +29 -17
  43. package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
  44. package/fesm2022/ngwr-burger.mjs +3 -3
  45. package/fesm2022/ngwr-button.mjs +6 -6
  46. package/fesm2022/ngwr-calendar-heatmap-testing.mjs +95 -0
  47. package/fesm2022/ngwr-calendar-heatmap-testing.mjs.map +1 -0
  48. package/fesm2022/ngwr-calendar-heatmap.mjs +17 -5
  49. package/fesm2022/ngwr-calendar-heatmap.mjs.map +1 -1
  50. package/fesm2022/ngwr-calendar-testing.mjs +368 -0
  51. package/fesm2022/ngwr-calendar-testing.mjs.map +1 -0
  52. package/fesm2022/ngwr-calendar.mjs +228 -10
  53. package/fesm2022/ngwr-calendar.mjs.map +1 -1
  54. package/fesm2022/ngwr-card.mjs +10 -10
  55. package/fesm2022/ngwr-card.mjs.map +1 -1
  56. package/fesm2022/ngwr-carousel.mjs +124 -24
  57. package/fesm2022/ngwr-carousel.mjs.map +1 -1
  58. package/fesm2022/ngwr-cascader.mjs +60 -5
  59. package/fesm2022/ngwr-cascader.mjs.map +1 -1
  60. package/fesm2022/ngwr-checkbox.mjs +14 -6
  61. package/fesm2022/ngwr-checkbox.mjs.map +1 -1
  62. package/fesm2022/ngwr-circular-text-testing.mjs +230 -0
  63. package/fesm2022/ngwr-circular-text-testing.mjs.map +1 -0
  64. package/fesm2022/ngwr-circular-text.mjs +4 -4
  65. package/fesm2022/ngwr-circular-text.mjs.map +1 -1
  66. package/fesm2022/ngwr-click-spark.mjs +27 -7
  67. package/fesm2022/ngwr-click-spark.mjs.map +1 -1
  68. package/fesm2022/ngwr-clipboard.mjs +3 -3
  69. package/fesm2022/ngwr-collapse.mjs +9 -9
  70. package/fesm2022/ngwr-color-picker-testing.mjs +452 -0
  71. package/fesm2022/ngwr-color-picker-testing.mjs.map +1 -0
  72. package/fesm2022/ngwr-color-picker.mjs +126 -10
  73. package/fesm2022/ngwr-color-picker.mjs.map +1 -1
  74. package/fesm2022/ngwr-command-palette.mjs +14 -5
  75. package/fesm2022/ngwr-command-palette.mjs.map +1 -1
  76. package/fesm2022/ngwr-compare.mjs +3 -3
  77. package/fesm2022/ngwr-confetti.mjs +31 -6
  78. package/fesm2022/ngwr-confetti.mjs.map +1 -1
  79. package/fesm2022/ngwr-config.mjs +9 -0
  80. package/fesm2022/ngwr-config.mjs.map +1 -1
  81. package/fesm2022/ngwr-context-menu-testing.mjs +30 -11
  82. package/fesm2022/ngwr-context-menu-testing.mjs.map +1 -1
  83. package/fesm2022/ngwr-context-menu.mjs +358 -48
  84. package/fesm2022/ngwr-context-menu.mjs.map +1 -1
  85. package/fesm2022/ngwr-cookie.mjs +3 -3
  86. package/fesm2022/ngwr-counter.mjs +25 -9
  87. package/fesm2022/ngwr-counter.mjs.map +1 -1
  88. package/fesm2022/{ngwr-date-adapter-fns.mjs → ngwr-date-adapters-fns.mjs} +37 -10
  89. package/fesm2022/ngwr-date-adapters-fns.mjs.map +1 -0
  90. package/fesm2022/{ngwr-date-adapter-luxon.mjs → ngwr-date-adapters-luxon.mjs} +5 -5
  91. package/fesm2022/ngwr-date-adapters-luxon.mjs.map +1 -0
  92. package/fesm2022/ngwr-date-picker-testing.mjs +21 -85
  93. package/fesm2022/ngwr-date-picker-testing.mjs.map +1 -1
  94. package/fesm2022/ngwr-date-picker.mjs +119 -37
  95. package/fesm2022/ngwr-date-picker.mjs.map +1 -1
  96. package/fesm2022/{ngwr-date-adapter.mjs → ngwr-date.mjs} +36 -10
  97. package/fesm2022/ngwr-date.mjs.map +1 -0
  98. package/fesm2022/ngwr-decrypt-text-testing.mjs +261 -0
  99. package/fesm2022/ngwr-decrypt-text-testing.mjs.map +1 -0
  100. package/fesm2022/ngwr-decrypt-text.mjs +9 -4
  101. package/fesm2022/ngwr-decrypt-text.mjs.map +1 -1
  102. package/fesm2022/ngwr-density.mjs +6 -6
  103. package/fesm2022/ngwr-descriptions.mjs +6 -6
  104. package/fesm2022/ngwr-dialog.mjs +73 -18
  105. package/fesm2022/ngwr-dialog.mjs.map +1 -1
  106. package/fesm2022/ngwr-directives.mjs +12 -12
  107. package/fesm2022/ngwr-divider.mjs +52 -5
  108. package/fesm2022/ngwr-divider.mjs.map +1 -1
  109. package/fesm2022/ngwr-donut-chart-testing.mjs +97 -0
  110. package/fesm2022/ngwr-donut-chart-testing.mjs.map +1 -0
  111. package/fesm2022/ngwr-donut-chart.mjs +7 -7
  112. package/fesm2022/ngwr-donut-chart.mjs.map +1 -1
  113. package/fesm2022/ngwr-drag-drop.mjs +160 -11
  114. package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
  115. package/fesm2022/ngwr-drawer.mjs +156 -64
  116. package/fesm2022/ngwr-drawer.mjs.map +1 -1
  117. package/fesm2022/ngwr-dropdown.mjs +58 -12
  118. package/fesm2022/ngwr-dropdown.mjs.map +1 -1
  119. package/fesm2022/ngwr-empty.mjs +3 -3
  120. package/fesm2022/ngwr-event-calendar-testing.mjs +446 -0
  121. package/fesm2022/ngwr-event-calendar-testing.mjs.map +1 -0
  122. package/fesm2022/ngwr-event-calendar.mjs +66 -28
  123. package/fesm2022/ngwr-event-calendar.mjs.map +1 -1
  124. package/fesm2022/ngwr-falling-text-testing.mjs +220 -0
  125. package/fesm2022/ngwr-falling-text-testing.mjs.map +1 -0
  126. package/fesm2022/ngwr-falling-text.mjs +75 -46
  127. package/fesm2022/ngwr-falling-text.mjs.map +1 -1
  128. package/fesm2022/ngwr-file-upload.mjs +3 -3
  129. package/fesm2022/ngwr-form.mjs +32 -15
  130. package/fesm2022/ngwr-form.mjs.map +1 -1
  131. package/fesm2022/ngwr-fuzzy-text-testing.mjs +134 -0
  132. package/fesm2022/ngwr-fuzzy-text-testing.mjs.map +1 -0
  133. package/fesm2022/ngwr-fuzzy-text.mjs +21 -11
  134. package/fesm2022/ngwr-fuzzy-text.mjs.map +1 -1
  135. package/fesm2022/ngwr-gauge-testing.mjs +86 -0
  136. package/fesm2022/ngwr-gauge-testing.mjs.map +1 -0
  137. package/fesm2022/ngwr-gauge.mjs +3 -3
  138. package/fesm2022/ngwr-glitch-text-testing.mjs +215 -0
  139. package/fesm2022/ngwr-glitch-text-testing.mjs.map +1 -0
  140. package/fesm2022/ngwr-glitch-text.mjs +7 -7
  141. package/fesm2022/ngwr-glitch-text.mjs.map +1 -1
  142. package/fesm2022/ngwr-gradient-text-testing.mjs +258 -0
  143. package/fesm2022/ngwr-gradient-text-testing.mjs.map +1 -0
  144. package/fesm2022/ngwr-gradient-text.mjs +4 -4
  145. package/fesm2022/ngwr-gradient-text.mjs.map +1 -1
  146. package/fesm2022/ngwr-hotkey.mjs +24 -9
  147. package/fesm2022/ngwr-hotkey.mjs.map +1 -1
  148. package/fesm2022/ngwr-i18n-en.mjs +87 -1
  149. package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
  150. package/fesm2022/ngwr-i18n-ru.mjs +69 -1
  151. package/fesm2022/ngwr-i18n-ru.mjs.map +1 -1
  152. package/fesm2022/ngwr-i18n.mjs +26 -15
  153. package/fesm2022/ngwr-i18n.mjs.map +1 -1
  154. package/fesm2022/ngwr-icon.mjs +6 -6
  155. package/fesm2022/ngwr-image-cropper-testing.mjs +200 -0
  156. package/fesm2022/ngwr-image-cropper-testing.mjs.map +1 -0
  157. package/fesm2022/ngwr-image-cropper.mjs +156 -11
  158. package/fesm2022/ngwr-image-cropper.mjs.map +1 -1
  159. package/fesm2022/ngwr-input-number-testing.mjs +15 -10
  160. package/fesm2022/ngwr-input-number-testing.mjs.map +1 -1
  161. package/fesm2022/ngwr-input-number.mjs +89 -15
  162. package/fesm2022/ngwr-input-number.mjs.map +1 -1
  163. package/fesm2022/ngwr-input-otp-testing.mjs +12 -6
  164. package/fesm2022/ngwr-input-otp-testing.mjs.map +1 -1
  165. package/fesm2022/ngwr-input-otp.mjs +24 -5
  166. package/fesm2022/ngwr-input-otp.mjs.map +1 -1
  167. package/fesm2022/ngwr-input.mjs +15 -15
  168. package/fesm2022/ngwr-keyboard.mjs +3 -3
  169. package/fesm2022/ngwr-knob-testing.mjs +220 -0
  170. package/fesm2022/ngwr-knob-testing.mjs.map +1 -0
  171. package/fesm2022/ngwr-knob.mjs +3 -3
  172. package/fesm2022/ngwr-layout.mjs +15 -15
  173. package/fesm2022/ngwr-lightbox-testing.mjs +223 -0
  174. package/fesm2022/ngwr-lightbox-testing.mjs.map +1 -0
  175. package/fesm2022/ngwr-lightbox.mjs +11 -4
  176. package/fesm2022/ngwr-lightbox.mjs.map +1 -1
  177. package/fesm2022/ngwr-line-chart-testing.mjs +119 -0
  178. package/fesm2022/ngwr-line-chart-testing.mjs.map +1 -0
  179. package/fesm2022/ngwr-line-chart.mjs +73 -26
  180. package/fesm2022/ngwr-line-chart.mjs.map +1 -1
  181. package/fesm2022/ngwr-list.mjs +7 -7
  182. package/fesm2022/ngwr-list.mjs.map +1 -1
  183. package/fesm2022/ngwr-loading-bar.mjs +7 -7
  184. package/fesm2022/ngwr-loading-bar.mjs.map +1 -1
  185. package/fesm2022/ngwr-markdown.mjs +66 -8
  186. package/fesm2022/ngwr-markdown.mjs.map +1 -1
  187. package/fesm2022/ngwr-marquee-testing.mjs +336 -0
  188. package/fesm2022/ngwr-marquee-testing.mjs.map +1 -0
  189. package/fesm2022/ngwr-marquee.mjs +4 -4
  190. package/fesm2022/ngwr-marquee.mjs.map +1 -1
  191. package/fesm2022/ngwr-media.mjs +3 -3
  192. package/fesm2022/ngwr-mention.mjs +108 -13
  193. package/fesm2022/ngwr-mention.mjs.map +1 -1
  194. package/fesm2022/ngwr-meta.mjs +6 -6
  195. package/fesm2022/ngwr-meter-group-testing.mjs +100 -0
  196. package/fesm2022/ngwr-meter-group-testing.mjs.map +1 -0
  197. package/fesm2022/ngwr-meter-group.mjs +3 -3
  198. package/fesm2022/ngwr-overlay.mjs +34 -7
  199. package/fesm2022/ngwr-overlay.mjs.map +1 -1
  200. package/fesm2022/ngwr-page-header.mjs +3 -3
  201. package/fesm2022/ngwr-pagination-testing.mjs +6 -6
  202. package/fesm2022/ngwr-pagination-testing.mjs.map +1 -1
  203. package/fesm2022/ngwr-pagination.mjs +17 -13
  204. package/fesm2022/ngwr-pagination.mjs.map +1 -1
  205. package/fesm2022/ngwr-pipes.mjs +39 -26
  206. package/fesm2022/ngwr-pipes.mjs.map +1 -1
  207. package/fesm2022/ngwr-platform.mjs +9 -9
  208. package/fesm2022/ngwr-popconfirm.mjs +6 -6
  209. package/fesm2022/ngwr-popover-testing.mjs +7 -2
  210. package/fesm2022/ngwr-popover-testing.mjs.map +1 -1
  211. package/fesm2022/ngwr-popover.mjs +169 -33
  212. package/fesm2022/ngwr-popover.mjs.map +1 -1
  213. package/fesm2022/ngwr-progress.mjs +3 -3
  214. package/fesm2022/ngwr-pull-to-refresh.mjs +3 -3
  215. package/fesm2022/ngwr-qr.mjs +42 -5
  216. package/fesm2022/ngwr-qr.mjs.map +1 -1
  217. package/fesm2022/ngwr-radio.mjs +6 -6
  218. package/fesm2022/ngwr-rating.mjs +3 -3
  219. package/fesm2022/ngwr-result.mjs +21 -30
  220. package/fesm2022/ngwr-result.mjs.map +1 -1
  221. package/fesm2022/ngwr-rotating-text-testing.mjs +220 -0
  222. package/fesm2022/ngwr-rotating-text-testing.mjs.map +1 -0
  223. package/fesm2022/ngwr-rotating-text.mjs +4 -4
  224. package/fesm2022/ngwr-rotating-text.mjs.map +1 -1
  225. package/fesm2022/ngwr-scroll.mjs +3 -3
  226. package/fesm2022/ngwr-segmented-testing.mjs +14 -1
  227. package/fesm2022/ngwr-segmented-testing.mjs.map +1 -1
  228. package/fesm2022/ngwr-segmented.mjs +29 -6
  229. package/fesm2022/ngwr-segmented.mjs.map +1 -1
  230. package/fesm2022/ngwr-select.mjs +227 -43
  231. package/fesm2022/ngwr-select.mjs.map +1 -1
  232. package/fesm2022/ngwr-shiny-text-testing.mjs +237 -0
  233. package/fesm2022/ngwr-shiny-text-testing.mjs.map +1 -0
  234. package/fesm2022/ngwr-shiny-text.mjs +11 -9
  235. package/fesm2022/ngwr-shiny-text.mjs.map +1 -1
  236. package/fesm2022/ngwr-sidebar.mjs +31 -16
  237. package/fesm2022/ngwr-sidebar.mjs.map +1 -1
  238. package/fesm2022/ngwr-skeleton.mjs +3 -3
  239. package/fesm2022/ngwr-slider.mjs +143 -14
  240. package/fesm2022/ngwr-slider.mjs.map +1 -1
  241. package/fesm2022/ngwr-sparkline-testing.mjs +76 -0
  242. package/fesm2022/ngwr-sparkline-testing.mjs.map +1 -0
  243. package/fesm2022/ngwr-sparkline.mjs +3 -3
  244. package/fesm2022/ngwr-speed-dial-testing.mjs +281 -0
  245. package/fesm2022/ngwr-speed-dial-testing.mjs.map +1 -0
  246. package/fesm2022/ngwr-speed-dial.mjs +27 -12
  247. package/fesm2022/ngwr-speed-dial.mjs.map +1 -1
  248. package/fesm2022/ngwr-spinner.mjs +3 -3
  249. package/fesm2022/ngwr-splash-cursor-testing.mjs +89 -0
  250. package/fesm2022/ngwr-splash-cursor-testing.mjs.map +1 -0
  251. package/fesm2022/ngwr-splash-cursor.mjs +3 -3
  252. package/fesm2022/ngwr-split-text-testing.mjs +224 -0
  253. package/fesm2022/ngwr-split-text-testing.mjs.map +1 -0
  254. package/fesm2022/ngwr-split-text.mjs +31 -5
  255. package/fesm2022/ngwr-split-text.mjs.map +1 -1
  256. package/fesm2022/ngwr-splitter-testing.mjs +245 -0
  257. package/fesm2022/ngwr-splitter-testing.mjs.map +1 -0
  258. package/fesm2022/ngwr-splitter.mjs +3 -3
  259. package/fesm2022/ngwr-spotlight-card-testing.mjs +368 -0
  260. package/fesm2022/ngwr-spotlight-card-testing.mjs.map +1 -0
  261. package/fesm2022/ngwr-spotlight-card.mjs +7 -7
  262. package/fesm2022/ngwr-spotlight-card.mjs.map +1 -1
  263. package/fesm2022/ngwr-squircle.mjs +6 -6
  264. package/fesm2022/ngwr-star-border-testing.mjs +172 -0
  265. package/fesm2022/ngwr-star-border-testing.mjs.map +1 -0
  266. package/fesm2022/ngwr-star-border.mjs +4 -4
  267. package/fesm2022/ngwr-star-border.mjs.map +1 -1
  268. package/fesm2022/ngwr-statistic.mjs +9 -9
  269. package/fesm2022/ngwr-stepper-testing.mjs +8 -8
  270. package/fesm2022/ngwr-stepper-testing.mjs.map +1 -1
  271. package/fesm2022/ngwr-stepper.mjs +33 -8
  272. package/fesm2022/ngwr-stepper.mjs.map +1 -1
  273. package/fesm2022/ngwr-storage.mjs +17 -5
  274. package/fesm2022/ngwr-storage.mjs.map +1 -1
  275. package/fesm2022/ngwr-switch.mjs +3 -3
  276. package/fesm2022/ngwr-table.mjs +110 -40
  277. package/fesm2022/ngwr-table.mjs.map +1 -1
  278. package/fesm2022/ngwr-tabs-testing.mjs +11 -10
  279. package/fesm2022/ngwr-tabs-testing.mjs.map +1 -1
  280. package/fesm2022/ngwr-tabs.mjs +51 -11
  281. package/fesm2022/ngwr-tabs.mjs.map +1 -1
  282. package/fesm2022/ngwr-textarea.mjs +3 -3
  283. package/fesm2022/ngwr-theme.mjs +181 -4
  284. package/fesm2022/ngwr-theme.mjs.map +1 -1
  285. package/fesm2022/ngwr-tilt-card-testing.mjs +190 -0
  286. package/fesm2022/ngwr-tilt-card-testing.mjs.map +1 -0
  287. package/fesm2022/ngwr-tilt-card.mjs +26 -8
  288. package/fesm2022/ngwr-tilt-card.mjs.map +1 -1
  289. package/fesm2022/ngwr-timeline.mjs +6 -6
  290. package/fesm2022/ngwr-toast.mjs +44 -15
  291. package/fesm2022/ngwr-toast.mjs.map +1 -1
  292. package/fesm2022/ngwr-toolbar.mjs +3 -3
  293. package/fesm2022/ngwr-tour-testing.mjs +173 -0
  294. package/fesm2022/ngwr-tour-testing.mjs.map +1 -0
  295. package/fesm2022/ngwr-tour.mjs +34 -10
  296. package/fesm2022/ngwr-tour.mjs.map +1 -1
  297. package/fesm2022/ngwr-transfer.mjs +3 -3
  298. package/fesm2022/ngwr-tree.mjs +36 -11
  299. package/fesm2022/ngwr-tree.mjs.map +1 -1
  300. package/fesm2022/ngwr-typewriter-testing.mjs +242 -0
  301. package/fesm2022/ngwr-typewriter-testing.mjs.map +1 -0
  302. package/fesm2022/ngwr-typewriter.mjs +13 -5
  303. package/fesm2022/ngwr-typewriter.mjs.map +1 -1
  304. package/fesm2022/ngwr-typography.mjs +3 -3
  305. package/fesm2022/ngwr-utils.mjs +5 -2
  306. package/fesm2022/ngwr-utils.mjs.map +1 -1
  307. package/fesm2022/ngwr-version.mjs +1 -1
  308. package/fesm2022/ngwr-version.mjs.map +1 -1
  309. package/fesm2022/ngwr-virtual-scroll.mjs +4 -4
  310. package/fesm2022/ngwr-virtual-scroll.mjs.map +1 -1
  311. package/fesm2022/ngwr-waves-testing.mjs +128 -0
  312. package/fesm2022/ngwr-waves-testing.mjs.map +1 -0
  313. package/fesm2022/ngwr-waves.mjs +4 -4
  314. package/fesm2022/ngwr-waves.mjs.map +1 -1
  315. package/fesm2022/ngwr-window-testing.mjs +361 -0
  316. package/fesm2022/ngwr-window-testing.mjs.map +1 -0
  317. package/fesm2022/ngwr-window.mjs +175 -31
  318. package/fesm2022/ngwr-window.mjs.map +1 -1
  319. package/file-upload/styles/_index.scss +2 -2
  320. package/glitch-text/styles/_index.scss +27 -12
  321. package/i18n/en.json +71 -7
  322. package/i18n/ru.json +71 -7
  323. package/image-cropper/styles/_index.scss +19 -0
  324. package/input/styles/_index.scss +2 -2
  325. package/input-number/styles/_index.scss +2 -2
  326. package/input-otp/styles/_index.scss +9 -2
  327. package/knob/styles/_index.scss +1 -1
  328. package/lightbox/styles/_index.scss +16 -2
  329. package/line-chart/styles/_index.scss +28 -14
  330. package/list/styles/_index.scss +1 -1
  331. package/llms-full.txt +161 -19
  332. package/llms.txt +45 -10
  333. package/markdown/styles/_index.scss +3 -3
  334. package/mcp/api.js +6 -4
  335. package/mcp/catalog.js +40 -3
  336. package/mcp/providers.js +42 -0
  337. package/mcp/tools.js +22 -30
  338. package/meter-group/styles/_index.scss +1 -1
  339. package/overlay/styles/_index.scss +33 -1
  340. package/package.json +161 -12
  341. package/pagination/styles/_index.scss +23 -1
  342. package/popover/styles/_index.scss +16 -7
  343. package/progress/styles/_index.scss +1 -1
  344. package/radio/styles/_index.scss +2 -2
  345. package/rating/styles/_index.scss +1 -1
  346. package/schematics/collection.json +1 -1
  347. package/schematics/migrations/v12/index.js +65 -0
  348. package/schematics/migrations/v7/index.js +12 -1
  349. package/schematics/migrations/v8/index.js +10 -1
  350. package/schematics/migrations.json +5 -0
  351. package/schematics/ng-add/index.js +8 -3
  352. package/schematics/provider/index.js +80 -13
  353. package/schematics/use/index.js +9 -129
  354. package/schematics/use/rule.js +206 -0
  355. package/schematics/use/symbol-map.json +4 -4
  356. package/segmented/styles/_index.scss +14 -3
  357. package/select/styles/_index.scss +14 -2
  358. package/sidebar/styles/_index.scss +12 -10
  359. package/skills/ngwr/SKILL.md +117 -0
  360. package/skills/ngwr/references/catalog.md +212 -0
  361. package/skills/ngwr/references/setup.md +78 -0
  362. package/slider/styles/_index.scss +1 -1
  363. package/speed-dial/styles/_index.scss +1 -1
  364. package/stepper/styles/_index.scss +12 -3
  365. package/switch/styles/_index.scss +2 -2
  366. package/table/styles/_index.scss +61 -12
  367. package/tabs/styles/_index.scss +1 -1
  368. package/textarea/styles/_index.scss +1 -1
  369. package/theme/styles/_colors.scss +142 -56
  370. package/theme/styles/_dark.scss +46 -3
  371. package/theme/styles/_focus.scss +28 -5
  372. package/theme/styles/_mixins.scss +1 -1
  373. package/theme/styles/_variables.scss +67 -0
  374. package/transfer/styles/_index.scss +26 -3
  375. package/tree/styles/_index.scss +29 -6
  376. package/types/ngwr-action-sheet-testing.d.ts +260 -0
  377. package/types/ngwr-bar-chart-testing.d.ts +85 -0
  378. package/types/ngwr-blur-text-testing.d.ts +180 -0
  379. package/types/ngwr-blur-text.d.ts +20 -4
  380. package/types/ngwr-border-glow-testing.d.ts +219 -0
  381. package/types/ngwr-breadcrumbs.d.ts +17 -10
  382. package/types/ngwr-calendar-heatmap-testing.d.ts +79 -0
  383. package/types/ngwr-calendar-testing.d.ts +277 -0
  384. package/types/ngwr-calendar.d.ts +76 -0
  385. package/types/ngwr-carousel.d.ts +85 -6
  386. package/types/ngwr-cascader.d.ts +17 -0
  387. package/types/ngwr-checkbox.d.ts +13 -0
  388. package/types/ngwr-circular-text-testing.d.ts +196 -0
  389. package/types/ngwr-click-spark.d.ts +4 -0
  390. package/types/ngwr-color-picker-testing.d.ts +299 -0
  391. package/types/ngwr-color-picker.d.ts +34 -2
  392. package/types/ngwr-confetti.d.ts +8 -0
  393. package/types/ngwr-config.d.ts +10 -1
  394. package/types/ngwr-context-menu-testing.d.ts +24 -11
  395. package/types/ngwr-context-menu.d.ts +71 -1
  396. package/types/ngwr-counter.d.ts +1 -0
  397. package/types/{ngwr-date-adapter-fns.d.ts → ngwr-date-adapters-fns.d.ts} +33 -6
  398. package/types/{ngwr-date-adapter-luxon.d.ts → ngwr-date-adapters-luxon.d.ts} +1 -1
  399. package/types/ngwr-date-picker-testing.d.ts +17 -72
  400. package/types/ngwr-date-picker.d.ts +8 -4
  401. package/types/{ngwr-date-adapter.d.ts → ngwr-date.d.ts} +24 -5
  402. package/types/ngwr-decrypt-text-testing.d.ts +222 -0
  403. package/types/ngwr-dialog.d.ts +38 -1
  404. package/types/ngwr-divider.d.ts +25 -0
  405. package/types/ngwr-donut-chart-testing.d.ts +83 -0
  406. package/types/ngwr-donut-chart.d.ts +3 -3
  407. package/types/ngwr-drag-drop.d.ts +56 -2
  408. package/types/ngwr-drawer.d.ts +68 -5
  409. package/types/ngwr-dropdown.d.ts +9 -0
  410. package/types/ngwr-event-calendar-testing.d.ts +301 -0
  411. package/types/ngwr-event-calendar.d.ts +17 -8
  412. package/types/ngwr-falling-text-testing.d.ts +188 -0
  413. package/types/ngwr-falling-text.d.ts +1 -1
  414. package/types/ngwr-form.d.ts +12 -2
  415. package/types/ngwr-fuzzy-text-testing.d.ts +130 -0
  416. package/types/ngwr-gauge-testing.d.ts +71 -0
  417. package/types/ngwr-glitch-text-testing.d.ts +201 -0
  418. package/types/ngwr-gradient-text-testing.d.ts +186 -0
  419. package/types/ngwr-i18n.d.ts +13 -4
  420. package/types/ngwr-image-cropper-testing.d.ts +173 -0
  421. package/types/ngwr-image-cropper.d.ts +71 -5
  422. package/types/ngwr-input-number-testing.d.ts +15 -10
  423. package/types/ngwr-input-number.d.ts +44 -5
  424. package/types/ngwr-input-otp-testing.d.ts +12 -6
  425. package/types/ngwr-input-otp.d.ts +15 -1
  426. package/types/ngwr-knob-testing.d.ts +150 -0
  427. package/types/ngwr-lightbox-testing.d.ts +154 -0
  428. package/types/ngwr-lightbox.d.ts +6 -0
  429. package/types/ngwr-line-chart-testing.d.ts +93 -0
  430. package/types/ngwr-line-chart.d.ts +20 -3
  431. package/types/ngwr-markdown.d.ts +11 -0
  432. package/types/ngwr-marquee-testing.d.ts +280 -0
  433. package/types/ngwr-mention.d.ts +32 -0
  434. package/types/ngwr-meter-group-testing.d.ts +77 -0
  435. package/types/ngwr-overlay.d.ts +20 -1
  436. package/types/ngwr-pagination-testing.d.ts +4 -4
  437. package/types/ngwr-pipes.d.ts +1 -1
  438. package/types/ngwr-popover-testing.d.ts +7 -2
  439. package/types/ngwr-popover.d.ts +1 -0
  440. package/types/ngwr-result.d.ts +6 -0
  441. package/types/ngwr-rotating-text-testing.d.ts +191 -0
  442. package/types/ngwr-segmented-testing.d.ts +9 -0
  443. package/types/ngwr-segmented.d.ts +21 -1
  444. package/types/ngwr-select.d.ts +100 -6
  445. package/types/ngwr-shiny-text-testing.d.ts +165 -0
  446. package/types/ngwr-shiny-text.d.ts +4 -2
  447. package/types/ngwr-sidebar.d.ts +14 -5
  448. package/types/ngwr-slider.d.ts +84 -1
  449. package/types/ngwr-sparkline-testing.d.ts +69 -0
  450. package/types/ngwr-speed-dial-testing.d.ts +199 -0
  451. package/types/ngwr-speed-dial.d.ts +22 -3
  452. package/types/ngwr-splash-cursor-testing.d.ts +95 -0
  453. package/types/ngwr-split-text-testing.d.ts +209 -0
  454. package/types/ngwr-split-text.d.ts +21 -0
  455. package/types/ngwr-splitter-testing.d.ts +174 -0
  456. package/types/ngwr-spotlight-card-testing.d.ts +303 -0
  457. package/types/ngwr-star-border-testing.d.ts +135 -0
  458. package/types/ngwr-stepper-testing.d.ts +5 -5
  459. package/types/ngwr-stepper.d.ts +8 -0
  460. package/types/ngwr-storage.d.ts +1 -0
  461. package/types/ngwr-table.d.ts +114 -12
  462. package/types/ngwr-tabs-testing.d.ts +11 -10
  463. package/types/ngwr-tabs.d.ts +2 -0
  464. package/types/ngwr-theme.d.ts +82 -1
  465. package/types/ngwr-tilt-card-testing.d.ts +158 -0
  466. package/types/ngwr-tilt-card.d.ts +2 -0
  467. package/types/ngwr-toast.d.ts +14 -5
  468. package/types/ngwr-tour-testing.d.ts +143 -0
  469. package/types/ngwr-tour.d.ts +22 -4
  470. package/types/ngwr-tree.d.ts +12 -4
  471. package/types/ngwr-typewriter-testing.d.ts +211 -0
  472. package/types/ngwr-utils.d.ts +5 -2
  473. package/types/ngwr-version.d.ts +1 -1
  474. package/types/ngwr-waves-testing.d.ts +121 -0
  475. package/types/ngwr-window-testing.d.ts +263 -0
  476. package/types/ngwr-window.d.ts +66 -21
  477. package/typography/styles/_index.scss +1 -1
  478. package/window/styles/_index.scss +116 -42
  479. package/fesm2022/ngwr-date-adapter-fns.mjs.map +0 -1
  480. package/fesm2022/ngwr-date-adapter-luxon.mjs.map +0 -1
  481. package/fesm2022/ngwr-date-adapter.mjs.map +0 -1
@@ -41,12 +41,19 @@ class WrDateAdapter {
41
41
  * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
42
42
  */
43
43
  /**
44
- * BCP 47 locale tag used by {@link WrDateAdapter} implementations for
45
- * formatting, parsing, and locale-derived defaults (first day of week,
46
- * month / day names). Defaults to `navigator.language` in the browser and
47
- * `'en-US'` on the server.
44
+ * BCP 47 locale tag the {@link WrDateAdapter} implementations read. Defaults to
45
+ * `navigator.language` in the browser and `'en-US'` on the server; override via
46
+ * {@link provideWrDateAdapter}'s `locale` option.
48
47
  *
49
- * Override via {@link provideWrDateAdapter}'s `locale` option.
48
+ * **How far it reaches depends on the adapter, and the difference matters.**
49
+ * The luxon adapter threads it through everything — every `DateTime` is
50
+ * constructed with it, and `format` / `parse` call `setLocale`. The date-fns
51
+ * adapter reads it only for locale-DERIVED defaults (first day of week); its
52
+ * `format` and `parse` pass no locale to date-fns, so they stay on that
53
+ * library's module default. Setting this token and expecting French month names
54
+ * out of `WrDateFnsAdapter` gets English ones, and the parse side of that
55
+ * mismatch is silent rather than loud — see the adapter's own class docs for the
56
+ * lever (`setDefaultOptions`).
50
57
  */
51
58
  const WR_DATE_LOCALE = new InjectionToken('WR_DATE_LOCALE', {
52
59
  providedIn: 'root',
@@ -227,7 +234,7 @@ class WrNativeDateAdapter extends WrDateAdapter {
227
234
  // while still accepting any other string as a raw token pattern.
228
235
  format(date, formatKeyOrString) {
229
236
  if (isNamedFormat(formatKeyOrString)) {
230
- return new Intl.DateTimeFormat(this.locale, INTL_OPTIONS[formatKeyOrString]).format(date);
237
+ return this.intl(formatKeyOrString).format(date);
231
238
  }
232
239
  return this.formatWithTokens(date, formatKeyOrString);
233
240
  }
@@ -259,6 +266,25 @@ class WrNativeDateAdapter extends WrDateAdapter {
259
266
  }
260
267
  return this.locale.toLowerCase().startsWith('en-us') ? 0 : 1;
261
268
  }
269
+ /**
270
+ * One `Intl.DateTimeFormat` per named format, built once.
271
+ *
272
+ * Constructing one is the expensive part of `format()`, and this adapter is
273
+ * called per CELL: `wr-event-calendar` builds an `aria-label` for every time
274
+ * slot on every day, so a week view asked for hundreds of identical
275
+ * formatters. `locale` is injected once and never changes for the life of the
276
+ * adapter, so the cache needs no invalidation — that is the whole reason it
277
+ * can be this simple.
278
+ */
279
+ formatters = new Map();
280
+ intl(key) {
281
+ let found = this.formatters.get(key);
282
+ if (!found) {
283
+ found = new Intl.DateTimeFormat(this.locale, INTL_OPTIONS[key]);
284
+ this.formatters.set(key, found);
285
+ }
286
+ return found;
287
+ }
262
288
  getDayOfWeekNames(style) {
263
289
  const formatter = new Intl.DateTimeFormat(this.locale, { weekday: style });
264
290
  const first = this.getFirstDayOfWeek();
@@ -424,10 +450,10 @@ class WrNativeDateAdapter extends WrDateAdapter {
424
450
  return null;
425
451
  return out;
426
452
  }
427
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrNativeDateAdapter, deps: [], target: i0.ɵɵFactoryTarget.Service });
428
- static ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.1", ngImport: i0, type: WrNativeDateAdapter });
453
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: WrNativeDateAdapter, deps: [], target: i0.ɵɵFactoryTarget.Service });
454
+ static ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.2", ngImport: i0, type: WrNativeDateAdapter });
429
455
  }
430
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrNativeDateAdapter, decorators: [{
456
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: WrNativeDateAdapter, decorators: [{
431
457
  type: Service
432
458
  }] });
433
459
 
@@ -467,4 +493,4 @@ function provideWrDateAdapter(options = {}) {
467
493
  */
468
494
 
469
495
  export { WR_DATE_LOCALE, WrDateAdapter, WrNativeDateAdapter, isNamedFormat, provideWrDateAdapter };
470
- //# sourceMappingURL=ngwr-date-adapter.mjs.map
496
+ //# sourceMappingURL=ngwr-date.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ngwr-date.mjs","sources":["../../../projects/lib/date/wr-date-adapter.ts","../../../projects/lib/date/tokens/wr-date-locale.token.ts","../../../projects/lib/date/wr-native-date-adapter.ts","../../../projects/lib/date/provide-wr-date-adapter.ts","../../../projects/lib/date/ngwr-date.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 type { WrDateFormat } from './interfaces';\n\n/**\n * Abstraction over a date object so the calendar, date picker and time picker\n * can work with `Date`, `date-fns`, `luxon`, or any other library a consumer\n * prefers — without changing component code.\n *\n * Default implementation: {@link WrNativeDateAdapter} (native `Date`,\n * `Intl.DateTimeFormat`). Register a different adapter via\n * `provideWrDateAdapter({ adapter: MyAdapter })`.\n *\n * Used as both the type and the DI token — `inject(WrDateAdapter)` works\n * directly thanks to Angular's class-as-token resolution.\n *\n * Every \"mutating\" method (`addX`, `setTime`) returns a **new** value;\n * adapters never mutate in place so consumers can pass dates around safely.\n */\nexport abstract class WrDateAdapter<TDate = Date> {\n // Construction & identity\n\n /** Current moment. */\n abstract today(): TDate;\n\n /** Defensive clone — must return an independent value, never the same reference. */\n abstract clone(date: TDate): TDate;\n\n /** Build a date from year / month (0-based) / day. */\n abstract createDate(year: number, month: number, day: number): TDate;\n\n /** `false` for `NaN` / invalid input. */\n abstract isValid(date: TDate): boolean;\n\n // Accessors\n\n abstract getYear(date: TDate): number;\n /** `0` (January) – `11` (December). */\n abstract getMonth(date: TDate): number;\n /** Day of the month, `1`-`31`. */\n abstract getDate(date: TDate): number;\n /** `0` (Sunday) – `6` (Saturday). */\n abstract getDayOfWeek(date: TDate): number;\n abstract getDaysInMonth(date: TDate): number;\n abstract getHours(date: TDate): number;\n abstract getMinutes(date: TDate): number;\n abstract getSeconds(date: TDate): number;\n\n // Immutable math\n\n abstract addYears(date: TDate, amount: number): TDate;\n abstract addMonths(date: TDate, amount: number): TDate;\n abstract addDays(date: TDate, amount: number): TDate;\n /** Returns a new date with the time portion replaced. */\n abstract setTime(date: TDate, hours: number, minutes: number, seconds: number): TDate;\n\n // Comparison\n\n abstract isSameDay(a: TDate, b: TDate): boolean;\n abstract isSameMonth(a: TDate, b: TDate): boolean;\n /** Negative if `a < b`, positive if `a > b`, zero if equal (compared at day precision). */\n abstract compareDate(a: TDate, b: TDate): number;\n\n /**\n * Convenience used by the calendar's range UI. Inclusive on both ends.\n * Implementation can stay on the base class because it delegates to\n * `compareDate`.\n */\n isWithinRange(date: TDate, start: TDate, end: TDate): boolean {\n return this.compareDate(date, start) >= 0 && this.compareDate(date, end) <= 0;\n }\n\n // Formatting / parsing\n\n /**\n * Format a date. Accepts either a named {@link WrDateFormat} key (which the\n * adapter resolves locale-aware) or a raw format string (`'dd.MM.yyyy'`).\n *\n * Supported tokens for raw strings: `yyyy`, `yy`, `MMMM`, `MMM`, `MM`, `M`,\n * `dd`, `d`, `HH`, `H`, `hh`, `h`, `mm`, `ss`, `a` (am / pm).\n */\n abstract format(date: TDate, formatKeyOrString: WrDateFormat | (string & {})): string;\n\n /**\n * Parse a string into a date. Returns `null` when parsing fails. Accepts\n * the same `formatKeyOrString` set as {@link format}.\n */\n abstract parse(value: string, formatKeyOrString: WrDateFormat | (string & {})): TDate | null;\n\n // Locale info\n\n /** `0` Sunday, `1` Monday — locale-dependent. */\n abstract getFirstDayOfWeek(): number;\n\n /** Names ordered from `getFirstDayOfWeek()` onwards. Length 7. */\n abstract getDayOfWeekNames(style: 'narrow' | 'short' | 'long'): readonly string[];\n\n /** Names from January (index `0`) to December (`11`). Length 12. */\n abstract getMonthNames(style: 'narrow' | 'short' | 'long'): readonly string[];\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 { isPlatformBrowser } from '@angular/common';\nimport { InjectionToken, PLATFORM_ID, inject } from '@angular/core';\n\n/**\n * BCP 47 locale tag the {@link WrDateAdapter} implementations read. Defaults to\n * `navigator.language` in the browser and `'en-US'` on the server; override via\n * {@link provideWrDateAdapter}'s `locale` option.\n *\n * **How far it reaches depends on the adapter, and the difference matters.**\n * The luxon adapter threads it through everything — every `DateTime` is\n * constructed with it, and `format` / `parse` call `setLocale`. The date-fns\n * adapter reads it only for locale-DERIVED defaults (first day of week); its\n * `format` and `parse` pass no locale to date-fns, so they stay on that\n * library's module default. Setting this token and expecting French month names\n * out of `WrDateFnsAdapter` gets English ones, and the parse side of that\n * mismatch is silent rather than loud — see the adapter's own class docs for the\n * lever (`setDefaultOptions`).\n */\nexport const WR_DATE_LOCALE = new InjectionToken<string>('WR_DATE_LOCALE', {\n providedIn: 'root',\n factory: () => {\n // Node 21+ also defines `navigator`, and reports the *build machine's*\n // locale — so a `typeof` probe silently bakes that locale into\n // prerendered output (wrong month names, wrong first day of week).\n // Ask the platform instead.\n if (isPlatformBrowser(inject(PLATFORM_ID)) && navigator.language) {\n return navigator.language;\n }\n return 'en-US';\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 { Service, inject } from '@angular/core';\n\nimport type { WrDateFormat } from './interfaces';\nimport { WR_DATE_LOCALE } from './tokens';\nimport { WrDateAdapter } from './wr-date-adapter';\n\nconst NAMED_KEYS = new Set<WrDateFormat>([\n 'shortDate',\n 'mediumDate',\n 'longDate',\n 'time',\n 'shortDateTime',\n 'mediumDateTime',\n]);\n\nconst INTL_OPTIONS: Readonly<Record<WrDateFormat, Intl.DateTimeFormatOptions>> = {\n shortDate: { year: 'numeric', month: 'numeric', day: 'numeric' },\n mediumDate: { year: 'numeric', month: 'short', day: 'numeric' },\n longDate: { year: 'numeric', month: 'long', day: 'numeric' },\n time: { hour: '2-digit', minute: '2-digit' },\n shortDateTime: { year: 'numeric', month: 'numeric', day: 'numeric', hour: '2-digit', minute: '2-digit' },\n mediumDateTime: { year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' },\n};\n\n/** Recognised tokens, longest first so `MMMM` matches before `MMM`. */\n/**\n * Every token, with single-quoted runs taken FIRST so they win.\n *\n * Without that, the one-letter tokens match letters inside literal text: `'yyyy [year]'`\n * came out as `2025 [yeamr]`, because the `a` in \"year\" was read as the meridiem token.\n * Quote literals the way `DatePipe` and LDML do — `'at'` — and `''` for a real quote.\n */\nconst PART_RE = /'([^']*)'|yyyy|yy|MMMM|MMM|MM|M|dd|d|HH|H|hh|h|mm|ss|a/g;\n\nfunction pad(n: number, width = 2): string {\n return String(Math.abs(n)).padStart(width, '0');\n}\n\n/** Whether `value` is one of the shared named format keys. */\nfunction isNamedFormat(value: string): value is WrDateFormat {\n return NAMED_KEYS.has(value as WrDateFormat);\n}\n\nfunction tokenToRegex(token: string): string {\n switch (token) {\n case 'yyyy':\n return '(\\\\d{4})';\n case 'yy':\n return '(\\\\d{2})';\n case 'MM':\n case 'dd':\n case 'HH':\n case 'hh':\n case 'mm':\n case 'ss':\n return '(\\\\d{2})';\n case 'M':\n case 'd':\n case 'H':\n case 'h':\n return '(\\\\d{1,2})';\n case 'a':\n return '(am|pm|AM|PM)';\n default:\n return '(.+)';\n }\n}\n\n/**\n * Reference {@link WrDateAdapter} implementation backed by the native `Date`\n * object and `Intl.DateTimeFormat`. Zero external dependencies. Suitable for\n * most apps — swap to a `date-fns` / `luxon` adapter only when you need\n * timezone-aware math or richer parsing.\n */\n@Service()\nexport class WrNativeDateAdapter extends WrDateAdapter<Date> {\n private readonly locale = inject(WR_DATE_LOCALE);\n\n // Construction & identity\n\n today(): Date {\n return new Date();\n }\n\n clone(date: Date): Date {\n return new Date(date.getTime());\n }\n\n createDate(year: number, month: number, day: number): Date {\n // Native Date constructor with year < 100 maps to 1900 + year unless we explicitly setFullYear.\n const d = new Date(year, month, day);\n if (year >= 0 && year < 100) d.setFullYear(year);\n return d;\n }\n\n isValid(date: Date): boolean {\n return date instanceof Date && !Number.isNaN(date.getTime());\n }\n\n // Accessors\n\n getYear(date: Date): number {\n return date.getFullYear();\n }\n\n getMonth(date: Date): number {\n return date.getMonth();\n }\n\n getDate(date: Date): number {\n return date.getDate();\n }\n\n getDayOfWeek(date: Date): number {\n return date.getDay();\n }\n\n getDaysInMonth(date: Date): number {\n return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();\n }\n\n getHours(date: Date): number {\n return date.getHours();\n }\n\n getMinutes(date: Date): number {\n return date.getMinutes();\n }\n\n getSeconds(date: Date): number {\n return date.getSeconds();\n }\n\n // Immutable math\n\n addYears(date: Date, amount: number): Date {\n const d = this.clone(date);\n d.setFullYear(d.getFullYear() + amount);\n return d;\n }\n\n addMonths(date: Date, amount: number): Date {\n const d = this.clone(date);\n const desiredDay = d.getDate();\n d.setDate(1);\n d.setMonth(d.getMonth() + amount);\n // Clamp day to the new month's length (Jan 31 + 1 month → Feb 28/29).\n d.setDate(Math.min(desiredDay, this.getDaysInMonth(d)));\n return d;\n }\n\n addDays(date: Date, amount: number): Date {\n // A calendar day, not 86 400 000 ms. Where daylight saving applies a day can be 23 or\n // 25 hours long, so millisecond arithmetic drifts the wall clock and — across an\n // autumn change — lands back on the same calendar date, which makes a month grid\n // repeat a day and lose one. Not observable in a fixed-offset timezone, which is why\n // the reason lives here rather than only in a test.\n const d = this.clone(date);\n d.setDate(d.getDate() + amount);\n return d;\n }\n\n setTime(date: Date, hours: number, minutes: number, seconds: number): Date {\n const d = this.clone(date);\n d.setHours(hours, minutes, seconds, 0);\n return d;\n }\n\n // Comparison\n\n isSameDay(a: Date, b: Date): boolean {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n }\n\n isSameMonth(a: Date, b: Date): boolean {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth();\n }\n\n compareDate(a: Date, b: Date): number {\n const ay = a.getFullYear();\n const by = b.getFullYear();\n if (ay !== by) return ay - by;\n const am = a.getMonth();\n const bm = b.getMonth();\n if (am !== bm) return am - bm;\n return a.getDate() - b.getDate();\n }\n\n // Formatting / parsing\n\n // `(string & {})` keeps autocomplete for the WrDateFormat literals\n // while still accepting any other string as a raw token pattern.\n format(date: Date, formatKeyOrString: WrDateFormat | (string & {})): string {\n if (isNamedFormat(formatKeyOrString)) {\n return this.intl(formatKeyOrString).format(date);\n }\n return this.formatWithTokens(date, formatKeyOrString);\n }\n\n parse(value: string, formatKeyOrString: WrDateFormat | (string & {})): Date | null {\n const raw = value?.trim();\n if (!raw) return null;\n\n // Named formats fall back to `new Date()` parsing — best-effort, locale-fragile.\n if (isNamedFormat(formatKeyOrString)) {\n const d = new Date(raw);\n return this.isValid(d) ? d : null;\n }\n\n return this.parseWithTokens(raw, formatKeyOrString);\n }\n\n // Locale info\n\n getFirstDayOfWeek(): number {\n // `Intl.Locale.prototype.getWeekInfo` is Stage 3 — not in TS lib types yet,\n // so we probe at runtime through an unknown cast.\n try {\n const locale = new Intl.Locale(this.locale) as unknown as { getWeekInfo?: () => { firstDay: number } };\n const info = locale.getWeekInfo?.();\n if (info && typeof info.firstDay === 'number') {\n // Intl uses 1 (Mon) – 7 (Sun); we use 0 (Sun) – 6 (Sat).\n return info.firstDay % 7;\n }\n } catch {\n // Browser doesn't support Intl.Locale or getWeekInfo — fall through.\n }\n return this.locale.toLowerCase().startsWith('en-us') ? 0 : 1;\n }\n\n /**\n * One `Intl.DateTimeFormat` per named format, built once.\n *\n * Constructing one is the expensive part of `format()`, and this adapter is\n * called per CELL: `wr-event-calendar` builds an `aria-label` for every time\n * slot on every day, so a week view asked for hundreds of identical\n * formatters. `locale` is injected once and never changes for the life of the\n * adapter, so the cache needs no invalidation — that is the whole reason it\n * can be this simple.\n */\n private readonly formatters = new Map<string, Intl.DateTimeFormat>();\n\n private intl(key: WrDateFormat): Intl.DateTimeFormat {\n let found = this.formatters.get(key);\n if (!found) {\n found = new Intl.DateTimeFormat(this.locale, INTL_OPTIONS[key]);\n this.formatters.set(key, found);\n }\n return found;\n }\n\n getDayOfWeekNames(style: 'narrow' | 'short' | 'long'): readonly string[] {\n const formatter = new Intl.DateTimeFormat(this.locale, { weekday: style });\n const first = this.getFirstDayOfWeek();\n // Pick a reference Sunday and walk seven days.\n const base = new Date(2024, 0, 7); // Sunday 7 Jan 2024\n const out: string[] = [];\n for (let i = 0; i < 7; i++) {\n const d = new Date(base);\n d.setDate(base.getDate() + ((first + i) % 7));\n out.push(formatter.format(d));\n }\n return out;\n }\n\n getMonthNames(style: 'narrow' | 'short' | 'long'): readonly string[] {\n const formatter = new Intl.DateTimeFormat(this.locale, { month: style });\n const out: string[] = [];\n for (let i = 0; i < 12; i++) {\n out.push(formatter.format(new Date(2024, i, 15)));\n }\n return out;\n }\n\n // Internals: token-based format / parse\n\n private formatWithTokens(date: Date, pattern: string): string {\n const year = date.getFullYear();\n const month = date.getMonth();\n const day = date.getDate();\n const hours24 = date.getHours();\n const hours12 = hours24 % 12 === 0 ? 12 : hours24 % 12;\n const minutes = date.getMinutes();\n const seconds = date.getSeconds();\n const monthNames = this.getMonthNames('long');\n const monthShort = this.getMonthNames('short');\n\n return pattern.replace(PART_RE, (part, quoted?: string) => {\n // A quoted run is emitted as-is; `''` is how a single quote is written.\n if (quoted !== undefined) return quoted === '' ? \"'\" : quoted;\n const token = part;\n switch (token) {\n case 'yyyy':\n return pad(year, 4);\n case 'yy':\n return pad(year % 100, 2);\n case 'MMMM':\n return monthNames[month] ?? '';\n case 'MMM':\n return monthShort[month] ?? '';\n case 'MM':\n return pad(month + 1);\n case 'M':\n return String(month + 1);\n case 'dd':\n return pad(day);\n case 'd':\n return String(day);\n case 'HH':\n return pad(hours24);\n case 'H':\n return String(hours24);\n case 'hh':\n return pad(hours12);\n case 'h':\n return String(hours12);\n case 'mm':\n return pad(minutes);\n case 'ss':\n return pad(seconds);\n case 'a':\n return hours24 < 12 ? 'am' : 'pm';\n }\n return token;\n });\n }\n\n private parseWithTokens(value: string, pattern: string): Date | null {\n const tokens: string[] = [];\n const monthLong = this.getMonthNames('long');\n const monthShort = this.getMonthNames('short');\n const escaped = pattern.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const regex = escaped.replace(PART_RE, (part, quoted?: string) => {\n if (quoted !== undefined) {\n // Literal text matches itself and captures nothing, so the token indices stay\n // aligned with the groups below.\n return quoted === '' ? \"'\" : quoted;\n }\n tokens.push(part);\n return tokenToRegex(part);\n });\n\n const match = new RegExp(`^${regex}$`).exec(value);\n if (!match) return null;\n\n let year = new Date().getFullYear();\n let month = 0;\n let day = 1;\n let hours = 0;\n let minutes = 0;\n let seconds = 0;\n let isPm = false;\n let hadHour12 = false;\n let hour12 = 0;\n\n for (let i = 0; i < tokens.length; i++) {\n const token = tokens[i];\n const raw = match[i + 1];\n const n = Number(raw);\n switch (token) {\n case 'yyyy':\n year = n;\n break;\n case 'yy':\n year = 2000 + n;\n break;\n case 'MM':\n case 'M':\n month = n - 1;\n break;\n case 'MMM':\n case 'MMMM': {\n const names = token === 'MMM' ? monthShort : monthLong;\n const found = names.findIndex(name => name.toLowerCase() === raw.toLowerCase());\n if (found < 0) return null;\n month = found;\n break;\n }\n case 'dd':\n case 'd':\n day = n;\n break;\n case 'HH':\n case 'H':\n hours = n;\n break;\n case 'hh':\n case 'h':\n hadHour12 = true;\n hour12 = n;\n break;\n case 'mm':\n minutes = n;\n break;\n case 'ss':\n seconds = n;\n break;\n case 'a':\n isPm = raw.toLowerCase() === 'pm';\n break;\n }\n }\n\n if (hadHour12) {\n hours = (hour12 % 12) + (isPm ? 12 : 0);\n }\n\n // `new Date(2025, 12, 45)` does not fail — it rolls forward into the next year — and\n // `isValid` is happy with the result, so a text field turned nonsense into a confident\n // wrong answer. The clock parts are range-checked directly; the month and the day are\n // checked by comparing what came back, which catches every rollover including a month\n // of 12 or -1.\n if (hours < 0 || hours > 23 || minutes < 0 || minutes > 59 || seconds < 0 || seconds > 59) return null;\n\n const out = new Date(year, month, day, hours, minutes, seconds);\n if (!this.isValid(out)) return null;\n // The day is range-checked by construction: anything the calendar rolled over comes\n // back as a different month or a different day.\n if (out.getMonth() !== month || out.getDate() !== day) return null;\n return out;\n }\n}\n\nexport { isNamedFormat };\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { type EnvironmentProviders, makeEnvironmentProviders } from '@angular/core';\n\nimport type { WrDateAdapterOptions } from './interfaces';\nimport { WR_DATE_LOCALE } from './tokens';\nimport { WrDateAdapter } from './wr-date-adapter';\nimport { WrNativeDateAdapter } from './wr-native-date-adapter';\n\n/**\n * Register the date adapter and locale used by the calendar / date picker /\n * time picker. Call once at bootstrap.\n *\n * @example\n * ```ts\n * bootstrapApplication(AppComponent, {\n * providers: [\n * provideWrDateAdapter(), // native, browser locale\n * // provideWrDateAdapter({ locale: 'ru-RU' }),\n * // provideWrDateAdapter({ adapter: MyDateFnsAdapter, locale: 'fr' }),\n * ],\n * });\n * ```\n */\nexport function provideWrDateAdapter(options: WrDateAdapterOptions = {}): EnvironmentProviders {\n const providers: Parameters<typeof makeEnvironmentProviders>[0] = [\n { provide: WrDateAdapter, useClass: options.adapter ?? WrNativeDateAdapter },\n ];\n\n if (options.locale) {\n providers.push({ provide: WR_DATE_LOCALE, useValue: options.locale });\n }\n\n return makeEnvironmentProviders(providers);\n}\n\nexport type { WrDateAdapterOptions } from './interfaces';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;AAAA;;;;;AAKG;AAIH;;;;;;;;;;;;;;AAcG;MACmB,aAAa,CAAA;AA4CjC;;;;AAIG;AACH,IAAA,aAAa,CAAC,IAAW,EAAE,KAAY,EAAE,GAAU,EAAA;QACjD,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC;IAC/E;AA6BD;;ACxGD;;;;;AAKG;AAKH;;;;;;;;;;;;;;AAcG;MACU,cAAc,GAAG,IAAI,cAAc,CAAS,gBAAgB,EAAE;AACzE,IAAA,UAAU,EAAE,MAAM;IAClB,OAAO,EAAE,MAAK;;;;;AAKZ,QAAA,IAAI,iBAAiB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,SAAS,CAAC,QAAQ,EAAE;YAChE,OAAO,SAAS,CAAC,QAAQ;QAC3B;AACA,QAAA,OAAO,OAAO;IAChB,CAAC;AACF,CAAA;;ACrCD;;;;;AAKG;AAQH,MAAM,UAAU,GAAG,IAAI,GAAG,CAAe;IACvC,WAAW;IACX,YAAY;IACZ,UAAU;IACV,MAAM;IACN,eAAe;IACf,gBAAgB;AACjB,CAAA,CAAC;AAEF,MAAM,YAAY,GAA+D;AAC/E,IAAA,SAAS,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE;AAChE,IAAA,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE;AAC/D,IAAA,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE;IAC5D,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE;IAC5C,aAAa,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE;IACxG,cAAc,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE;CACxG;AAED;AACA;;;;;;AAMG;AACH,MAAM,OAAO,GAAG,yDAAyD;AAEzE,SAAS,GAAG,CAAC,CAAS,EAAE,KAAK,GAAG,CAAC,EAAA;AAC/B,IAAA,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC;AACjD;AAEA;AACA,SAAS,aAAa,CAAC,KAAa,EAAA;AAClC,IAAA,OAAO,UAAU,CAAC,GAAG,CAAC,KAAqB,CAAC;AAC9C;AAEA,SAAS,YAAY,CAAC,KAAa,EAAA;IACjC,QAAQ,KAAK;AACX,QAAA,KAAK,MAAM;AACT,YAAA,OAAO,UAAU;AACnB,QAAA,KAAK,IAAI;AACP,YAAA,OAAO,UAAU;AACnB,QAAA,KAAK,IAAI;AACT,QAAA,KAAK,IAAI;AACT,QAAA,KAAK,IAAI;AACT,QAAA,KAAK,IAAI;AACT,QAAA,KAAK,IAAI;AACT,QAAA,KAAK,IAAI;AACP,YAAA,OAAO,UAAU;AACnB,QAAA,KAAK,GAAG;AACR,QAAA,KAAK,GAAG;AACR,QAAA,KAAK,GAAG;AACR,QAAA,KAAK,GAAG;AACN,YAAA,OAAO,YAAY;AACrB,QAAA,KAAK,GAAG;AACN,YAAA,OAAO,eAAe;AACxB,QAAA;AACE,YAAA,OAAO,MAAM;;AAEnB;AAEA;;;;;AAKG;AAEG,MAAO,mBAAoB,SAAQ,aAAmB,CAAA;AACzC,IAAA,MAAM,GAAG,MAAM,CAAC,cAAc,CAAC;;IAIhD,KAAK,GAAA;QACH,OAAO,IAAI,IAAI,EAAE;IACnB;AAEA,IAAA,KAAK,CAAC,IAAU,EAAA;QACd,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;IACjC;AAEA,IAAA,UAAU,CAAC,IAAY,EAAE,KAAa,EAAE,GAAW,EAAA;;QAEjD,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC;AACpC,QAAA,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,GAAG,GAAG;AAAE,YAAA,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC;AAChD,QAAA,OAAO,CAAC;IACV;AAEA,IAAA,OAAO,CAAC,IAAU,EAAA;AAChB,QAAA,OAAO,IAAI,YAAY,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;IAC9D;;AAIA,IAAA,OAAO,CAAC,IAAU,EAAA;AAChB,QAAA,OAAO,IAAI,CAAC,WAAW,EAAE;IAC3B;AAEA,IAAA,QAAQ,CAAC,IAAU,EAAA;AACjB,QAAA,OAAO,IAAI,CAAC,QAAQ,EAAE;IACxB;AAEA,IAAA,OAAO,CAAC,IAAU,EAAA;AAChB,QAAA,OAAO,IAAI,CAAC,OAAO,EAAE;IACvB;AAEA,IAAA,YAAY,CAAC,IAAU,EAAA;AACrB,QAAA,OAAO,IAAI,CAAC,MAAM,EAAE;IACtB;AAEA,IAAA,cAAc,CAAC,IAAU,EAAA;QACvB,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE;IACvE;AAEA,IAAA,QAAQ,CAAC,IAAU,EAAA;AACjB,QAAA,OAAO,IAAI,CAAC,QAAQ,EAAE;IACxB;AAEA,IAAA,UAAU,CAAC,IAAU,EAAA;AACnB,QAAA,OAAO,IAAI,CAAC,UAAU,EAAE;IAC1B;AAEA,IAAA,UAAU,CAAC,IAAU,EAAA;AACnB,QAAA,OAAO,IAAI,CAAC,UAAU,EAAE;IAC1B;;IAIA,QAAQ,CAAC,IAAU,EAAE,MAAc,EAAA;QACjC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;QAC1B,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,MAAM,CAAC;AACvC,QAAA,OAAO,CAAC;IACV;IAEA,SAAS,CAAC,IAAU,EAAE,MAAc,EAAA;QAClC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;AAC1B,QAAA,MAAM,UAAU,GAAG,CAAC,CAAC,OAAO,EAAE;AAC9B,QAAA,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;QACZ,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE,GAAG,MAAM,CAAC;;AAEjC,QAAA,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;AACvD,QAAA,OAAO,CAAC;IACV;IAEA,OAAO,CAAC,IAAU,EAAE,MAAc,EAAA;;;;;;QAMhC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;QAC1B,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC;AAC/B,QAAA,OAAO,CAAC;IACV;AAEA,IAAA,OAAO,CAAC,IAAU,EAAE,KAAa,EAAE,OAAe,EAAE,OAAe,EAAA;QACjE,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;QAC1B,CAAC,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;AACtC,QAAA,OAAO,CAAC;IACV;;IAIA,SAAS,CAAC,CAAO,EAAE,CAAO,EAAA;AACxB,QAAA,OAAO,CAAC,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,OAAO,EAAE;IAC5G;IAEA,WAAW,CAAC,CAAO,EAAE,CAAO,EAAA;AAC1B,QAAA,OAAO,CAAC,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,QAAQ,EAAE;IAC7E;IAEA,WAAW,CAAC,CAAO,EAAE,CAAO,EAAA;AAC1B,QAAA,MAAM,EAAE,GAAG,CAAC,CAAC,WAAW,EAAE;AAC1B,QAAA,MAAM,EAAE,GAAG,CAAC,CAAC,WAAW,EAAE;QAC1B,IAAI,EAAE,KAAK,EAAE;YAAE,OAAO,EAAE,GAAG,EAAE;AAC7B,QAAA,MAAM,EAAE,GAAG,CAAC,CAAC,QAAQ,EAAE;AACvB,QAAA,MAAM,EAAE,GAAG,CAAC,CAAC,QAAQ,EAAE;QACvB,IAAI,EAAE,KAAK,EAAE;YAAE,OAAO,EAAE,GAAG,EAAE;QAC7B,OAAO,CAAC,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,OAAO,EAAE;IAClC;;;;IAMA,MAAM,CAAC,IAAU,EAAE,iBAA+C,EAAA;AAChE,QAAA,IAAI,aAAa,CAAC,iBAAiB,CAAC,EAAE;YACpC,OAAO,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;QAClD;QACA,OAAO,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACvD;IAEA,KAAK,CAAC,KAAa,EAAE,iBAA+C,EAAA;AAClE,QAAA,MAAM,GAAG,GAAG,KAAK,EAAE,IAAI,EAAE;AACzB,QAAA,IAAI,CAAC,GAAG;AAAE,YAAA,OAAO,IAAI;;AAGrB,QAAA,IAAI,aAAa,CAAC,iBAAiB,CAAC,EAAE;AACpC,YAAA,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;AACvB,YAAA,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI;QACnC;QAEA,OAAO,IAAI,CAAC,eAAe,CAAC,GAAG,EAAE,iBAAiB,CAAC;IACrD;;IAIA,iBAAiB,GAAA;;;AAGf,QAAA,IAAI;YACF,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAA4D;AACtG,YAAA,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,IAAI;YACnC,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,QAAQ,KAAK,QAAQ,EAAE;;AAE7C,gBAAA,OAAO,IAAI,CAAC,QAAQ,GAAG,CAAC;YAC1B;QACF;AAAE,QAAA,MAAM;;QAER;AACA,QAAA,OAAO,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;IAC9D;AAEA;;;;;;;;;AASG;AACc,IAAA,UAAU,GAAG,IAAI,GAAG,EAA+B;AAE5D,IAAA,IAAI,CAAC,GAAiB,EAAA;QAC5B,IAAI,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC;QACpC,IAAI,CAAC,KAAK,EAAE;AACV,YAAA,KAAK,GAAG,IAAI,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC;YAC/D,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC;QACjC;AACA,QAAA,OAAO,KAAK;IACd;AAEA,IAAA,iBAAiB,CAAC,KAAkC,EAAA;AAClD,QAAA,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAC1E,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,iBAAiB,EAAE;;AAEtC,QAAA,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAClC,MAAM,GAAG,GAAa,EAAE;AACxB,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;AAC1B,YAAA,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC;AACxB,YAAA,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;YAC7C,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC/B;AACA,QAAA,OAAO,GAAG;IACZ;AAEA,IAAA,aAAa,CAAC,KAAkC,EAAA;AAC9C,QAAA,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;QACxE,MAAM,GAAG,GAAa,EAAE;AACxB,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE;AAC3B,YAAA,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QACnD;AACA,QAAA,OAAO,GAAG;IACZ;;IAIQ,gBAAgB,CAAC,IAAU,EAAE,OAAe,EAAA;AAClD,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE;AAC/B,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE;AAC7B,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE;AAC1B,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,EAAE;AAC/B,QAAA,MAAM,OAAO,GAAG,OAAO,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,GAAG,OAAO,GAAG,EAAE;AACtD,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE;AACjC,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE;QACjC,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC;QAC7C,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC;QAE9C,OAAO,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAe,KAAI;;YAExD,IAAI,MAAM,KAAK,SAAS;gBAAE,OAAO,MAAM,KAAK,EAAE,GAAG,GAAG,GAAG,MAAM;YAC7D,MAAM,KAAK,GAAG,IAAI;YAClB,QAAQ,KAAK;AACX,gBAAA,KAAK,MAAM;AACT,oBAAA,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;AACrB,gBAAA,KAAK,IAAI;oBACP,OAAO,GAAG,CAAC,IAAI,GAAG,GAAG,EAAE,CAAC,CAAC;AAC3B,gBAAA,KAAK,MAAM;AACT,oBAAA,OAAO,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE;AAChC,gBAAA,KAAK,KAAK;AACR,oBAAA,OAAO,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE;AAChC,gBAAA,KAAK,IAAI;AACP,oBAAA,OAAO,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC;AACvB,gBAAA,KAAK,GAAG;AACN,oBAAA,OAAO,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC;AAC1B,gBAAA,KAAK,IAAI;AACP,oBAAA,OAAO,GAAG,CAAC,GAAG,CAAC;AACjB,gBAAA,KAAK,GAAG;AACN,oBAAA,OAAO,MAAM,CAAC,GAAG,CAAC;AACpB,gBAAA,KAAK,IAAI;AACP,oBAAA,OAAO,GAAG,CAAC,OAAO,CAAC;AACrB,gBAAA,KAAK,GAAG;AACN,oBAAA,OAAO,MAAM,CAAC,OAAO,CAAC;AACxB,gBAAA,KAAK,IAAI;AACP,oBAAA,OAAO,GAAG,CAAC,OAAO,CAAC;AACrB,gBAAA,KAAK,GAAG;AACN,oBAAA,OAAO,MAAM,CAAC,OAAO,CAAC;AACxB,gBAAA,KAAK,IAAI;AACP,oBAAA,OAAO,GAAG,CAAC,OAAO,CAAC;AACrB,gBAAA,KAAK,IAAI;AACP,oBAAA,OAAO,GAAG,CAAC,OAAO,CAAC;AACrB,gBAAA,KAAK,GAAG;oBACN,OAAO,OAAO,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI;;AAErC,YAAA,OAAO,KAAK;AACd,QAAA,CAAC,CAAC;IACJ;IAEQ,eAAe,CAAC,KAAa,EAAE,OAAe,EAAA;QACpD,MAAM,MAAM,GAAa,EAAE;QAC3B,MAAM,SAAS,GAAG,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC;QAC5C,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC;QAC9C,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC;AAC9D,QAAA,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAe,KAAI;AAC/D,YAAA,IAAI,MAAM,KAAK,SAAS,EAAE;;;gBAGxB,OAAO,MAAM,KAAK,EAAE,GAAG,GAAG,GAAG,MAAM;YACrC;AACA,YAAA,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;AACjB,YAAA,OAAO,YAAY,CAAC,IAAI,CAAC;AAC3B,QAAA,CAAC,CAAC;AAEF,QAAA,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,CAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;AAClD,QAAA,IAAI,CAAC,KAAK;AAAE,YAAA,OAAO,IAAI;QAEvB,IAAI,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,IAAI,KAAK,GAAG,CAAC;QACb,IAAI,GAAG,GAAG,CAAC;QACX,IAAI,KAAK,GAAG,CAAC;QACb,IAAI,OAAO,GAAG,CAAC;QACf,IAAI,OAAO,GAAG,CAAC;QACf,IAAI,IAAI,GAAG,KAAK;QAChB,IAAI,SAAS,GAAG,KAAK;QACrB,IAAI,MAAM,GAAG,CAAC;AAEd,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AACtC,YAAA,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC;YACvB,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC;AACxB,YAAA,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC;YACrB,QAAQ,KAAK;AACX,gBAAA,KAAK,MAAM;oBACT,IAAI,GAAG,CAAC;oBACR;AACF,gBAAA,KAAK,IAAI;AACP,oBAAA,IAAI,GAAG,IAAI,GAAG,CAAC;oBACf;AACF,gBAAA,KAAK,IAAI;AACT,gBAAA,KAAK,GAAG;AACN,oBAAA,KAAK,GAAG,CAAC,GAAG,CAAC;oBACb;AACF,gBAAA,KAAK,KAAK;gBACV,KAAK,MAAM,EAAE;AACX,oBAAA,MAAM,KAAK,GAAG,KAAK,KAAK,KAAK,GAAG,UAAU,GAAG,SAAS;oBACtD,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,IAAI,IAAI,IAAI,CAAC,WAAW,EAAE,KAAK,GAAG,CAAC,WAAW,EAAE,CAAC;oBAC/E,IAAI,KAAK,GAAG,CAAC;AAAE,wBAAA,OAAO,IAAI;oBAC1B,KAAK,GAAG,KAAK;oBACb;gBACF;AACA,gBAAA,KAAK,IAAI;AACT,gBAAA,KAAK,GAAG;oBACN,GAAG,GAAG,CAAC;oBACP;AACF,gBAAA,KAAK,IAAI;AACT,gBAAA,KAAK,GAAG;oBACN,KAAK,GAAG,CAAC;oBACT;AACF,gBAAA,KAAK,IAAI;AACT,gBAAA,KAAK,GAAG;oBACN,SAAS,GAAG,IAAI;oBAChB,MAAM,GAAG,CAAC;oBACV;AACF,gBAAA,KAAK,IAAI;oBACP,OAAO,GAAG,CAAC;oBACX;AACF,gBAAA,KAAK,IAAI;oBACP,OAAO,GAAG,CAAC;oBACX;AACF,gBAAA,KAAK,GAAG;AACN,oBAAA,IAAI,GAAG,GAAG,CAAC,WAAW,EAAE,KAAK,IAAI;oBACjC;;QAEN;QAEA,IAAI,SAAS,EAAE;AACb,YAAA,KAAK,GAAG,CAAC,MAAM,GAAG,EAAE,KAAK,IAAI,GAAG,EAAE,GAAG,CAAC,CAAC;QACzC;;;;;;QAOA,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,EAAE,IAAI,OAAO,GAAG,CAAC,IAAI,OAAO,GAAG,EAAE,IAAI,OAAO,GAAG,CAAC,IAAI,OAAO,GAAG,EAAE;AAAE,YAAA,OAAO,IAAI;AAEtG,QAAA,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC;AAC/D,QAAA,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC;AAAE,YAAA,OAAO,IAAI;;;AAGnC,QAAA,IAAI,GAAG,CAAC,QAAQ,EAAE,KAAK,KAAK,IAAI,GAAG,CAAC,OAAO,EAAE,KAAK,GAAG;AAAE,YAAA,OAAO,IAAI;AAClE,QAAA,OAAO,GAAG;IACZ;uGAzVW,mBAAmB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,OAAA,EAAA,CAAA;wGAAnB,mBAAmB,EAAA,CAAA;;2FAAnB,mBAAmB,EAAA,UAAA,EAAA,CAAA;kBAD/B;;;ACjFD;;;;;AAKG;AASH;;;;;;;;;;;;;;AAcG;AACG,SAAU,oBAAoB,CAAC,OAAA,GAAgC,EAAE,EAAA;AACrE,IAAA,MAAM,SAAS,GAAmD;QAChE,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,OAAO,CAAC,OAAO,IAAI,mBAAmB,EAAE;KAC7E;AAED,IAAA,IAAI,OAAO,CAAC,MAAM,EAAE;AAClB,QAAA,SAAS,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;IACvE;AAEA,IAAA,OAAO,wBAAwB,CAAC,SAAS,CAAC;AAC5C;;ACvCA;;AAEG;;;;"}
@@ -0,0 +1,261 @@
1
+ import { ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';
2
+
3
+ /**
4
+ * @license
5
+ *
6
+ * Use of this source code is governed by an MIT-style license that can be
7
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
8
+ */
9
+ /** The readable copy of the string, carried once and hidden with CSS. */
10
+ const SR_ONLY = '.wr-decrypt-text__sr-only';
11
+ /** One span per CODE POINT of whatever is on screen this frame. */
12
+ const CHAR = '.wr-decrypt-text__char';
13
+ /** The modifier that carries the entire progress model. */
14
+ const ENCRYPTED = '.wr-decrypt-text__char--encrypted';
15
+ /**
16
+ * The wrapper holding every scramble character.
17
+ *
18
+ * Addressed structurally because it is the one element in this template with no BEM
19
+ * class of its own — see {@link WrDecryptTextHarness.isAnimatedLayerHidden}, which
20
+ * exists precisely because a selector this fragile should be written down once rather
21
+ * than assumed in every spec.
22
+ */
23
+ const SCRAMBLE = `${SR_ONLY} + span`;
24
+ /** Exactly what the element holds — untrimmed, unlike `TestElement.text()`. */
25
+ async function rawText(element) {
26
+ return (await element.getProperty('textContent')) ?? '';
27
+ }
28
+ /**
29
+ * Test harness for `<wr-decrypt-text>`.
30
+ *
31
+ * **Two layers, two questions, and they are meant to disagree.** The component renders
32
+ * the real string once in a visually-hidden span and the scramble in a parallel
33
+ * `aria-hidden` layer, so {@link getAccessibleText} is what a screen reader hears and
34
+ * {@link getRenderedText} is what a sighted reader sees. Mid-reveal the second is
35
+ * literal gibberish while the first must be untouched — that is the contract, and it is
36
+ * the half nobody looks at. A spec asserting only the visible glyphs would pass on a
37
+ * component that announced `XQ#PZ`.
38
+ *
39
+ * **Prefer the class over the glyphs.** {@link getRevealedIndices},
40
+ * {@link getEncryptedCount} and {@link isFullyRevealed} read
41
+ * `.wr-decrypt-text__char--encrypted`, which is deterministic with no stubbing at all —
42
+ * they are what tell `revealDirection` `'start'` from `'end'` from `'center'`, one index
43
+ * per tick. {@link getRenderedText} reads the glyphs themselves, which are a fresh
44
+ * `Math.random()` draw per tick, so stub it (`vi.spyOn(Math, 'random')
45
+ * .mockReturnValue(0)`) before asserting a string.
46
+ *
47
+ * **The clock is the spec's, not the harness's.** The reveal is a `setInterval` this
48
+ * class does not own, so there is no `advance(ms)` and no `waitUntilRevealed()`: one
49
+ * would flake on a loaded machine and the other would silently require fake timers to
50
+ * have been installed. Fake `setInterval` / `clearInterval` and nothing else — faking
51
+ * the microtask queue freezes the stabilization every `await harness.*()` runs through —
52
+ * then advance the clock yourself between reads.
53
+ *
54
+ * **There is no keyboard path, and this harness does not pretend there is one.**
55
+ * {@link hover}, {@link mouseAway} and {@link click} are the component's only triggers;
56
+ * with `animateOn="click"` the host takes a click handler while carrying no role, no
57
+ * `tabindex` and no keydown handler, so a `focus()` / `sendKeys(Enter)` affordance here
58
+ * would make a spec pass while a keyboard or switch user could not reveal the text at
59
+ * all. There is no `enterViewport()` either: `'view'` and `'inViewHover'` hang off an
60
+ * `IntersectionObserver` jsdom does not implement, so the spec stubs the global and
61
+ * fires it.
62
+ *
63
+ * **Also deliberately absent:** `isAnimating()` — the component has such a signal and it
64
+ * never reaches the DOM, and deriving it from "something is encrypted" would be wrong in
65
+ * exactly the interesting case, since `animateOn="click"` rests fully encrypted and
66
+ * perfectly still. `getSpeed()` / `getMaxIterations()` / `getRevealDirection()` /
67
+ * `getClickMode()` / `getAnimateOn()` — inputs that are never reflected anywhere, so
68
+ * reporting them would mean reading the component instance rather than the rendered
69
+ * control; they are observable as behaviour, which is what the methods above measure.
70
+ * `getScrambleAlphabet()` — the pool is internal and each frame shows one random draw
71
+ * from it, so any reconstruction is a guess that gets worse the shorter the string.
72
+ * `getCharColors()` / `isDimmed()` — the `--encrypted` rule is deliberately EMPTY, a
73
+ * styling hook for consumers, so there is nothing painted to read in any environment.
74
+ *
75
+ * @example
76
+ * ```ts
77
+ * const secret = await loader.getHarness(WrDecryptTextHarness.with({ text: 'Hello' }));
78
+ *
79
+ * await secret.hover();
80
+ * vi.advanceTimersByTime(50);
81
+ *
82
+ * expect(await secret.getRevealedIndices()).toEqual([0]); // sequential, from the start
83
+ * expect(await secret.getAccessibleText()).toBe('Hello'); // untouched throughout
84
+ * ```
85
+ *
86
+ * @see https://ngwr.dev/guides/testing
87
+ */
88
+ class WrDecryptTextHarness extends ComponentHarness {
89
+ static hostSelector = 'wr-decrypt-text';
90
+ /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */
91
+ static with(options = {}) {
92
+ return new HarnessPredicate(WrDecryptTextHarness, options)
93
+ .addOption('text', options.text, (harness, text) => HarnessPredicate.stringMatches(harness.getAccessibleText(), text))
94
+ .addOption('revealed', options.revealed, async (harness, revealed) => {
95
+ // Not `isFullyRevealed()`, which refuses to answer for an instance that rendered
96
+ // no characters. A predicate is the wrong place to throw — a single empty
97
+ // instance would take down every query on the page — so the vacuous case is
98
+ // spelled out here instead, and matches neither `true` nor `false`.
99
+ if ((await harness.getCharCount()) === 0)
100
+ return false;
101
+ return ((await harness.getEncryptedCount()) === 0) === revealed;
102
+ });
103
+ }
104
+ chars = this.locatorForAll(CHAR);
105
+ encrypted = this.locatorForAll(ENCRYPTED);
106
+ /**
107
+ * The real string, as the one readable copy holds it.
108
+ *
109
+ * The single highest-value assertion here: it must stay equal to the `text` input on
110
+ * every frame, while the visible layer is unreadable by design. Lose this span and the
111
+ * component announces nothing at all — every drawn character sits under `aria-hidden`,
112
+ * so no other part of the DOM would change.
113
+ *
114
+ * Untrimmed, so that it can be compared against {@link getRenderedText} without one
115
+ * side of the comparison quietly forgiving a lost leading space.
116
+ */
117
+ async getAccessibleText() {
118
+ return rawText(await this.locatorFor(SR_ONLY)());
119
+ }
120
+ /**
121
+ * What is on screen this frame — scramble glyphs and all, in document order.
122
+ *
123
+ * Plain before anything triggers it, gibberish mid-reveal, and the real string once it
124
+ * settles; comparing it against {@link getAccessibleText} is how a spec says which of
125
+ * those it is looking at. `useOriginalCharsOnly` is visible only here — every glyph
126
+ * has to be one the text really contains.
127
+ *
128
+ * Nondeterministic unless the spec stubs `Math.random`, because each unrevealed
129
+ * position is an independent draw from the pool. When the assertion does not actually
130
+ * need the glyphs, {@link getRevealedIndices} answers the same progress question off
131
+ * the class and needs no stub.
132
+ */
133
+ async getRenderedText() {
134
+ return (await Promise.all((await this.chars()).map(rawText))).join('');
135
+ }
136
+ /**
137
+ * How many characters the animation walks.
138
+ *
139
+ * CODE POINTS, not UTF-16 units: `'a🚀b'` is 3 here, and the indices
140
+ * {@link getRevealedIndices} returns line up with `[...text]` rather than with plain
141
+ * `text[i]`. That distinction is not pedantry — counting units gave a sequential
142
+ * reveal extra ticks with no character to spend them on, and made "everything is
143
+ * revealed" disagree with what was on screen.
144
+ */
145
+ async getCharCount() {
146
+ return (await this.chars()).length;
147
+ }
148
+ /**
149
+ * The positions that have settled on their real character, ascending.
150
+ *
151
+ * The payload method, and the deterministic one: it reads the `--encrypted` modifier
152
+ * rather than the glyphs, so no `Math.random` stub is involved. It is the only thing
153
+ * that separates `revealDirection` `'start'` (`[0]`, `[0, 1]`, …) from `'end'`
154
+ * (`[4]`, `[3, 4]`, …) from `'center'` (`[2]`, `[1, 2]`, …), and one index per tick is
155
+ * what makes a sequential reveal sequential.
156
+ *
157
+ * Ascending by position, NOT in the order the reveal visited them — the DOM records
158
+ * which characters have landed, never the path taken to them. Assert the set after
159
+ * each tick to pin an order.
160
+ */
161
+ async getRevealedIndices() {
162
+ const chars = await this.chars();
163
+ const states = await Promise.all(chars.map(char => char.hasClass('wr-decrypt-text__char--encrypted')));
164
+ return states.flatMap((isEncrypted, index) => (isEncrypted ? [] : [index]));
165
+ }
166
+ /**
167
+ * How many characters are still scrambled.
168
+ *
169
+ * The coarse progress read, and the cheapest way to say "scrambled on hover", "plain on
170
+ * leave", or "a reader who asked for less motion never saw a scramble at all". Class-
171
+ * based like {@link getRevealedIndices}, so it too is random-proof.
172
+ */
173
+ async getEncryptedCount() {
174
+ return (await this.encrypted()).length;
175
+ }
176
+ /**
177
+ * Whether every character has settled.
178
+ *
179
+ * Deliberately does NOT also compare {@link getRenderedText} against
180
+ * {@link getAccessibleText}: folding two conditions into one boolean hides which of
181
+ * them broke, and a spec that wants both should write both lines.
182
+ *
183
+ * Throws when nothing was rendered. "No character is encrypted" is true of no
184
+ * characters, which is the same answer a component that stopped rendering its text
185
+ * would give — and this is the method most likely to be the only assertion in a test.
186
+ */
187
+ async isFullyRevealed() {
188
+ const total = await this.getCharCount();
189
+ if (total === 0) {
190
+ throw new Error('WrDecryptTextHarness.isFullyRevealed(): this <wr-decrypt-text> rendered no characters, so "nothing is ' +
191
+ 'encrypted" is vacuously true — the same answer a component that stopped rendering its text would ' +
192
+ 'give. Check `text` is set, or ask getCharCount().');
193
+ }
194
+ return (await this.getEncryptedCount()) === 0;
195
+ }
196
+ /**
197
+ * Whether the scramble layer is out of the accessibility tree.
198
+ *
199
+ * The contract that keeps a screen reader from spelling out `XQ#PZ` beside the real
200
+ * string it already read. Worth a method rather than an assumption because the wrapper
201
+ * holding the characters carries NO class — it can only be addressed as the readable
202
+ * span's next sibling, which any template reshuffle breaks.
203
+ *
204
+ * Throws when that structural selector finds nothing, rather than returning `false`: a
205
+ * missing wrapper and an unhidden one are different failures, and the answer to
206
+ * "is the scramble hidden" when there is no scramble layer at all is not `false`.
207
+ */
208
+ async isAnimatedLayerHidden() {
209
+ const scramble = await this.locatorForOptional(SCRAMBLE)();
210
+ if (!scramble) {
211
+ throw new Error('WrDecryptTextHarness.isAnimatedLayerHidden(): no scramble layer found. It carries no class of its own, ' +
212
+ `so it is addressed structurally as \`${SCRAMBLE}\` — a template that moved either span out from ` +
213
+ 'under that selector breaks this read, and "false" would report the layer as ANNOUNCED rather than as ' +
214
+ 'missing.');
215
+ }
216
+ return (await scramble.getAttribute('aria-hidden')) === 'true';
217
+ }
218
+ /**
219
+ * Point at it — the trigger for `animateOn` `'hover'` and `'inViewHover'`.
220
+ *
221
+ * Drives the component the way a user does, and works in a test because the trigger is
222
+ * an event rather than a gesture: `TestElement.hover()` dispatches `pointerenter`,
223
+ * `mouseover` and `mouseenter`, and the component listens for the last of those. A
224
+ * hand-rolled pointer-only dispatch would not reach it.
225
+ *
226
+ * Does nothing in the other two modes, exactly as a real pointer does nothing there.
227
+ */
228
+ async hover() {
229
+ return (await this.host()).hover();
230
+ }
231
+ /**
232
+ * Move the pointer off — the other half of hover mode.
233
+ *
234
+ * Pins the promise that leaving mid-scramble restores the real text IMMEDIATELY rather
235
+ * than letting the reveal play out: the reader took the effect away, so the string has
236
+ * to come back at once.
237
+ */
238
+ async mouseAway() {
239
+ return (await this.host()).mouseAway();
240
+ }
241
+ /**
242
+ * Click the host — the `animateOn="click"` trigger, and the only way to tell
243
+ * `clickMode` `'once'` from `'toggle'`.
244
+ *
245
+ * There is no keyboard equivalent, and that is a statement about the component rather
246
+ * than about this harness: in click mode the host carries a click handler with no role,
247
+ * no `tabindex` and no keydown handler, so a keyboard or switch user cannot reveal the
248
+ * text at all. A `sendKeys(Enter)` here would invent an affordance that does not exist
249
+ * and let a spec pass over the top of it.
250
+ */
251
+ async click() {
252
+ return (await this.host()).click();
253
+ }
254
+ }
255
+
256
+ /**
257
+ * Generated bundle index. Do not edit.
258
+ */
259
+
260
+ export { WrDecryptTextHarness };
261
+ //# sourceMappingURL=ngwr-decrypt-text-testing.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ngwr-decrypt-text-testing.mjs","sources":["../../../projects/lib/decrypt-text/testing/wr-decrypt-text-harness.ts","../../../projects/lib/decrypt-text/testing/ngwr-decrypt-text-testing.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { ComponentHarness, HarnessPredicate, type TestElement } from '@angular/cdk/testing';\n\nimport type { WrDecryptTextHarnessFilters } from './interfaces';\n\n/** The readable copy of the string, carried once and hidden with CSS. */\nconst SR_ONLY = '.wr-decrypt-text__sr-only';\n\n/** One span per CODE POINT of whatever is on screen this frame. */\nconst CHAR = '.wr-decrypt-text__char';\n\n/** The modifier that carries the entire progress model. */\nconst ENCRYPTED = '.wr-decrypt-text__char--encrypted';\n\n/**\n * The wrapper holding every scramble character.\n *\n * Addressed structurally because it is the one element in this template with no BEM\n * class of its own — see {@link WrDecryptTextHarness.isAnimatedLayerHidden}, which\n * exists precisely because a selector this fragile should be written down once rather\n * than assumed in every spec.\n */\nconst SCRAMBLE = `${SR_ONLY} + span`;\n\n/** Exactly what the element holds — untrimmed, unlike `TestElement.text()`. */\nasync function rawText(element: TestElement): Promise<string> {\n return (await element.getProperty<string | null>('textContent')) ?? '';\n}\n\n/**\n * Test harness for `<wr-decrypt-text>`.\n *\n * **Two layers, two questions, and they are meant to disagree.** The component renders\n * the real string once in a visually-hidden span and the scramble in a parallel\n * `aria-hidden` layer, so {@link getAccessibleText} is what a screen reader hears and\n * {@link getRenderedText} is what a sighted reader sees. Mid-reveal the second is\n * literal gibberish while the first must be untouched — that is the contract, and it is\n * the half nobody looks at. A spec asserting only the visible glyphs would pass on a\n * component that announced `XQ#PZ`.\n *\n * **Prefer the class over the glyphs.** {@link getRevealedIndices},\n * {@link getEncryptedCount} and {@link isFullyRevealed} read\n * `.wr-decrypt-text__char--encrypted`, which is deterministic with no stubbing at all —\n * they are what tell `revealDirection` `'start'` from `'end'` from `'center'`, one index\n * per tick. {@link getRenderedText} reads the glyphs themselves, which are a fresh\n * `Math.random()` draw per tick, so stub it (`vi.spyOn(Math, 'random')\n * .mockReturnValue(0)`) before asserting a string.\n *\n * **The clock is the spec's, not the harness's.** The reveal is a `setInterval` this\n * class does not own, so there is no `advance(ms)` and no `waitUntilRevealed()`: one\n * would flake on a loaded machine and the other would silently require fake timers to\n * have been installed. Fake `setInterval` / `clearInterval` and nothing else — faking\n * the microtask queue freezes the stabilization every `await harness.*()` runs through —\n * then advance the clock yourself between reads.\n *\n * **There is no keyboard path, and this harness does not pretend there is one.**\n * {@link hover}, {@link mouseAway} and {@link click} are the component's only triggers;\n * with `animateOn=\"click\"` the host takes a click handler while carrying no role, no\n * `tabindex` and no keydown handler, so a `focus()` / `sendKeys(Enter)` affordance here\n * would make a spec pass while a keyboard or switch user could not reveal the text at\n * all. There is no `enterViewport()` either: `'view'` and `'inViewHover'` hang off an\n * `IntersectionObserver` jsdom does not implement, so the spec stubs the global and\n * fires it.\n *\n * **Also deliberately absent:** `isAnimating()` — the component has such a signal and it\n * never reaches the DOM, and deriving it from \"something is encrypted\" would be wrong in\n * exactly the interesting case, since `animateOn=\"click\"` rests fully encrypted and\n * perfectly still. `getSpeed()` / `getMaxIterations()` / `getRevealDirection()` /\n * `getClickMode()` / `getAnimateOn()` — inputs that are never reflected anywhere, so\n * reporting them would mean reading the component instance rather than the rendered\n * control; they are observable as behaviour, which is what the methods above measure.\n * `getScrambleAlphabet()` — the pool is internal and each frame shows one random draw\n * from it, so any reconstruction is a guess that gets worse the shorter the string.\n * `getCharColors()` / `isDimmed()` — the `--encrypted` rule is deliberately EMPTY, a\n * styling hook for consumers, so there is nothing painted to read in any environment.\n *\n * @example\n * ```ts\n * const secret = await loader.getHarness(WrDecryptTextHarness.with({ text: 'Hello' }));\n *\n * await secret.hover();\n * vi.advanceTimersByTime(50);\n *\n * expect(await secret.getRevealedIndices()).toEqual([0]); // sequential, from the start\n * expect(await secret.getAccessibleText()).toBe('Hello'); // untouched throughout\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrDecryptTextHarness extends ComponentHarness {\n static hostSelector = 'wr-decrypt-text';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrDecryptTextHarnessFilters = {}): HarnessPredicate<WrDecryptTextHarness> {\n return new HarnessPredicate(WrDecryptTextHarness, options)\n .addOption('text', options.text, (harness, text) =>\n HarnessPredicate.stringMatches(harness.getAccessibleText(), text)\n )\n .addOption('revealed', options.revealed, async (harness, revealed) => {\n // Not `isFullyRevealed()`, which refuses to answer for an instance that rendered\n // no characters. A predicate is the wrong place to throw — a single empty\n // instance would take down every query on the page — so the vacuous case is\n // spelled out here instead, and matches neither `true` nor `false`.\n if ((await harness.getCharCount()) === 0) return false;\n return ((await harness.getEncryptedCount()) === 0) === revealed;\n });\n }\n\n private readonly chars = this.locatorForAll(CHAR);\n private readonly encrypted = this.locatorForAll(ENCRYPTED);\n\n /**\n * The real string, as the one readable copy holds it.\n *\n * The single highest-value assertion here: it must stay equal to the `text` input on\n * every frame, while the visible layer is unreadable by design. Lose this span and the\n * component announces nothing at all — every drawn character sits under `aria-hidden`,\n * so no other part of the DOM would change.\n *\n * Untrimmed, so that it can be compared against {@link getRenderedText} without one\n * side of the comparison quietly forgiving a lost leading space.\n */\n async getAccessibleText(): Promise<string> {\n return rawText(await this.locatorFor(SR_ONLY)());\n }\n\n /**\n * What is on screen this frame — scramble glyphs and all, in document order.\n *\n * Plain before anything triggers it, gibberish mid-reveal, and the real string once it\n * settles; comparing it against {@link getAccessibleText} is how a spec says which of\n * those it is looking at. `useOriginalCharsOnly` is visible only here — every glyph\n * has to be one the text really contains.\n *\n * Nondeterministic unless the spec stubs `Math.random`, because each unrevealed\n * position is an independent draw from the pool. When the assertion does not actually\n * need the glyphs, {@link getRevealedIndices} answers the same progress question off\n * the class and needs no stub.\n */\n async getRenderedText(): Promise<string> {\n return (await Promise.all((await this.chars()).map(rawText))).join('');\n }\n\n /**\n * How many characters the animation walks.\n *\n * CODE POINTS, not UTF-16 units: `'a🚀b'` is 3 here, and the indices\n * {@link getRevealedIndices} returns line up with `[...text]` rather than with plain\n * `text[i]`. That distinction is not pedantry — counting units gave a sequential\n * reveal extra ticks with no character to spend them on, and made \"everything is\n * revealed\" disagree with what was on screen.\n */\n async getCharCount(): Promise<number> {\n return (await this.chars()).length;\n }\n\n /**\n * The positions that have settled on their real character, ascending.\n *\n * The payload method, and the deterministic one: it reads the `--encrypted` modifier\n * rather than the glyphs, so no `Math.random` stub is involved. It is the only thing\n * that separates `revealDirection` `'start'` (`[0]`, `[0, 1]`, …) from `'end'`\n * (`[4]`, `[3, 4]`, …) from `'center'` (`[2]`, `[1, 2]`, …), and one index per tick is\n * what makes a sequential reveal sequential.\n *\n * Ascending by position, NOT in the order the reveal visited them — the DOM records\n * which characters have landed, never the path taken to them. Assert the set after\n * each tick to pin an order.\n */\n async getRevealedIndices(): Promise<number[]> {\n const chars = await this.chars();\n const states = await Promise.all(chars.map(char => char.hasClass('wr-decrypt-text__char--encrypted')));\n return states.flatMap((isEncrypted, index) => (isEncrypted ? [] : [index]));\n }\n\n /**\n * How many characters are still scrambled.\n *\n * The coarse progress read, and the cheapest way to say \"scrambled on hover\", \"plain on\n * leave\", or \"a reader who asked for less motion never saw a scramble at all\". Class-\n * based like {@link getRevealedIndices}, so it too is random-proof.\n */\n async getEncryptedCount(): Promise<number> {\n return (await this.encrypted()).length;\n }\n\n /**\n * Whether every character has settled.\n *\n * Deliberately does NOT also compare {@link getRenderedText} against\n * {@link getAccessibleText}: folding two conditions into one boolean hides which of\n * them broke, and a spec that wants both should write both lines.\n *\n * Throws when nothing was rendered. \"No character is encrypted\" is true of no\n * characters, which is the same answer a component that stopped rendering its text\n * would give — and this is the method most likely to be the only assertion in a test.\n */\n async isFullyRevealed(): Promise<boolean> {\n const total = await this.getCharCount();\n\n if (total === 0) {\n throw new Error(\n 'WrDecryptTextHarness.isFullyRevealed(): this <wr-decrypt-text> rendered no characters, so \"nothing is ' +\n 'encrypted\" is vacuously true — the same answer a component that stopped rendering its text would ' +\n 'give. Check `text` is set, or ask getCharCount().'\n );\n }\n\n return (await this.getEncryptedCount()) === 0;\n }\n\n /**\n * Whether the scramble layer is out of the accessibility tree.\n *\n * The contract that keeps a screen reader from spelling out `XQ#PZ` beside the real\n * string it already read. Worth a method rather than an assumption because the wrapper\n * holding the characters carries NO class — it can only be addressed as the readable\n * span's next sibling, which any template reshuffle breaks.\n *\n * Throws when that structural selector finds nothing, rather than returning `false`: a\n * missing wrapper and an unhidden one are different failures, and the answer to\n * \"is the scramble hidden\" when there is no scramble layer at all is not `false`.\n */\n async isAnimatedLayerHidden(): Promise<boolean> {\n const scramble = await this.locatorForOptional(SCRAMBLE)();\n\n if (!scramble) {\n throw new Error(\n 'WrDecryptTextHarness.isAnimatedLayerHidden(): no scramble layer found. It carries no class of its own, ' +\n `so it is addressed structurally as \\`${SCRAMBLE}\\` — a template that moved either span out from ` +\n 'under that selector breaks this read, and \"false\" would report the layer as ANNOUNCED rather than as ' +\n 'missing.'\n );\n }\n\n return (await scramble.getAttribute('aria-hidden')) === 'true';\n }\n\n /**\n * Point at it — the trigger for `animateOn` `'hover'` and `'inViewHover'`.\n *\n * Drives the component the way a user does, and works in a test because the trigger is\n * an event rather than a gesture: `TestElement.hover()` dispatches `pointerenter`,\n * `mouseover` and `mouseenter`, and the component listens for the last of those. A\n * hand-rolled pointer-only dispatch would not reach it.\n *\n * Does nothing in the other two modes, exactly as a real pointer does nothing there.\n */\n async hover(): Promise<void> {\n return (await this.host()).hover();\n }\n\n /**\n * Move the pointer off — the other half of hover mode.\n *\n * Pins the promise that leaving mid-scramble restores the real text IMMEDIATELY rather\n * than letting the reveal play out: the reader took the effect away, so the string has\n * to come back at once.\n */\n async mouseAway(): Promise<void> {\n return (await this.host()).mouseAway();\n }\n\n /**\n * Click the host — the `animateOn=\"click\"` trigger, and the only way to tell\n * `clickMode` `'once'` from `'toggle'`.\n *\n * There is no keyboard equivalent, and that is a statement about the component rather\n * than about this harness: in click mode the host carries a click handler with no role,\n * no `tabindex` and no keydown handler, so a keyboard or switch user cannot reveal the\n * text at all. A `sendKeys(Enter)` here would invent an affordance that does not exist\n * and let a spec pass over the top of it.\n */\n async click(): Promise<void> {\n return (await this.host()).click();\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;AAAA;;;;;AAKG;AAMH;AACA,MAAM,OAAO,GAAG,2BAA2B;AAE3C;AACA,MAAM,IAAI,GAAG,wBAAwB;AAErC;AACA,MAAM,SAAS,GAAG,mCAAmC;AAErD;;;;;;;AAOG;AACH,MAAM,QAAQ,GAAG,CAAA,EAAG,OAAO,SAAS;AAEpC;AACA,eAAe,OAAO,CAAC,OAAoB,EAAA;IACzC,OAAO,CAAC,MAAM,OAAO,CAAC,WAAW,CAAgB,aAAa,CAAC,KAAK,EAAE;AACxE;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2DG;AACG,MAAO,oBAAqB,SAAQ,gBAAgB,CAAA;AACxD,IAAA,OAAO,YAAY,GAAG,iBAAiB;;AAGvC,IAAA,OAAO,IAAI,CAAC,OAAA,GAAuC,EAAE,EAAA;AACnD,QAAA,OAAO,IAAI,gBAAgB,CAAC,oBAAoB,EAAE,OAAO;aACtD,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,IAAI,KAC7C,gBAAgB,CAAC,aAAa,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,IAAI,CAAC;AAElE,aAAA,SAAS,CAAC,UAAU,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,OAAO,EAAE,QAAQ,KAAI;;;;;YAKnE,IAAI,CAAC,MAAM,OAAO,CAAC,YAAY,EAAE,MAAM,CAAC;AAAE,gBAAA,OAAO,KAAK;AACtD,YAAA,OAAO,CAAC,CAAC,MAAM,OAAO,CAAC,iBAAiB,EAAE,MAAM,CAAC,MAAM,QAAQ;AACjE,QAAA,CAAC,CAAC;IACN;AAEiB,IAAA,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC;AAChC,IAAA,SAAS,GAAG,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC;AAE1D;;;;;;;;;;AAUG;AACH,IAAA,MAAM,iBAAiB,GAAA;QACrB,OAAO,OAAO,CAAC,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;IAClD;AAEA;;;;;;;;;;;;AAYG;AACH,IAAA,MAAM,eAAe,GAAA;QACnB,OAAO,CAAC,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC;IACxE;AAEA;;;;;;;;AAQG;AACH,IAAA,MAAM,YAAY,GAAA;QAChB,OAAO,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,EAAE,MAAM;IACpC;AAEA;;;;;;;;;;;;AAYG;AACH,IAAA,MAAM,kBAAkB,GAAA;AACtB,QAAA,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE;QAChC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,kCAAkC,CAAC,CAAC,CAAC;QACtG,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,KAAK,MAAM,WAAW,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;IAC7E;AAEA;;;;;;AAMG;AACH,IAAA,MAAM,iBAAiB,GAAA;QACrB,OAAO,CAAC,MAAM,IAAI,CAAC,SAAS,EAAE,EAAE,MAAM;IACxC;AAEA;;;;;;;;;;AAUG;AACH,IAAA,MAAM,eAAe,GAAA;AACnB,QAAA,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,YAAY,EAAE;AAEvC,QAAA,IAAI,KAAK,KAAK,CAAC,EAAE;YACf,MAAM,IAAI,KAAK,CACb,wGAAwG;gBACtG,mGAAmG;AACnG,gBAAA,mDAAmD,CACtD;QACH;QAEA,OAAO,CAAC,MAAM,IAAI,CAAC,iBAAiB,EAAE,MAAM,CAAC;IAC/C;AAEA;;;;;;;;;;;AAWG;AACH,IAAA,MAAM,qBAAqB,GAAA;QACzB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,EAAE;QAE1D,IAAI,CAAC,QAAQ,EAAE;YACb,MAAM,IAAI,KAAK,CACb,yGAAyG;AACvG,gBAAA,CAAA,qCAAA,EAAwC,QAAQ,CAAA,gDAAA,CAAkD;gBAClG,uGAAuG;AACvG,gBAAA,UAAU,CACb;QACH;QAEA,OAAO,CAAC,MAAM,QAAQ,CAAC,YAAY,CAAC,aAAa,CAAC,MAAM,MAAM;IAChE;AAEA;;;;;;;;;AASG;AACH,IAAA,MAAM,KAAK,GAAA;QACT,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE;IACpC;AAEA;;;;;;AAMG;AACH,IAAA,MAAM,SAAS,GAAA;QACb,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE;IACxC;AAEA;;;;;;;;;AASG;AACH,IAAA,MAAM,KAAK,GAAA;QACT,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE;IACpC;;;ACzRF;;AAEG;;;;"}
@@ -160,7 +160,12 @@ class WrDecryptText {
160
160
  const txt = this.text();
161
161
  const mode = this.animateOn();
162
162
  this.stopInterval();
163
- if (mode === 'click') {
163
+ // The resting state of `click` mode is the scramble — but not for someone who
164
+ // asked for less motion. `startInterval` short-circuits every TRIGGER to the
165
+ // plain text, and this is the one path that never reaches it, so a reduced-
166
+ // motion reader was left staring at permanently scrambled glyphs with no
167
+ // pointer-free way to undo them.
168
+ if (mode === 'click' && !this.platform.prefersReducedMotion()) {
164
169
  this.encryptInstantly(txt);
165
170
  }
166
171
  else {
@@ -393,10 +398,10 @@ class WrDecryptText {
393
398
  })
394
399
  .join('');
395
400
  }
396
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrDecryptText, deps: [], target: i0.ɵɵFactoryTarget.Component });
397
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: WrDecryptText, isStandalone: true, selector: "wr-decrypt-text", inputs: { text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: true, transformFunction: null }, speed: { classPropertyName: "speed", publicName: "speed", isSignal: true, isRequired: false, transformFunction: null }, maxIterations: { classPropertyName: "maxIterations", publicName: "maxIterations", isSignal: true, isRequired: false, transformFunction: null }, sequential: { classPropertyName: "sequential", publicName: "sequential", isSignal: true, isRequired: false, transformFunction: null }, revealDirection: { classPropertyName: "revealDirection", publicName: "revealDirection", isSignal: true, isRequired: false, transformFunction: null }, useOriginalCharsOnly: { classPropertyName: "useOriginalCharsOnly", publicName: "useOriginalCharsOnly", isSignal: true, isRequired: false, transformFunction: null }, characters: { classPropertyName: "characters", publicName: "characters", isSignal: true, isRequired: false, transformFunction: null }, animateOn: { classPropertyName: "animateOn", publicName: "animateOn", isSignal: true, isRequired: false, transformFunction: null }, clickMode: { classPropertyName: "clickMode", publicName: "clickMode", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "onMouseLeave()", "click": "onClick()" }, classAttribute: "wr-decrypt-text" }, ngImport: i0, template: "<span class=\"wr-decrypt-text__sr-only\">{{ text() }}</span>\n<span aria-hidden=\"true\">\n @for (c of chars(); track $index) {\n <span [class]=\"c.revealed ? 'wr-decrypt-text__char' : 'wr-decrypt-text__char wr-decrypt-text__char--encrypted'\">{{\n c.ch\n }}</span>\n }\n</span>\n", styles: [".wr-decrypt-text{display:inline-block;white-space:pre-wrap}.wr-decrypt-text__sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0}.wr-decrypt-text__char{display:inline}\n"], encapsulation: i0.ViewEncapsulation.None });
401
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: WrDecryptText, deps: [], target: i0.ɵɵFactoryTarget.Component });
402
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.2", type: WrDecryptText, isStandalone: true, selector: "wr-decrypt-text", inputs: { text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: true, transformFunction: null }, speed: { classPropertyName: "speed", publicName: "speed", isSignal: true, isRequired: false, transformFunction: null }, maxIterations: { classPropertyName: "maxIterations", publicName: "maxIterations", isSignal: true, isRequired: false, transformFunction: null }, sequential: { classPropertyName: "sequential", publicName: "sequential", isSignal: true, isRequired: false, transformFunction: null }, revealDirection: { classPropertyName: "revealDirection", publicName: "revealDirection", isSignal: true, isRequired: false, transformFunction: null }, useOriginalCharsOnly: { classPropertyName: "useOriginalCharsOnly", publicName: "useOriginalCharsOnly", isSignal: true, isRequired: false, transformFunction: null }, characters: { classPropertyName: "characters", publicName: "characters", isSignal: true, isRequired: false, transformFunction: null }, animateOn: { classPropertyName: "animateOn", publicName: "animateOn", isSignal: true, isRequired: false, transformFunction: null }, clickMode: { classPropertyName: "clickMode", publicName: "clickMode", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "onMouseLeave()", "click": "onClick()" }, classAttribute: "wr-decrypt-text" }, ngImport: i0, template: "<span class=\"wr-decrypt-text__sr-only\">{{ text() }}</span>\n<span aria-hidden=\"true\">\n @for (c of chars(); track $index) {\n <span [class]=\"c.revealed ? 'wr-decrypt-text__char' : 'wr-decrypt-text__char wr-decrypt-text__char--encrypted'\">{{\n c.ch\n }}</span>\n }\n</span>\n", styles: [".wr-decrypt-text{display:inline-block;white-space:pre-wrap}.wr-decrypt-text__sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0}.wr-decrypt-text__char{display:inline}\n"], encapsulation: i0.ViewEncapsulation.None });
398
403
  }
399
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrDecryptText, decorators: [{
404
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: WrDecryptText, decorators: [{
400
405
  type: Component,
401
406
  args: [{ selector: 'wr-decrypt-text', encapsulation: ViewEncapsulation.None, host: {
402
407
  class: 'wr-decrypt-text',