ngwr 10.2.0 → 11.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 (471) hide show
  1. package/README.md +39 -19
  2. package/anchor/styles/_index.scss +4 -4
  3. package/back-top/styles/_index.scss +6 -1
  4. package/blur-text/styles/_index.scss +13 -0
  5. package/button/styles/_index.scss +11 -6
  6. package/carousel/styles/_index.scss +13 -2
  7. package/cascader/styles/_index.scss +2 -2
  8. package/circular-text/styles/_index.scss +2 -0
  9. package/collapse/styles/_index.scss +1 -1
  10. package/color-picker/styles/_index.scss +6 -1
  11. package/compare/styles/_index.scss +1 -2
  12. package/context-menu/styles/_index.scss +6 -1
  13. package/descriptions/styles/_index.scss +2 -2
  14. package/dialog/styles/_index.scss +38 -0
  15. package/drawer/styles/_index.scss +20 -1
  16. package/dropdown/styles/_index.scss +19 -5
  17. package/empty/styles/_index.scss +10 -0
  18. package/fesm2022/ngwr-action-sheet.mjs +15 -5
  19. package/fesm2022/ngwr-action-sheet.mjs.map +1 -1
  20. package/fesm2022/ngwr-affix.mjs +43 -16
  21. package/fesm2022/ngwr-affix.mjs.map +1 -1
  22. package/fesm2022/ngwr-alert.mjs +3 -3
  23. package/fesm2022/ngwr-anchor.mjs +20 -8
  24. package/fesm2022/ngwr-anchor.mjs.map +1 -1
  25. package/fesm2022/ngwr-aurora.mjs +4 -4
  26. package/fesm2022/ngwr-aurora.mjs.map +1 -1
  27. package/fesm2022/ngwr-avatar.mjs +33 -9
  28. package/fesm2022/ngwr-avatar.mjs.map +1 -1
  29. package/fesm2022/ngwr-back-top.mjs +8 -4
  30. package/fesm2022/ngwr-back-top.mjs.map +1 -1
  31. package/fesm2022/ngwr-badge.mjs +6 -6
  32. package/fesm2022/ngwr-badge.mjs.map +1 -1
  33. package/fesm2022/ngwr-bar-chart.mjs +32 -11
  34. package/fesm2022/ngwr-bar-chart.mjs.map +1 -1
  35. package/fesm2022/ngwr-blur-text.mjs +4 -4
  36. package/fesm2022/ngwr-blur-text.mjs.map +1 -1
  37. package/fesm2022/ngwr-border-glow.mjs +4 -4
  38. package/fesm2022/ngwr-border-glow.mjs.map +1 -1
  39. package/fesm2022/ngwr-breadcrumbs.mjs +9 -8
  40. package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
  41. package/fesm2022/ngwr-burger.mjs +11 -6
  42. package/fesm2022/ngwr-burger.mjs.map +1 -1
  43. package/fesm2022/ngwr-button-testing.mjs +96 -0
  44. package/fesm2022/ngwr-button-testing.mjs.map +1 -0
  45. package/fesm2022/ngwr-button.mjs +89 -24
  46. package/fesm2022/ngwr-button.mjs.map +1 -1
  47. package/fesm2022/ngwr-calendar-heatmap.mjs +42 -10
  48. package/fesm2022/ngwr-calendar-heatmap.mjs.map +1 -1
  49. package/fesm2022/ngwr-calendar.mjs +108 -9
  50. package/fesm2022/ngwr-calendar.mjs.map +1 -1
  51. package/fesm2022/ngwr-card.mjs +10 -10
  52. package/fesm2022/ngwr-card.mjs.map +1 -1
  53. package/fesm2022/ngwr-carousel-testing.mjs +377 -0
  54. package/fesm2022/ngwr-carousel-testing.mjs.map +1 -0
  55. package/fesm2022/ngwr-carousel.mjs +72 -18
  56. package/fesm2022/ngwr-carousel.mjs.map +1 -1
  57. package/fesm2022/ngwr-cascader-testing.mjs +534 -0
  58. package/fesm2022/ngwr-cascader-testing.mjs.map +1 -0
  59. package/fesm2022/ngwr-cascader.mjs +4 -4
  60. package/fesm2022/ngwr-cascader.mjs.map +1 -1
  61. package/fesm2022/ngwr-checkbox-testing.mjs +90 -0
  62. package/fesm2022/ngwr-checkbox-testing.mjs.map +1 -0
  63. package/fesm2022/ngwr-checkbox.mjs +15 -9
  64. package/fesm2022/ngwr-checkbox.mjs.map +1 -1
  65. package/fesm2022/ngwr-circular-text.mjs +4 -4
  66. package/fesm2022/ngwr-circular-text.mjs.map +1 -1
  67. package/fesm2022/ngwr-click-spark.mjs +4 -4
  68. package/fesm2022/ngwr-click-spark.mjs.map +1 -1
  69. package/fesm2022/ngwr-clipboard.mjs +18 -4
  70. package/fesm2022/ngwr-clipboard.mjs.map +1 -1
  71. package/fesm2022/ngwr-collapse-testing.mjs +368 -0
  72. package/fesm2022/ngwr-collapse-testing.mjs.map +1 -0
  73. package/fesm2022/ngwr-collapse.mjs +9 -9
  74. package/fesm2022/ngwr-color-picker.mjs +139 -19
  75. package/fesm2022/ngwr-color-picker.mjs.map +1 -1
  76. package/fesm2022/ngwr-command-palette-testing.mjs +589 -0
  77. package/fesm2022/ngwr-command-palette-testing.mjs.map +1 -0
  78. package/fesm2022/ngwr-command-palette.mjs +60 -10
  79. package/fesm2022/ngwr-command-palette.mjs.map +1 -1
  80. package/fesm2022/ngwr-compare.mjs +105 -15
  81. package/fesm2022/ngwr-compare.mjs.map +1 -1
  82. package/fesm2022/ngwr-confetti.mjs +3 -3
  83. package/fesm2022/ngwr-config.mjs +106 -0
  84. package/fesm2022/ngwr-config.mjs.map +1 -0
  85. package/fesm2022/ngwr-context-menu-testing.mjs +631 -0
  86. package/fesm2022/ngwr-context-menu-testing.mjs.map +1 -0
  87. package/fesm2022/ngwr-context-menu.mjs +104 -18
  88. package/fesm2022/ngwr-context-menu.mjs.map +1 -1
  89. package/fesm2022/ngwr-cookie.mjs +8 -4
  90. package/fesm2022/ngwr-cookie.mjs.map +1 -1
  91. package/fesm2022/ngwr-counter.mjs +17 -9
  92. package/fesm2022/ngwr-counter.mjs.map +1 -1
  93. package/fesm2022/ngwr-date-adapter-fns.mjs +3 -3
  94. package/fesm2022/ngwr-date-adapter-luxon.mjs +55 -7
  95. package/fesm2022/ngwr-date-adapter-luxon.mjs.map +1 -1
  96. package/fesm2022/ngwr-date-adapter.mjs +57 -11
  97. package/fesm2022/ngwr-date-adapter.mjs.map +1 -1
  98. package/fesm2022/ngwr-date-picker-testing.mjs +766 -0
  99. package/fesm2022/ngwr-date-picker-testing.mjs.map +1 -0
  100. package/fesm2022/ngwr-date-picker.mjs +409 -57
  101. package/fesm2022/ngwr-date-picker.mjs.map +1 -1
  102. package/fesm2022/ngwr-decrypt-text.mjs +30 -12
  103. package/fesm2022/ngwr-decrypt-text.mjs.map +1 -1
  104. package/fesm2022/ngwr-density.mjs +6 -6
  105. package/fesm2022/ngwr-descriptions.mjs +6 -6
  106. package/fesm2022/ngwr-dialog-testing.mjs +89 -0
  107. package/fesm2022/ngwr-dialog-testing.mjs.map +1 -0
  108. package/fesm2022/ngwr-dialog.mjs +33 -17
  109. package/fesm2022/ngwr-dialog.mjs.map +1 -1
  110. package/fesm2022/ngwr-directives.mjs +48 -24
  111. package/fesm2022/ngwr-directives.mjs.map +1 -1
  112. package/fesm2022/ngwr-divider.mjs +3 -3
  113. package/fesm2022/ngwr-donut-chart.mjs +24 -7
  114. package/fesm2022/ngwr-donut-chart.mjs.map +1 -1
  115. package/fesm2022/ngwr-drag-drop.mjs +7 -7
  116. package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
  117. package/fesm2022/ngwr-drawer-testing.mjs +250 -0
  118. package/fesm2022/ngwr-drawer-testing.mjs.map +1 -0
  119. package/fesm2022/ngwr-drawer.mjs +37 -19
  120. package/fesm2022/ngwr-drawer.mjs.map +1 -1
  121. package/fesm2022/ngwr-dropdown-testing.mjs +291 -0
  122. package/fesm2022/ngwr-dropdown-testing.mjs.map +1 -0
  123. package/fesm2022/ngwr-dropdown.mjs +19 -11
  124. package/fesm2022/ngwr-dropdown.mjs.map +1 -1
  125. package/fesm2022/ngwr-empty.mjs +26 -9
  126. package/fesm2022/ngwr-empty.mjs.map +1 -1
  127. package/fesm2022/ngwr-event-calendar.mjs +62 -15
  128. package/fesm2022/ngwr-event-calendar.mjs.map +1 -1
  129. package/fesm2022/ngwr-falling-text.mjs +4 -4
  130. package/fesm2022/ngwr-falling-text.mjs.map +1 -1
  131. package/fesm2022/ngwr-file-upload-testing.mjs +332 -0
  132. package/fesm2022/ngwr-file-upload-testing.mjs.map +1 -0
  133. package/fesm2022/ngwr-file-upload.mjs +3 -3
  134. package/fesm2022/ngwr-form-testing.mjs +451 -0
  135. package/fesm2022/ngwr-form-testing.mjs.map +1 -0
  136. package/fesm2022/ngwr-form.mjs +28 -12
  137. package/fesm2022/ngwr-form.mjs.map +1 -1
  138. package/fesm2022/ngwr-fuzzy-text.mjs +11 -4
  139. package/fesm2022/ngwr-fuzzy-text.mjs.map +1 -1
  140. package/fesm2022/ngwr-gauge.mjs +21 -7
  141. package/fesm2022/ngwr-gauge.mjs.map +1 -1
  142. package/fesm2022/ngwr-glitch-text.mjs +4 -4
  143. package/fesm2022/ngwr-glitch-text.mjs.map +1 -1
  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 +31 -10
  147. package/fesm2022/ngwr-hotkey.mjs.map +1 -1
  148. package/fesm2022/ngwr-i18n-en.mjs +61 -0
  149. package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
  150. package/fesm2022/ngwr-i18n-ru.mjs +59 -0
  151. package/fesm2022/ngwr-i18n-ru.mjs.map +1 -1
  152. package/fesm2022/ngwr-i18n.mjs +9 -9
  153. package/fesm2022/ngwr-icon.mjs +6 -6
  154. package/fesm2022/ngwr-image-cropper.mjs +26 -3
  155. package/fesm2022/ngwr-image-cropper.mjs.map +1 -1
  156. package/fesm2022/ngwr-input-number-testing.mjs +306 -0
  157. package/fesm2022/ngwr-input-number-testing.mjs.map +1 -0
  158. package/fesm2022/ngwr-input-number.mjs +37 -5
  159. package/fesm2022/ngwr-input-number.mjs.map +1 -1
  160. package/fesm2022/ngwr-input-otp-testing.mjs +419 -0
  161. package/fesm2022/ngwr-input-otp-testing.mjs.map +1 -0
  162. package/fesm2022/ngwr-input-otp.mjs +39 -8
  163. package/fesm2022/ngwr-input-otp.mjs.map +1 -1
  164. package/fesm2022/ngwr-input-testing.mjs +102 -0
  165. package/fesm2022/ngwr-input-testing.mjs.map +1 -0
  166. package/fesm2022/ngwr-input.mjs +62 -25
  167. package/fesm2022/ngwr-input.mjs.map +1 -1
  168. package/fesm2022/ngwr-keyboard.mjs +3 -3
  169. package/fesm2022/ngwr-knob.mjs +46 -10
  170. package/fesm2022/ngwr-knob.mjs.map +1 -1
  171. package/fesm2022/ngwr-layout.mjs +36 -20
  172. package/fesm2022/ngwr-layout.mjs.map +1 -1
  173. package/fesm2022/ngwr-lightbox.mjs +35 -8
  174. package/fesm2022/ngwr-lightbox.mjs.map +1 -1
  175. package/fesm2022/ngwr-line-chart.mjs +19 -6
  176. package/fesm2022/ngwr-line-chart.mjs.map +1 -1
  177. package/fesm2022/ngwr-list.mjs +14 -9
  178. package/fesm2022/ngwr-list.mjs.map +1 -1
  179. package/fesm2022/ngwr-loading-bar.mjs +71 -31
  180. package/fesm2022/ngwr-loading-bar.mjs.map +1 -1
  181. package/fesm2022/ngwr-markdown-testing.mjs +516 -0
  182. package/fesm2022/ngwr-markdown-testing.mjs.map +1 -0
  183. package/fesm2022/ngwr-markdown.mjs +1492 -0
  184. package/fesm2022/ngwr-markdown.mjs.map +1 -0
  185. package/fesm2022/ngwr-marquee.mjs +19 -8
  186. package/fesm2022/ngwr-marquee.mjs.map +1 -1
  187. package/fesm2022/ngwr-media.mjs +3 -3
  188. package/fesm2022/ngwr-mention-testing.mjs +513 -0
  189. package/fesm2022/ngwr-mention-testing.mjs.map +1 -0
  190. package/fesm2022/ngwr-mention.mjs +16 -7
  191. package/fesm2022/ngwr-mention.mjs.map +1 -1
  192. package/fesm2022/ngwr-meta.mjs +28 -13
  193. package/fesm2022/ngwr-meta.mjs.map +1 -1
  194. package/fesm2022/ngwr-meter-group.mjs +22 -8
  195. package/fesm2022/ngwr-meter-group.mjs.map +1 -1
  196. package/fesm2022/ngwr-overlay.mjs +57 -8
  197. package/fesm2022/ngwr-overlay.mjs.map +1 -1
  198. package/fesm2022/ngwr-page-header.mjs +3 -3
  199. package/fesm2022/ngwr-pagination-testing.mjs +389 -0
  200. package/fesm2022/ngwr-pagination-testing.mjs.map +1 -0
  201. package/fesm2022/ngwr-pagination.mjs +27 -11
  202. package/fesm2022/ngwr-pagination.mjs.map +1 -1
  203. package/fesm2022/ngwr-pipes.mjs +21 -21
  204. package/fesm2022/ngwr-platform.mjs +9 -9
  205. package/fesm2022/ngwr-popconfirm-testing.mjs +309 -0
  206. package/fesm2022/ngwr-popconfirm-testing.mjs.map +1 -0
  207. package/fesm2022/ngwr-popconfirm.mjs +99 -21
  208. package/fesm2022/ngwr-popconfirm.mjs.map +1 -1
  209. package/fesm2022/ngwr-popover-testing.mjs +316 -0
  210. package/fesm2022/ngwr-popover-testing.mjs.map +1 -0
  211. package/fesm2022/ngwr-popover.mjs +48 -10
  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 +19 -4
  215. package/fesm2022/ngwr-pull-to-refresh.mjs.map +1 -1
  216. package/fesm2022/ngwr-qr.mjs +15 -5
  217. package/fesm2022/ngwr-qr.mjs.map +1 -1
  218. package/fesm2022/ngwr-radio-testing.mjs +392 -0
  219. package/fesm2022/ngwr-radio-testing.mjs.map +1 -0
  220. package/fesm2022/ngwr-radio.mjs +16 -9
  221. package/fesm2022/ngwr-radio.mjs.map +1 -1
  222. package/fesm2022/ngwr-rating-testing.mjs +384 -0
  223. package/fesm2022/ngwr-rating-testing.mjs.map +1 -0
  224. package/fesm2022/ngwr-rating.mjs +40 -5
  225. package/fesm2022/ngwr-rating.mjs.map +1 -1
  226. package/fesm2022/ngwr-result.mjs +12 -12
  227. package/fesm2022/ngwr-rotating-text.mjs +3 -3
  228. package/fesm2022/ngwr-scroll.mjs +3 -3
  229. package/fesm2022/ngwr-segmented-testing.mjs +512 -0
  230. package/fesm2022/ngwr-segmented-testing.mjs.map +1 -0
  231. package/fesm2022/ngwr-segmented.mjs +3 -3
  232. package/fesm2022/ngwr-select-testing.mjs +268 -0
  233. package/fesm2022/ngwr-select-testing.mjs.map +1 -0
  234. package/fesm2022/ngwr-select.mjs +96 -25
  235. package/fesm2022/ngwr-select.mjs.map +1 -1
  236. package/fesm2022/ngwr-shiny-text.mjs +7 -7
  237. package/fesm2022/ngwr-shiny-text.mjs.map +1 -1
  238. package/fesm2022/ngwr-sidebar.mjs +67 -14
  239. package/fesm2022/ngwr-sidebar.mjs.map +1 -1
  240. package/fesm2022/ngwr-skeleton.mjs +3 -3
  241. package/fesm2022/ngwr-slider-testing.mjs +478 -0
  242. package/fesm2022/ngwr-slider-testing.mjs.map +1 -0
  243. package/fesm2022/ngwr-slider.mjs +59 -15
  244. package/fesm2022/ngwr-slider.mjs.map +1 -1
  245. package/fesm2022/ngwr-sparkline.mjs +28 -8
  246. package/fesm2022/ngwr-sparkline.mjs.map +1 -1
  247. package/fesm2022/ngwr-speed-dial.mjs +39 -6
  248. package/fesm2022/ngwr-speed-dial.mjs.map +1 -1
  249. package/fesm2022/ngwr-spinner.mjs +14 -5
  250. package/fesm2022/ngwr-spinner.mjs.map +1 -1
  251. package/fesm2022/ngwr-splash-cursor.mjs +4 -4
  252. package/fesm2022/ngwr-splash-cursor.mjs.map +1 -1
  253. package/fesm2022/ngwr-split-text.mjs +4 -4
  254. package/fesm2022/ngwr-split-text.mjs.map +1 -1
  255. package/fesm2022/ngwr-splitter.mjs +72 -11
  256. package/fesm2022/ngwr-splitter.mjs.map +1 -1
  257. package/fesm2022/ngwr-spotlight-card.mjs +7 -7
  258. package/fesm2022/ngwr-spotlight-card.mjs.map +1 -1
  259. package/fesm2022/ngwr-squircle.mjs +6 -6
  260. package/fesm2022/ngwr-star-border.mjs +4 -4
  261. package/fesm2022/ngwr-star-border.mjs.map +1 -1
  262. package/fesm2022/ngwr-statistic.mjs +33 -16
  263. package/fesm2022/ngwr-statistic.mjs.map +1 -1
  264. package/fesm2022/ngwr-stepper-testing.mjs +477 -0
  265. package/fesm2022/ngwr-stepper-testing.mjs.map +1 -0
  266. package/fesm2022/ngwr-stepper.mjs +6 -6
  267. package/fesm2022/ngwr-storage.mjs +27 -17
  268. package/fesm2022/ngwr-storage.mjs.map +1 -1
  269. package/fesm2022/ngwr-switch-testing.mjs +77 -0
  270. package/fesm2022/ngwr-switch-testing.mjs.map +1 -0
  271. package/fesm2022/ngwr-switch.mjs +12 -6
  272. package/fesm2022/ngwr-switch.mjs.map +1 -1
  273. package/fesm2022/ngwr-table-testing.mjs +580 -0
  274. package/fesm2022/ngwr-table-testing.mjs.map +1 -0
  275. package/fesm2022/ngwr-table.mjs +105 -44
  276. package/fesm2022/ngwr-table.mjs.map +1 -1
  277. package/fesm2022/ngwr-tabs-testing.mjs +617 -0
  278. package/fesm2022/ngwr-tabs-testing.mjs.map +1 -0
  279. package/fesm2022/ngwr-tabs.mjs +44 -12
  280. package/fesm2022/ngwr-tabs.mjs.map +1 -1
  281. package/fesm2022/ngwr-textarea-testing.mjs +238 -0
  282. package/fesm2022/ngwr-textarea-testing.mjs.map +1 -0
  283. package/fesm2022/ngwr-textarea.mjs +35 -7
  284. package/fesm2022/ngwr-textarea.mjs.map +1 -1
  285. package/fesm2022/ngwr-theme.mjs +3 -3
  286. package/fesm2022/ngwr-tilt-card.mjs +7 -7
  287. package/fesm2022/ngwr-tilt-card.mjs.map +1 -1
  288. package/fesm2022/ngwr-timeline.mjs +6 -6
  289. package/fesm2022/ngwr-toast-testing.mjs +101 -0
  290. package/fesm2022/ngwr-toast-testing.mjs.map +1 -0
  291. package/fesm2022/ngwr-toast.mjs +55 -21
  292. package/fesm2022/ngwr-toast.mjs.map +1 -1
  293. package/fesm2022/ngwr-toolbar.mjs +3 -3
  294. package/fesm2022/ngwr-tour.mjs +67 -15
  295. package/fesm2022/ngwr-tour.mjs.map +1 -1
  296. package/fesm2022/ngwr-transfer-testing.mjs +538 -0
  297. package/fesm2022/ngwr-transfer-testing.mjs.map +1 -0
  298. package/fesm2022/ngwr-transfer.mjs +47 -16
  299. package/fesm2022/ngwr-transfer.mjs.map +1 -1
  300. package/fesm2022/ngwr-tree-testing.mjs +734 -0
  301. package/fesm2022/ngwr-tree-testing.mjs.map +1 -0
  302. package/fesm2022/ngwr-tree.mjs +75 -9
  303. package/fesm2022/ngwr-tree.mjs.map +1 -1
  304. package/fesm2022/ngwr-typewriter.mjs +7 -5
  305. package/fesm2022/ngwr-typewriter.mjs.map +1 -1
  306. package/fesm2022/ngwr-typography.mjs +3 -3
  307. package/fesm2022/ngwr-version.mjs +1 -1
  308. package/fesm2022/ngwr-version.mjs.map +1 -1
  309. package/fesm2022/ngwr-virtual-scroll.mjs +33 -7
  310. package/fesm2022/ngwr-virtual-scroll.mjs.map +1 -1
  311. package/fesm2022/ngwr-waves.mjs +5 -5
  312. package/fesm2022/ngwr-waves.mjs.map +1 -1
  313. package/fesm2022/ngwr-window.mjs +88 -18
  314. package/fesm2022/ngwr-window.mjs.map +1 -1
  315. package/gauge/styles/_index.scss +1 -1
  316. package/glitch-text/styles/_index.scss +4 -0
  317. package/i18n/en.json +56 -0
  318. package/i18n/ru.json +56 -0
  319. package/image-cropper/styles/_index.scss +13 -1
  320. package/input/styles/_index.scss +2 -2
  321. package/input-number/styles/_index.scss +7 -2
  322. package/knob/styles/_index.scss +8 -1
  323. package/layout/styles/_index.scss +3 -3
  324. package/lightbox/styles/_index.scss +10 -2
  325. package/line-chart/styles/_index.scss +6 -0
  326. package/llms-full.txt +151 -4
  327. package/llms.txt +57 -8
  328. package/loading-bar/styles/_index.scss +1 -2
  329. package/markdown/styles/_index.scss +296 -0
  330. package/marquee/styles/_index.scss +12 -0
  331. package/mcp/api.js +512 -0
  332. package/mcp/catalog.js +157 -0
  333. package/mcp/server.js +273 -0
  334. package/mcp/tools.js +366 -0
  335. package/meter-group/styles/_index.scss +1 -1
  336. package/package.json +186 -35
  337. package/pagination/styles/_index.scss +6 -6
  338. package/popover/styles/_index.scss +37 -5
  339. package/rating/styles/_index.scss +10 -0
  340. package/schematics/use/symbol-map.json +2 -0
  341. package/segmented/styles/_index.scss +7 -0
  342. package/select/styles/_index.scss +29 -9
  343. package/sidebar/styles/_index.scss +30 -5
  344. package/slider/styles/_index.scss +15 -0
  345. package/speed-dial/styles/_index.scss +20 -0
  346. package/split-text/styles/_index.scss +13 -0
  347. package/star-border/styles/_index.scss +2 -0
  348. package/stepper/styles/_index.scss +1 -1
  349. package/styles/_grid.scss +4 -4
  350. package/styles.scss +1 -0
  351. package/switch/styles/_index.scss +5 -3
  352. package/table/styles/_index.scss +22 -11
  353. package/tabs/styles/_index.scss +11 -1
  354. package/textarea/styles/_index.scss +5 -0
  355. package/theme/styles/_colors.scss +29 -13
  356. package/theme/styles/_dark.scss +11 -3
  357. package/theme/styles/_mixins.scss +3 -0
  358. package/timeline/styles/_index.scss +2 -2
  359. package/toast/styles/_index.scss +17 -8
  360. package/toolbar/styles/_index.scss +3 -3
  361. package/tour/styles/_index.scss +7 -1
  362. package/tree/styles/_index.scss +5 -3
  363. package/types/ngwr-action-sheet.d.ts +9 -1
  364. package/types/ngwr-affix.d.ts +7 -1
  365. package/types/ngwr-anchor.d.ts +8 -1
  366. package/types/ngwr-avatar.d.ts +13 -3
  367. package/types/ngwr-bar-chart.d.ts +16 -0
  368. package/types/ngwr-burger.d.ts +6 -2
  369. package/types/ngwr-button-testing.d.ts +85 -0
  370. package/types/ngwr-button.d.ts +58 -10
  371. package/types/ngwr-calendar-heatmap.d.ts +16 -2
  372. package/types/ngwr-calendar.d.ts +37 -1
  373. package/types/ngwr-carousel-testing.d.ts +257 -0
  374. package/types/ngwr-carousel.d.ts +20 -4
  375. package/types/ngwr-cascader-testing.d.ts +392 -0
  376. package/types/ngwr-checkbox-testing.d.ts +77 -0
  377. package/types/ngwr-checkbox.d.ts +7 -2
  378. package/types/ngwr-clipboard.d.ts +8 -1
  379. package/types/ngwr-collapse-testing.d.ts +290 -0
  380. package/types/ngwr-color-picker.d.ts +20 -11
  381. package/types/ngwr-command-palette-testing.d.ts +437 -0
  382. package/types/ngwr-command-palette.d.ts +25 -2
  383. package/types/ngwr-compare.d.ts +50 -2
  384. package/types/ngwr-config.d.ts +176 -0
  385. package/types/ngwr-context-menu-testing.d.ts +401 -0
  386. package/types/ngwr-context-menu.d.ts +65 -17
  387. package/types/ngwr-counter.d.ts +6 -1
  388. package/types/ngwr-date-adapter-luxon.d.ts +26 -0
  389. package/types/ngwr-date-picker-testing.d.ts +518 -0
  390. package/types/ngwr-date-picker.d.ts +128 -8
  391. package/types/ngwr-dialog-testing.d.ts +79 -0
  392. package/types/ngwr-dialog.d.ts +13 -0
  393. package/types/ngwr-directives.d.ts +10 -1
  394. package/types/ngwr-donut-chart.d.ts +8 -1
  395. package/types/ngwr-drawer-testing.d.ts +196 -0
  396. package/types/ngwr-drawer.d.ts +15 -0
  397. package/types/ngwr-dropdown-testing.d.ts +202 -0
  398. package/types/ngwr-dropdown.d.ts +7 -1
  399. package/types/ngwr-empty.d.ts +19 -4
  400. package/types/ngwr-event-calendar.d.ts +26 -1
  401. package/types/ngwr-file-upload-testing.d.ts +194 -0
  402. package/types/ngwr-form-testing.d.ts +379 -0
  403. package/types/ngwr-form.d.ts +17 -0
  404. package/types/ngwr-gauge.d.ts +13 -1
  405. package/types/ngwr-hotkey.d.ts +2 -0
  406. package/types/ngwr-image-cropper.d.ts +10 -0
  407. package/types/ngwr-input-number-testing.d.ts +226 -0
  408. package/types/ngwr-input-number.d.ts +29 -1
  409. package/types/ngwr-input-otp-testing.d.ts +299 -0
  410. package/types/ngwr-input-otp.d.ts +23 -2
  411. package/types/ngwr-input-testing.d.ts +84 -0
  412. package/types/ngwr-input.d.ts +20 -6
  413. package/types/ngwr-knob.d.ts +18 -0
  414. package/types/ngwr-layout.d.ts +1 -0
  415. package/types/ngwr-lightbox.d.ts +17 -3
  416. package/types/ngwr-line-chart.d.ts +9 -2
  417. package/types/ngwr-list.d.ts +7 -2
  418. package/types/ngwr-loading-bar.d.ts +4 -7
  419. package/types/ngwr-markdown-testing.d.ts +462 -0
  420. package/types/ngwr-markdown.d.ts +534 -0
  421. package/types/ngwr-marquee.d.ts +12 -2
  422. package/types/ngwr-mention-testing.d.ts +359 -0
  423. package/types/ngwr-meta.d.ts +4 -2
  424. package/types/ngwr-meter-group.d.ts +11 -1
  425. package/types/ngwr-overlay.d.ts +33 -2
  426. package/types/ngwr-pagination-testing.d.ts +291 -0
  427. package/types/ngwr-pagination.d.ts +7 -1
  428. package/types/ngwr-popconfirm-testing.d.ts +235 -0
  429. package/types/ngwr-popconfirm.d.ts +31 -21
  430. package/types/ngwr-popover-testing.d.ts +221 -0
  431. package/types/ngwr-popover.d.ts +19 -2
  432. package/types/ngwr-pull-to-refresh.d.ts +7 -0
  433. package/types/ngwr-qr.d.ts +9 -1
  434. package/types/ngwr-radio-testing.d.ts +296 -0
  435. package/types/ngwr-radio.d.ts +8 -2
  436. package/types/ngwr-rating-testing.d.ts +291 -0
  437. package/types/ngwr-rating.d.ts +23 -0
  438. package/types/ngwr-segmented-testing.d.ts +401 -0
  439. package/types/ngwr-select-testing.d.ts +175 -0
  440. package/types/ngwr-select.d.ts +45 -4
  441. package/types/ngwr-sidebar.d.ts +17 -2
  442. package/types/ngwr-slider-testing.d.ts +329 -0
  443. package/types/ngwr-slider.d.ts +35 -1
  444. package/types/ngwr-sparkline.d.ts +12 -2
  445. package/types/ngwr-speed-dial.d.ts +17 -18
  446. package/types/ngwr-spinner.d.ts +8 -1
  447. package/types/ngwr-splitter.d.ts +24 -1
  448. package/types/ngwr-statistic.d.ts +12 -2
  449. package/types/ngwr-stepper-testing.d.ts +346 -0
  450. package/types/ngwr-storage.d.ts +10 -1
  451. package/types/ngwr-switch-testing.d.ts +66 -0
  452. package/types/ngwr-switch.d.ts +7 -2
  453. package/types/ngwr-table-testing.d.ts +423 -0
  454. package/types/ngwr-table.d.ts +42 -0
  455. package/types/ngwr-tabs-testing.d.ts +470 -0
  456. package/types/ngwr-tabs.d.ts +9 -0
  457. package/types/ngwr-textarea-testing.d.ts +184 -0
  458. package/types/ngwr-textarea.d.ts +7 -2
  459. package/types/ngwr-toast-testing.d.ts +80 -0
  460. package/types/ngwr-toast.d.ts +19 -4
  461. package/types/ngwr-tour.d.ts +27 -0
  462. package/types/ngwr-transfer-testing.d.ts +444 -0
  463. package/types/ngwr-transfer.d.ts +16 -1
  464. package/types/ngwr-tree-testing.d.ts +501 -0
  465. package/types/ngwr-tree.d.ts +33 -0
  466. package/types/ngwr-version.d.ts +1 -1
  467. package/types/ngwr-virtual-scroll.d.ts +13 -1
  468. package/types/ngwr-window.d.ts +23 -2
  469. package/typewriter/styles/_index.scss +1 -1
  470. package/typography/styles/_index.scss +1 -1
  471. package/window/styles/_index.scss +32 -9
@@ -1,6 +1,9 @@
1
+ import { Directionality } from '@angular/cdk/bidi';
1
2
  import { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';
2
3
  import * as i0 from '@angular/core';
3
- import { model, input, inject, ElementRef, computed, ViewEncapsulation, Component } from '@angular/core';
4
+ import { model, input, inject, ElementRef, signal, effect, computed, ViewEncapsulation, Component } from '@angular/core';
5
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
6
+ import { useI18nText } from 'ngwr/i18n';
4
7
  import { clamp } from 'ngwr/utils';
5
8
 
6
9
  /**
@@ -28,12 +31,31 @@ import { clamp } from 'ngwr/utils';
28
31
  * </wr-compare>
29
32
  * ```
30
33
  *
34
+ * Under `dir="rtl"` the horizontal wipe MIRRORS: "before" occupies the inline-start
35
+ * side, which is the right. Before/after is an ordinal pair — the two ends of a
36
+ * progression — and ordinal progressions follow reading order, the same reason a
37
+ * progress bar fills from the right in Arabic. The LTR habit of putting "before" on
38
+ * the left IS reading order, so mirroring preserves that intent rather than breaking
39
+ * it. Nothing is flipped pixel-wise: both layers are the images the consumer passed,
40
+ * unscaled and unmirrored — only the side each is revealed on changes.
41
+ *
42
+ * Pinning the physical arrangement inside an RTL page takes the CDK's `Dir` directive
43
+ * (`[dir]`, from `@angular/cdk/bidi`) on a wrapper, because that is what provides a
44
+ * scoped `Directionality`. A bare `dir="ltr"` attribute does NOT do it: the ambient
45
+ * `Directionality` reads `<html>` / `<body>` once at startup and never looks at the
46
+ * element, and this component's horizontal wipe is painted entirely from TypeScript,
47
+ * so the attribute would change nothing at all while looking like an opt-out.
48
+ *
31
49
  * @see https://ngwr.dev/reference/components/compare
32
50
  */
33
51
  class WrCompare {
34
52
  /** Divider position as a percentage (0–100). Two-way bindable. @default 50 */
35
53
  position = model(50, /* @ts-ignore */
36
54
  ...(ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []));
55
+ /** Accessible name of the divider. Falls back to `compare.label`. */
56
+ ariaLabel = input(null, /* @ts-ignore */
57
+ ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
58
+ resolvedAriaLabel = useI18nText(this.ariaLabel, 'compare.label', 'Comparison divider');
37
59
  /**
38
60
  * Divider direction:
39
61
  * - `'horizontal'` — divider line is vertical, drags left/right.
@@ -50,7 +72,30 @@ class WrCompare {
50
72
  minPosition = input(0, { ...(ngDevMode ? { debugName: "minPosition" } : /* istanbul ignore next */ {}), transform: (v) => coerceNumberProperty(v, 0) });
51
73
  maxPosition = input(100, { ...(ngDevMode ? { debugName: "maxPosition" } : /* istanbul ignore next */ {}), transform: (v) => coerceNumberProperty(v, 100) });
52
74
  host = inject(ElementRef);
75
+ // Optional on purpose: `Directionality` is root-provided, so a consumer never has to
76
+ // supply it — and a bare `TestBed` does not either.
77
+ dir = inject(Directionality, { optional: true });
78
+ /**
79
+ * Reading direction as a signal, because unlike the splitter this component PAINTS
80
+ * from it: the clip and the divider offset are both direction-derived, and
81
+ * `Directionality.value` is an ordinary read. A `dir` flip at runtime would otherwise
82
+ * leave the wipe on the side the page no longer uses until some unrelated position
83
+ * change happened to recompute it.
84
+ */
85
+ rtl = signal(this.dir?.value === 'rtl', /* @ts-ignore */
86
+ ...(ngDevMode ? [{ debugName: "rtl" }] : /* istanbul ignore next */ []));
53
87
  dragging = false;
88
+ constructor() {
89
+ this.dir?.change.pipe(takeUntilDestroyed()).subscribe(value => this.rtl.set(value === 'rtl'));
90
+ // `position` is a `model`, so `[(position)]` and a restored layout write into it
91
+ // directly while only the handlers clamped — an out-of-range write reached the DOM
92
+ // as `aria-valuenow="150"` against a `valuemax` of 100.
93
+ effect(() => {
94
+ const clamped = clamp(this.position(), this.minPosition(), this.maxPosition());
95
+ if (clamped !== this.position())
96
+ this.position.set(clamped);
97
+ });
98
+ }
54
99
  classes = computed(() => {
55
100
  const parts = ['wr-compare', `wr-compare--${this.orientation()}`];
56
101
  if (this.disabled())
@@ -58,23 +103,46 @@ class WrCompare {
58
103
  return parts.join(' ');
59
104
  }, /* @ts-ignore */
60
105
  ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
61
- /** Clip path applied to the "after" layer so the divider reveals it. */
106
+ /**
107
+ * Clip path applied to the "after" layer so the divider reveals it.
108
+ *
109
+ * `inset()` takes PHYSICAL edges and has no logical form, so the mirroring is done
110
+ * here rather than in CSS: `position` counts from the inline-start edge, and under
111
+ * RTL that edge is the right one, so the after layer is clipped from the right by
112
+ * the same percentage.
113
+ */
62
114
  clipPath = computed(() => {
63
115
  const p = clamp(this.position(), 0, 100);
64
116
  if (this.orientation() === 'horizontal') {
65
- // Show from `p%` to the right edge.
66
- return `inset(0 0 0 ${p}%)`;
117
+ // Show from `p%` to the inline-end edge.
118
+ return this.rtl() ? `inset(0 ${p}% 0 0)` : `inset(0 0 0 ${p}%)`;
67
119
  }
120
+ // Block axis: `dir` does not touch it.
68
121
  return `inset(${p}% 0 0 0)`;
69
122
  }, /* @ts-ignore */
70
123
  ...(ngDevMode ? [{ debugName: "clipPath" }] : /* istanbul ignore next */ []));
124
+ /**
125
+ * Physical `left` percentage of the divider. Deliberately physical: it pairs with the
126
+ * `translateX(-50%)` that centres the 2px line on its own position, and the two have
127
+ * to agree on which edge they count from. `position` is logical, so RTL flips it here.
128
+ */
129
+ dividerLeft = computed(() => (this.rtl() ? 100 - this.position() : this.position()), /* @ts-ignore */
130
+ ...(ngDevMode ? [{ debugName: "dividerLeft" }] : /* istanbul ignore next */ []));
71
131
  // Pointer handlers
72
132
  onPointerDown(event) {
73
133
  if (this.disabled())
74
134
  return;
135
+ // Any pointerdown used to start a drag, so the right button moved the divider; the
136
+ // same guard keeps a second finger out of a drag already in progress.
137
+ if (event.button !== 0 || !event.isPrimary)
138
+ return;
75
139
  event.preventDefault();
76
140
  this.dragging = true;
77
- event.currentTarget.setPointerCapture(event.pointerId);
141
+ const surface = event.currentTarget;
142
+ surface.setPointerCapture(event.pointerId);
143
+ // `preventDefault` above also suppresses the click's default focus, so the arrows
144
+ // did nothing after a mouse drag until the divider was found again with Tab.
145
+ surface.focus();
78
146
  this.updateFromPointer(event);
79
147
  }
80
148
  onPointerMove(event) {
@@ -94,17 +162,23 @@ class WrCompare {
94
162
  const step = event.shiftKey ? 10 : 1;
95
163
  let next = null;
96
164
  if (this.orientation() === 'horizontal') {
165
+ // Arrows follow the VISUAL axis (WAI-ARIA APG). Under `dir="rtl"` the "before"
166
+ // side grows from the right, so the visual right is the low end of this slider's
167
+ // range and ArrowRight has to decrease the value.
168
+ const inline = this.rtl() ? -step : step;
97
169
  if (event.key === 'ArrowLeft')
98
- next = this.position() - step;
170
+ next = this.position() - inline;
99
171
  else if (event.key === 'ArrowRight')
100
- next = this.position() + step;
172
+ next = this.position() + inline;
101
173
  }
102
174
  else {
175
+ // Block axis: unaffected by `dir`.
103
176
  if (event.key === 'ArrowUp')
104
177
  next = this.position() - step;
105
178
  else if (event.key === 'ArrowDown')
106
179
  next = this.position() + step;
107
180
  }
181
+ // Home/End are semantic — first/last, not left/right — so they never mirror.
108
182
  if (event.key === 'Home')
109
183
  next = this.minPosition();
110
184
  else if (event.key === 'End')
@@ -116,18 +190,34 @@ class WrCompare {
116
190
  }
117
191
  updateFromPointer(event) {
118
192
  const rect = this.host.nativeElement.getBoundingClientRect();
119
- const raw = this.orientation() === 'horizontal'
120
- ? ((event.clientX - rect.left) / rect.width) * 100
121
- : ((event.clientY - rect.top) / rect.height) * 100;
193
+ const horizontal = this.orientation() === 'horizontal';
194
+ const extent = horizontal ? rect.width : rect.height;
195
+ // A host that has not been laid out — hidden, detached, or a pane the browser has
196
+ // throttled — measures 0, and dividing by it puts `Infinity` or `NaN` straight into
197
+ // `aria-valuenow`. There is no meaningful position to compute, so keep the current one.
198
+ if (extent <= 0)
199
+ return;
200
+ const raw = horizontal
201
+ ? this.inlineFraction(event.clientX, rect) * 100
202
+ : ((event.clientY - rect.top) / extent) * 100;
122
203
  this.position.set(clamp(raw, this.minPosition(), this.maxPosition()));
123
204
  }
124
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrCompare, deps: [], target: i0.ɵɵFactoryTarget.Component });
125
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: WrCompare, isStandalone: true, selector: "wr-compare", inputs: { position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, showHandle: { classPropertyName: "showHandle", publicName: "showHandle", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, minPosition: { classPropertyName: "minPosition", publicName: "minPosition", isSignal: true, isRequired: false, transformFunction: null }, maxPosition: { classPropertyName: "maxPosition", publicName: "maxPosition", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { position: "positionChange" }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: "<div\n class=\"wr-compare__surface\"\n role=\"slider\"\n aria-label=\"Comparison divider\"\n [attr.aria-orientation]=\"orientation()\"\n [attr.aria-valuemin]=\"minPosition()\"\n [attr.aria-valuemax]=\"maxPosition()\"\n [attr.aria-valuenow]=\"position()\"\n [attr.aria-disabled]=\"disabled() || null\"\n [attr.tabindex]=\"disabled() ? -1 : 0\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerUp($event)\"\n (keydown)=\"onKeydown($event)\"\n>\n <div class=\"wr-compare__layers\">\n <div class=\"wr-compare__layer wr-compare__layer--before\">\n <ng-content select=\"[wrCompareBefore]\" />\n </div>\n <div class=\"wr-compare__layer wr-compare__layer--after\" [style.clip-path]=\"clipPath()\">\n <ng-content select=\"[wrCompareAfter]\" />\n </div>\n </div>\n\n <div\n class=\"wr-compare__divider\"\n [style.left.%]=\"orientation() === 'horizontal' ? position() : null\"\n [style.top.%]=\"orientation() === 'vertical' ? position() : null\"\n aria-hidden=\"true\"\n >\n @if (showHandle()) {\n <span class=\"wr-compare__handle\">\n @if (orientation() === 'horizontal') {\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"M5 4 L1 8 L5 12 M11 4 L15 8 L11 12\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n } @else {\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"M4 5 L8 1 L12 5 M4 11 L8 15 L12 11\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n }\n </span>\n }\n </div>\n</div>\n", encapsulation: i0.ViewEncapsulation.None });
205
+ /**
206
+ * Fraction of the host measured from the INLINE-START edge — the left edge in LTR, the
207
+ * right edge in RTL, which is the side "before" is revealed from. Taken from
208
+ * `rect.left` in both, a drag under `dir="rtl"` read 0 at the visual maximum and moved
209
+ * the divider opposite the pointer.
210
+ */
211
+ inlineFraction(clientX, rect) {
212
+ return this.rtl() ? (rect.right - clientX) / rect.width : (clientX - rect.left) / rect.width;
213
+ }
214
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrCompare, deps: [], target: i0.ɵɵFactoryTarget.Component });
215
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: WrCompare, isStandalone: true, selector: "wr-compare", inputs: { position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, showHandle: { classPropertyName: "showHandle", publicName: "showHandle", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, minPosition: { classPropertyName: "minPosition", publicName: "minPosition", isSignal: true, isRequired: false, transformFunction: null }, maxPosition: { classPropertyName: "maxPosition", publicName: "maxPosition", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { position: "positionChange" }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: "<div\n class=\"wr-compare__surface\"\n role=\"slider\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n [attr.aria-orientation]=\"orientation()\"\n [attr.aria-valuemin]=\"minPosition()\"\n [attr.aria-valuemax]=\"maxPosition()\"\n [attr.aria-valuenow]=\"position()\"\n [attr.aria-disabled]=\"disabled() || null\"\n [attr.tabindex]=\"disabled() ? -1 : 0\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerUp($event)\"\n (keydown)=\"onKeydown($event)\"\n>\n <div class=\"wr-compare__layers\">\n <div class=\"wr-compare__layer wr-compare__layer--before\">\n <ng-content select=\"[wrCompareBefore]\" />\n </div>\n <div class=\"wr-compare__layer wr-compare__layer--after\" [style.clip-path]=\"clipPath()\">\n <ng-content select=\"[wrCompareAfter]\" />\n </div>\n </div>\n\n <div\n class=\"wr-compare__divider\"\n [style.left.%]=\"orientation() === 'horizontal' ? dividerLeft() : null\"\n [style.top.%]=\"orientation() === 'vertical' ? position() : null\"\n aria-hidden=\"true\"\n >\n @if (showHandle()) {\n <span class=\"wr-compare__handle\">\n @if (orientation() === 'horizontal') {\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"M5 4 L1 8 L5 12 M11 4 L15 8 L11 12\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n } @else {\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"M4 5 L8 1 L12 5 M4 11 L8 15 L12 11\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n }\n </span>\n }\n </div>\n</div>\n", encapsulation: i0.ViewEncapsulation.None });
126
216
  }
127
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrCompare, decorators: [{
217
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrCompare, decorators: [{
128
218
  type: Component,
129
- args: [{ selector: 'wr-compare', encapsulation: ViewEncapsulation.None, host: { '[class]': 'classes()' }, template: "<div\n class=\"wr-compare__surface\"\n role=\"slider\"\n aria-label=\"Comparison divider\"\n [attr.aria-orientation]=\"orientation()\"\n [attr.aria-valuemin]=\"minPosition()\"\n [attr.aria-valuemax]=\"maxPosition()\"\n [attr.aria-valuenow]=\"position()\"\n [attr.aria-disabled]=\"disabled() || null\"\n [attr.tabindex]=\"disabled() ? -1 : 0\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerUp($event)\"\n (keydown)=\"onKeydown($event)\"\n>\n <div class=\"wr-compare__layers\">\n <div class=\"wr-compare__layer wr-compare__layer--before\">\n <ng-content select=\"[wrCompareBefore]\" />\n </div>\n <div class=\"wr-compare__layer wr-compare__layer--after\" [style.clip-path]=\"clipPath()\">\n <ng-content select=\"[wrCompareAfter]\" />\n </div>\n </div>\n\n <div\n class=\"wr-compare__divider\"\n [style.left.%]=\"orientation() === 'horizontal' ? position() : null\"\n [style.top.%]=\"orientation() === 'vertical' ? position() : null\"\n aria-hidden=\"true\"\n >\n @if (showHandle()) {\n <span class=\"wr-compare__handle\">\n @if (orientation() === 'horizontal') {\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"M5 4 L1 8 L5 12 M11 4 L15 8 L11 12\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n } @else {\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"M4 5 L8 1 L12 5 M4 11 L8 15 L12 11\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n }\n </span>\n }\n </div>\n</div>\n" }]
130
- }], propDecorators: { position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }, { type: i0.Output, args: ["positionChange"] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], showHandle: [{ type: i0.Input, args: [{ isSignal: true, alias: "showHandle", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], minPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "minPosition", required: false }] }], maxPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxPosition", required: false }] }] } });
219
+ args: [{ selector: 'wr-compare', encapsulation: ViewEncapsulation.None, host: { '[class]': 'classes()' }, template: "<div\n class=\"wr-compare__surface\"\n role=\"slider\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n [attr.aria-orientation]=\"orientation()\"\n [attr.aria-valuemin]=\"minPosition()\"\n [attr.aria-valuemax]=\"maxPosition()\"\n [attr.aria-valuenow]=\"position()\"\n [attr.aria-disabled]=\"disabled() || null\"\n [attr.tabindex]=\"disabled() ? -1 : 0\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerUp($event)\"\n (keydown)=\"onKeydown($event)\"\n>\n <div class=\"wr-compare__layers\">\n <div class=\"wr-compare__layer wr-compare__layer--before\">\n <ng-content select=\"[wrCompareBefore]\" />\n </div>\n <div class=\"wr-compare__layer wr-compare__layer--after\" [style.clip-path]=\"clipPath()\">\n <ng-content select=\"[wrCompareAfter]\" />\n </div>\n </div>\n\n <div\n class=\"wr-compare__divider\"\n [style.left.%]=\"orientation() === 'horizontal' ? dividerLeft() : null\"\n [style.top.%]=\"orientation() === 'vertical' ? position() : null\"\n aria-hidden=\"true\"\n >\n @if (showHandle()) {\n <span class=\"wr-compare__handle\">\n @if (orientation() === 'horizontal') {\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"M5 4 L1 8 L5 12 M11 4 L15 8 L11 12\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n } @else {\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"M4 5 L8 1 L12 5 M4 11 L8 15 L12 11\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n }\n </span>\n }\n </div>\n</div>\n" }]
220
+ }], ctorParameters: () => [], propDecorators: { position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }, { type: i0.Output, args: ["positionChange"] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], showHandle: [{ type: i0.Input, args: [{ isSignal: true, alias: "showHandle", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], minPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "minPosition", required: false }] }], maxPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxPosition", required: false }] }] } });
131
221
 
132
222
  /**
133
223
  * Generated bundle index. Do not edit.
@@ -1 +1 @@
1
- {"version":3,"file":"ngwr-compare.mjs","sources":["../../../projects/lib/compare/compare.ts","../../../projects/lib/compare/compare.html","../../../projects/lib/compare/ngwr-compare.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';\nimport { Component, ElementRef, ViewEncapsulation, computed, inject, input, model } from '@angular/core';\n\nimport { clamp } from 'ngwr/utils';\n\n/**\n * Before/after comparison slider. Works with any content — project two\n * pieces of markup with `wrCompareBefore` and `wrCompareAfter` attributes;\n * the component stacks them in the same cell and clips the \"after\" side\n * with a draggable divider.\n *\n * @example\n * ```html\n * <wr-compare [(position)]=\"pos\">\n * <img wrCompareBefore src=\"before.jpg\" alt=\"\" />\n * <img wrCompareAfter src=\"after.jpg\" alt=\"\" />\n * </wr-compare>\n *\n * <wr-compare orientation=\"vertical\">\n * <pre wrCompareBefore>{{ oldCode }}</pre>\n * <pre wrCompareAfter>{{ newCode }}</pre>\n * </wr-compare>\n * ```\n *\n * @see https://ngwr.dev/reference/components/compare\n */\n@Component({\n selector: 'wr-compare',\n templateUrl: './compare.html',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n})\nexport class WrCompare {\n /** Divider position as a percentage (0–100). Two-way bindable. @default 50 */\n readonly position = model(50);\n\n /**\n * Divider direction:\n * - `'horizontal'` — divider line is vertical, drags left/right.\n * - `'vertical'` — divider line is horizontal, drags up/down.\n * @default 'horizontal'\n */\n readonly orientation = input<'horizontal' | 'vertical'>('horizontal');\n\n /** Show the round drag handle on the divider. @default true */\n readonly showHandle = input(true, { transform: coerceBooleanProperty });\n\n /** Disable interaction (divider stays put). @default false */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n /** Initial position transform — accepts any number / numeric string. */\n readonly minPosition = input(0, { transform: (v: unknown): number => coerceNumberProperty(v, 0) });\n readonly maxPosition = input(100, { transform: (v: unknown): number => coerceNumberProperty(v, 100) });\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private dragging = false;\n\n protected readonly classes = computed(() => {\n const parts = ['wr-compare', `wr-compare--${this.orientation()}`];\n if (this.disabled()) parts.push('wr-compare--disabled');\n return parts.join(' ');\n });\n\n /** Clip path applied to the \"after\" layer so the divider reveals it. */\n protected readonly clipPath = computed(() => {\n const p = clamp(this.position(), 0, 100);\n if (this.orientation() === 'horizontal') {\n // Show from `p%` to the right edge.\n return `inset(0 0 0 ${p}%)`;\n }\n return `inset(${p}% 0 0 0)`;\n });\n\n // Pointer handlers\n\n protected onPointerDown(event: PointerEvent): void {\n if (this.disabled()) return;\n event.preventDefault();\n this.dragging = true;\n (event.currentTarget as HTMLElement).setPointerCapture(event.pointerId);\n this.updateFromPointer(event);\n }\n\n protected onPointerMove(event: PointerEvent): void {\n if (!this.dragging) return;\n this.updateFromPointer(event);\n }\n\n protected onPointerUp(event: PointerEvent): void {\n if (!this.dragging) return;\n this.dragging = false;\n (event.currentTarget as HTMLElement).releasePointerCapture(event.pointerId);\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n if (this.disabled()) return;\n const step = event.shiftKey ? 10 : 1;\n let next: number | null = null;\n if (this.orientation() === 'horizontal') {\n if (event.key === 'ArrowLeft') next = this.position() - step;\n else if (event.key === 'ArrowRight') next = this.position() + step;\n } else {\n if (event.key === 'ArrowUp') next = this.position() - step;\n else if (event.key === 'ArrowDown') next = this.position() + step;\n }\n if (event.key === 'Home') next = this.minPosition();\n else if (event.key === 'End') next = this.maxPosition();\n if (next === null) return;\n event.preventDefault();\n this.position.set(clamp(next, this.minPosition(), this.maxPosition()));\n }\n\n private updateFromPointer(event: PointerEvent): void {\n const rect = this.host.nativeElement.getBoundingClientRect();\n const raw =\n this.orientation() === 'horizontal'\n ? ((event.clientX - rect.left) / rect.width) * 100\n : ((event.clientY - rect.top) / rect.height) * 100;\n this.position.set(clamp(raw, this.minPosition(), this.maxPosition()));\n }\n}\n","<div\n class=\"wr-compare__surface\"\n role=\"slider\"\n aria-label=\"Comparison divider\"\n [attr.aria-orientation]=\"orientation()\"\n [attr.aria-valuemin]=\"minPosition()\"\n [attr.aria-valuemax]=\"maxPosition()\"\n [attr.aria-valuenow]=\"position()\"\n [attr.aria-disabled]=\"disabled() || null\"\n [attr.tabindex]=\"disabled() ? -1 : 0\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerUp($event)\"\n (keydown)=\"onKeydown($event)\"\n>\n <div class=\"wr-compare__layers\">\n <div class=\"wr-compare__layer wr-compare__layer--before\">\n <ng-content select=\"[wrCompareBefore]\" />\n </div>\n <div class=\"wr-compare__layer wr-compare__layer--after\" [style.clip-path]=\"clipPath()\">\n <ng-content select=\"[wrCompareAfter]\" />\n </div>\n </div>\n\n <div\n class=\"wr-compare__divider\"\n [style.left.%]=\"orientation() === 'horizontal' ? position() : null\"\n [style.top.%]=\"orientation() === 'vertical' ? position() : null\"\n aria-hidden=\"true\"\n >\n @if (showHandle()) {\n <span class=\"wr-compare__handle\">\n @if (orientation() === 'horizontal') {\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"M5 4 L1 8 L5 12 M11 4 L15 8 L11 12\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n } @else {\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"M4 5 L8 1 L12 5 M4 11 L8 15 L12 11\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n }\n </span>\n }\n </div>\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;AAAA;;;;;AAKG;AAOH;;;;;;;;;;;;;;;;;;;;AAoBG;MAOU,SAAS,CAAA;;IAEX,QAAQ,GAAG,KAAK,CAAC,EAAE;iFAAC;AAE7B;;;;;AAKG;IACM,WAAW,GAAG,KAAK,CAA4B,YAAY;oFAAC;;IAG5D,UAAU,GAAG,KAAK,CAAC,IAAI,kFAAI,SAAS,EAAE,qBAAqB,EAAA,CAAG;;IAG9D,QAAQ,GAAG,KAAK,CAAC,KAAK,gFAAI,SAAS,EAAE,qBAAqB,EAAA,CAAG;;AAG7D,IAAA,WAAW,GAAG,KAAK,CAAC,CAAC,EAAA,EAAA,IAAA,SAAA,GAAA,EAAA,SAAA,EAAA,aAAA,EAAA,8BAAA,EAAA,CAAA,EAAI,SAAS,EAAE,CAAC,CAAU,KAAa,oBAAoB,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;AACzF,IAAA,WAAW,GAAG,KAAK,CAAC,GAAG,EAAA,EAAA,IAAA,SAAA,GAAA,EAAA,SAAA,EAAA,aAAA,EAAA,8BAAA,EAAA,CAAA,EAAI,SAAS,EAAE,CAAC,CAAU,KAAa,oBAAoB,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG;AAErF,IAAA,IAAI,GAAG,MAAM,CAA0B,UAAU,CAAC;IAC3D,QAAQ,GAAG,KAAK;AAEL,IAAA,OAAO,GAAG,QAAQ,CAAC,MAAK;AACzC,QAAA,MAAM,KAAK,GAAG,CAAC,YAAY,EAAE,CAAA,YAAA,EAAe,IAAI,CAAC,WAAW,EAAE,CAAA,CAAE,CAAC;QACjE,IAAI,IAAI,CAAC,QAAQ,EAAE;AAAE,YAAA,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC;AACvD,QAAA,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;IACxB,CAAC;gFAAC;;AAGiB,IAAA,QAAQ,GAAG,QAAQ,CAAC,MAAK;AAC1C,QAAA,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC;AACxC,QAAA,IAAI,IAAI,CAAC,WAAW,EAAE,KAAK,YAAY,EAAE;;YAEvC,OAAO,CAAA,YAAA,EAAe,CAAC,CAAA,EAAA,CAAI;QAC7B;QACA,OAAO,CAAA,MAAA,EAAS,CAAC,CAAA,QAAA,CAAU;IAC7B,CAAC;iFAAC;;AAIQ,IAAA,aAAa,CAAC,KAAmB,EAAA;QACzC,IAAI,IAAI,CAAC,QAAQ,EAAE;YAAE;QACrB,KAAK,CAAC,cAAc,EAAE;AACtB,QAAA,IAAI,CAAC,QAAQ,GAAG,IAAI;QACnB,KAAK,CAAC,aAA6B,CAAC,iBAAiB,CAAC,KAAK,CAAC,SAAS,CAAC;AACvE,QAAA,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC;IAC/B;AAEU,IAAA,aAAa,CAAC,KAAmB,EAAA;QACzC,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE;AACpB,QAAA,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC;IAC/B;AAEU,IAAA,WAAW,CAAC,KAAmB,EAAA;QACvC,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE;AACpB,QAAA,IAAI,CAAC,QAAQ,GAAG,KAAK;QACpB,KAAK,CAAC,aAA6B,CAAC,qBAAqB,CAAC,KAAK,CAAC,SAAS,CAAC;IAC7E;AAEU,IAAA,SAAS,CAAC,KAAoB,EAAA;QACtC,IAAI,IAAI,CAAC,QAAQ,EAAE;YAAE;AACrB,QAAA,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,GAAG,EAAE,GAAG,CAAC;QACpC,IAAI,IAAI,GAAkB,IAAI;AAC9B,QAAA,IAAI,IAAI,CAAC,WAAW,EAAE,KAAK,YAAY,EAAE;AACvC,YAAA,IAAI,KAAK,CAAC,GAAG,KAAK,WAAW;AAAE,gBAAA,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI;AACvD,iBAAA,IAAI,KAAK,CAAC,GAAG,KAAK,YAAY;AAAE,gBAAA,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI;QACpE;aAAO;AACL,YAAA,IAAI,KAAK,CAAC,GAAG,KAAK,SAAS;AAAE,gBAAA,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI;AACrD,iBAAA,IAAI,KAAK,CAAC,GAAG,KAAK,WAAW;AAAE,gBAAA,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI;QACnE;AACA,QAAA,IAAI,KAAK,CAAC,GAAG,KAAK,MAAM;AAAE,YAAA,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE;AAC9C,aAAA,IAAI,KAAK,CAAC,GAAG,KAAK,KAAK;AAAE,YAAA,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE;QACvD,IAAI,IAAI,KAAK,IAAI;YAAE;QACnB,KAAK,CAAC,cAAc,EAAE;QACtB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IACxE;AAEQ,IAAA,iBAAiB,CAAC,KAAmB,EAAA;QAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,qBAAqB,EAAE;AAC5D,QAAA,MAAM,GAAG,GACP,IAAI,CAAC,WAAW,EAAE,KAAK;AACrB,cAAE,CAAC,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,IAAI;AAC/C,cAAE,CAAC,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,MAAM,IAAI,GAAG;QACtD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,WAAW,EAAE,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IACvE;uGAvFW,SAAS,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAT,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,SAAS,k9BCvCtB,ohEA4DA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;2FDrBa,SAAS,EAAA,UAAA,EAAA,CAAA;kBANrB,SAAS;+BACE,YAAY,EAAA,aAAA,EAEP,iBAAiB,CAAC,IAAI,QAC/B,EAAE,SAAS,EAAE,WAAW,EAAE,EAAA,QAAA,EAAA,ohEAAA,EAAA;;;AErClC;;AAEG;;;;"}
1
+ {"version":3,"file":"ngwr-compare.mjs","sources":["../../../projects/lib/compare/compare.ts","../../../projects/lib/compare/compare.html","../../../projects/lib/compare/ngwr-compare.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Directionality } from '@angular/cdk/bidi';\nimport { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';\nimport {\n Component,\n ElementRef,\n ViewEncapsulation,\n computed,\n effect,\n inject,\n input,\n model,\n signal,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { useI18nText } from 'ngwr/i18n';\nimport { clamp } from 'ngwr/utils';\n\n/**\n * Before/after comparison slider. Works with any content — project two\n * pieces of markup with `wrCompareBefore` and `wrCompareAfter` attributes;\n * the component stacks them in the same cell and clips the \"after\" side\n * with a draggable divider.\n *\n * @example\n * ```html\n * <wr-compare [(position)]=\"pos\">\n * <img wrCompareBefore src=\"before.jpg\" alt=\"\" />\n * <img wrCompareAfter src=\"after.jpg\" alt=\"\" />\n * </wr-compare>\n *\n * <wr-compare orientation=\"vertical\">\n * <pre wrCompareBefore>{{ oldCode }}</pre>\n * <pre wrCompareAfter>{{ newCode }}</pre>\n * </wr-compare>\n * ```\n *\n * Under `dir=\"rtl\"` the horizontal wipe MIRRORS: \"before\" occupies the inline-start\n * side, which is the right. Before/after is an ordinal pair — the two ends of a\n * progression — and ordinal progressions follow reading order, the same reason a\n * progress bar fills from the right in Arabic. The LTR habit of putting \"before\" on\n * the left IS reading order, so mirroring preserves that intent rather than breaking\n * it. Nothing is flipped pixel-wise: both layers are the images the consumer passed,\n * unscaled and unmirrored — only the side each is revealed on changes.\n *\n * Pinning the physical arrangement inside an RTL page takes the CDK's `Dir` directive\n * (`[dir]`, from `@angular/cdk/bidi`) on a wrapper, because that is what provides a\n * scoped `Directionality`. A bare `dir=\"ltr\"` attribute does NOT do it: the ambient\n * `Directionality` reads `<html>` / `<body>` once at startup and never looks at the\n * element, and this component's horizontal wipe is painted entirely from TypeScript,\n * so the attribute would change nothing at all while looking like an opt-out.\n *\n * @see https://ngwr.dev/reference/components/compare\n */\n@Component({\n selector: 'wr-compare',\n templateUrl: './compare.html',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n})\nexport class WrCompare {\n /** Divider position as a percentage (0–100). Two-way bindable. @default 50 */\n readonly position = model(50);\n\n /** Accessible name of the divider. Falls back to `compare.label`. */\n readonly ariaLabel = input<string | null>(null);\n\n protected readonly resolvedAriaLabel = useI18nText(this.ariaLabel, 'compare.label', 'Comparison divider');\n\n /**\n * Divider direction:\n * - `'horizontal'` — divider line is vertical, drags left/right.\n * - `'vertical'` — divider line is horizontal, drags up/down.\n * @default 'horizontal'\n */\n readonly orientation = input<'horizontal' | 'vertical'>('horizontal');\n\n /** Show the round drag handle on the divider. @default true */\n readonly showHandle = input(true, { transform: coerceBooleanProperty });\n\n /** Disable interaction (divider stays put). @default false */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n /** Initial position transform — accepts any number / numeric string. */\n readonly minPosition = input(0, { transform: (v: unknown): number => coerceNumberProperty(v, 0) });\n readonly maxPosition = input(100, { transform: (v: unknown): number => coerceNumberProperty(v, 100) });\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n // Optional on purpose: `Directionality` is root-provided, so a consumer never has to\n // supply it — and a bare `TestBed` does not either.\n private readonly dir = inject(Directionality, { optional: true });\n\n /**\n * Reading direction as a signal, because unlike the splitter this component PAINTS\n * from it: the clip and the divider offset are both direction-derived, and\n * `Directionality.value` is an ordinary read. A `dir` flip at runtime would otherwise\n * leave the wipe on the side the page no longer uses until some unrelated position\n * change happened to recompute it.\n */\n private readonly rtl = signal(this.dir?.value === 'rtl');\n\n private dragging = false;\n\n constructor() {\n this.dir?.change.pipe(takeUntilDestroyed()).subscribe(value => this.rtl.set(value === 'rtl'));\n\n // `position` is a `model`, so `[(position)]` and a restored layout write into it\n // directly while only the handlers clamped — an out-of-range write reached the DOM\n // as `aria-valuenow=\"150\"` against a `valuemax` of 100.\n effect(() => {\n const clamped = clamp(this.position(), this.minPosition(), this.maxPosition());\n if (clamped !== this.position()) this.position.set(clamped);\n });\n }\n\n protected readonly classes = computed(() => {\n const parts = ['wr-compare', `wr-compare--${this.orientation()}`];\n if (this.disabled()) parts.push('wr-compare--disabled');\n return parts.join(' ');\n });\n\n /**\n * Clip path applied to the \"after\" layer so the divider reveals it.\n *\n * `inset()` takes PHYSICAL edges and has no logical form, so the mirroring is done\n * here rather than in CSS: `position` counts from the inline-start edge, and under\n * RTL that edge is the right one, so the after layer is clipped from the right by\n * the same percentage.\n */\n protected readonly clipPath = computed(() => {\n const p = clamp(this.position(), 0, 100);\n if (this.orientation() === 'horizontal') {\n // Show from `p%` to the inline-end edge.\n return this.rtl() ? `inset(0 ${p}% 0 0)` : `inset(0 0 0 ${p}%)`;\n }\n // Block axis: `dir` does not touch it.\n return `inset(${p}% 0 0 0)`;\n });\n\n /**\n * Physical `left` percentage of the divider. Deliberately physical: it pairs with the\n * `translateX(-50%)` that centres the 2px line on its own position, and the two have\n * to agree on which edge they count from. `position` is logical, so RTL flips it here.\n */\n protected readonly dividerLeft = computed(() => (this.rtl() ? 100 - this.position() : this.position()));\n\n // Pointer handlers\n\n protected onPointerDown(event: PointerEvent): void {\n if (this.disabled()) return;\n // Any pointerdown used to start a drag, so the right button moved the divider; the\n // same guard keeps a second finger out of a drag already in progress.\n if (event.button !== 0 || !event.isPrimary) return;\n event.preventDefault();\n this.dragging = true;\n const surface = event.currentTarget as HTMLElement;\n surface.setPointerCapture(event.pointerId);\n // `preventDefault` above also suppresses the click's default focus, so the arrows\n // did nothing after a mouse drag until the divider was found again with Tab.\n surface.focus();\n this.updateFromPointer(event);\n }\n\n protected onPointerMove(event: PointerEvent): void {\n if (!this.dragging) return;\n this.updateFromPointer(event);\n }\n\n protected onPointerUp(event: PointerEvent): void {\n if (!this.dragging) return;\n this.dragging = false;\n (event.currentTarget as HTMLElement).releasePointerCapture(event.pointerId);\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n if (this.disabled()) return;\n const step = event.shiftKey ? 10 : 1;\n let next: number | null = null;\n if (this.orientation() === 'horizontal') {\n // Arrows follow the VISUAL axis (WAI-ARIA APG). Under `dir=\"rtl\"` the \"before\"\n // side grows from the right, so the visual right is the low end of this slider's\n // range and ArrowRight has to decrease the value.\n const inline = this.rtl() ? -step : step;\n if (event.key === 'ArrowLeft') next = this.position() - inline;\n else if (event.key === 'ArrowRight') next = this.position() + inline;\n } else {\n // Block axis: unaffected by `dir`.\n if (event.key === 'ArrowUp') next = this.position() - step;\n else if (event.key === 'ArrowDown') next = this.position() + step;\n }\n // Home/End are semantic — first/last, not left/right — so they never mirror.\n if (event.key === 'Home') next = this.minPosition();\n else if (event.key === 'End') next = this.maxPosition();\n if (next === null) return;\n event.preventDefault();\n this.position.set(clamp(next, this.minPosition(), this.maxPosition()));\n }\n\n private updateFromPointer(event: PointerEvent): void {\n const rect = this.host.nativeElement.getBoundingClientRect();\n const horizontal = this.orientation() === 'horizontal';\n const extent = horizontal ? rect.width : rect.height;\n // A host that has not been laid out — hidden, detached, or a pane the browser has\n // throttled — measures 0, and dividing by it puts `Infinity` or `NaN` straight into\n // `aria-valuenow`. There is no meaningful position to compute, so keep the current one.\n if (extent <= 0) return;\n const raw = horizontal\n ? this.inlineFraction(event.clientX, rect) * 100\n : ((event.clientY - rect.top) / extent) * 100;\n this.position.set(clamp(raw, this.minPosition(), this.maxPosition()));\n }\n\n /**\n * Fraction of the host measured from the INLINE-START edge — the left edge in LTR, the\n * right edge in RTL, which is the side \"before\" is revealed from. Taken from\n * `rect.left` in both, a drag under `dir=\"rtl\"` read 0 at the visual maximum and moved\n * the divider opposite the pointer.\n */\n private inlineFraction(clientX: number, rect: DOMRect): number {\n return this.rtl() ? (rect.right - clientX) / rect.width : (clientX - rect.left) / rect.width;\n }\n}\n","<div\n class=\"wr-compare__surface\"\n role=\"slider\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n [attr.aria-orientation]=\"orientation()\"\n [attr.aria-valuemin]=\"minPosition()\"\n [attr.aria-valuemax]=\"maxPosition()\"\n [attr.aria-valuenow]=\"position()\"\n [attr.aria-disabled]=\"disabled() || null\"\n [attr.tabindex]=\"disabled() ? -1 : 0\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerUp($event)\"\n (keydown)=\"onKeydown($event)\"\n>\n <div class=\"wr-compare__layers\">\n <div class=\"wr-compare__layer wr-compare__layer--before\">\n <ng-content select=\"[wrCompareBefore]\" />\n </div>\n <div class=\"wr-compare__layer wr-compare__layer--after\" [style.clip-path]=\"clipPath()\">\n <ng-content select=\"[wrCompareAfter]\" />\n </div>\n </div>\n\n <div\n class=\"wr-compare__divider\"\n [style.left.%]=\"orientation() === 'horizontal' ? dividerLeft() : null\"\n [style.top.%]=\"orientation() === 'vertical' ? position() : null\"\n aria-hidden=\"true\"\n >\n @if (showHandle()) {\n <span class=\"wr-compare__handle\">\n @if (orientation() === 'horizontal') {\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"M5 4 L1 8 L5 12 M11 4 L15 8 L11 12\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n } @else {\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path\n d=\"M4 5 L8 1 L12 5 M4 11 L8 15 L12 11\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n }\n </span>\n }\n </div>\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -145,10 +145,10 @@ class WrConfetti {
145
145
  this.rafId = null;
146
146
  }
147
147
  }
148
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrConfetti, deps: [], target: i0.ɵɵFactoryTarget.Service });
149
- static ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.0", ngImport: i0, type: WrConfetti });
148
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrConfetti, deps: [], target: i0.ɵɵFactoryTarget.Service });
149
+ static ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.1", ngImport: i0, type: WrConfetti });
150
150
  }
151
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrConfetti, decorators: [{
151
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrConfetti, decorators: [{
152
152
  type: Service
153
153
  }] });
154
154
 
@@ -0,0 +1,106 @@
1
+ import { InjectionToken, makeEnvironmentProviders, inject, computed } from '@angular/core';
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
+ /**
10
+ * App-wide component defaults, or `{}` when the app never called
11
+ * `provideWrConfig()`.
12
+ *
13
+ * A factory default rather than an optional inject at every call site: a
14
+ * component asking for its own default should not have to care whether anyone
15
+ * configured anything, and `{}` reads the same as absent through
16
+ * {@link useConfigValue}.
17
+ */
18
+ const WR_CONFIG = new InjectionToken('WR_CONFIG', {
19
+ providedIn: 'root',
20
+ factory: () => ({}),
21
+ });
22
+
23
+ /**
24
+ * @license
25
+ *
26
+ * Use of this source code is governed by an MIT-style license that can be
27
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
28
+ */
29
+ /**
30
+ * Set app-wide component defaults.
31
+ *
32
+ * Nothing is activated by this and no service is constructed — unlike
33
+ * `provideWrDensity()`, which has to instantiate its service to write an
34
+ * attribute onto `<html>`. A config is read on demand by whichever component
35
+ * wants a default, so providing it costs one token.
36
+ *
37
+ * @example
38
+ * ```ts
39
+ * bootstrapApplication(App, {
40
+ * providers: [provideWrConfig({ button: { size: 'sm' }, select: { rounded: true } })],
41
+ * });
42
+ * ```
43
+ *
44
+ * Scoped use works the same way: put it in a route's `providers` and only that
45
+ * branch of the tree sees it, because the components resolve the token through
46
+ * their own injector.
47
+ *
48
+ * @see https://ngwr.dev/start/configuration
49
+ */
50
+ function provideWrConfig(config) {
51
+ return makeEnvironmentProviders([{ provide: WR_CONFIG, useValue: config }]);
52
+ }
53
+
54
+ /**
55
+ * @license
56
+ *
57
+ * Use of this source code is governed by an MIT-style license that can be
58
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
59
+ */
60
+ /**
61
+ * Resolve an input against the app's {@link WrConfig}, then a built-in fallback.
62
+ *
63
+ * The same shape as `useI18nText` from `ngwr/i18n`, and for the same reason: a
64
+ * component's default has three possible sources and exactly one precedence
65
+ * order, so it is worth writing once.
66
+ *
67
+ * 1. What the template bound, if it bound anything.
68
+ * 2. What `provideWrConfig()` set for this component.
69
+ * 3. The component's own fallback.
70
+ *
71
+ * A bound value always wins. That is what keeps a global config from becoming
72
+ * something templates have to escape — the mistake NG-ZORRO's `NzConfigService`
73
+ * is remembered for.
74
+ *
75
+ * Call it from a field initializer (it injects), and give the input `null` as its
76
+ * own default so "not set" is expressible:
77
+ *
78
+ * ```ts
79
+ * readonly size = input<WrButtonSize | null>(null);
80
+ * protected readonly resolvedSize = useConfigValue(this.size, c => c.button?.size, 'md');
81
+ * ```
82
+ *
83
+ * The generic is the COMPONENT's type, not the config's, so a component whose
84
+ * size scale is narrower than {@link WrControlSize} stops compiling here rather
85
+ * than accepting a value it cannot render — the type checker doing the work a
86
+ * parity script would otherwise have to.
87
+ */
88
+ function useConfigValue(binding, pick, fallback) {
89
+ const config = inject(WR_CONFIG);
90
+ return computed(() => {
91
+ const bound = binding();
92
+ // `null` and `undefined` both mean "the template did not say". `false` and
93
+ // `0` do not, which is why this is not `??` on a falsy check — a
94
+ // `[rounded]="false"` has to be able to turn a configured `true` back off.
95
+ if (bound !== null && bound !== undefined)
96
+ return bound;
97
+ return pick(config) ?? fallback;
98
+ });
99
+ }
100
+
101
+ /**
102
+ * Generated bundle index. Do not edit.
103
+ */
104
+
105
+ export { WR_CONFIG, provideWrConfig, useConfigValue };
106
+ //# sourceMappingURL=ngwr-config.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ngwr-config.mjs","sources":["../../../projects/lib/config/tokens.ts","../../../projects/lib/config/provide-wr-config.ts","../../../projects/lib/config/util.ts","../../../projects/lib/config/ngwr-config.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { InjectionToken } from '@angular/core';\n\nimport type { WrConfig } from './interfaces';\n\n/**\n * App-wide component defaults, or `{}` when the app never called\n * `provideWrConfig()`.\n *\n * A factory default rather than an optional inject at every call site: a\n * component asking for its own default should not have to care whether anyone\n * configured anything, and `{}` reads the same as absent through\n * {@link useConfigValue}.\n */\nexport const WR_CONFIG = new InjectionToken<WrConfig>('WR_CONFIG', {\n providedIn: 'root',\n factory: (): WrConfig => ({}),\n});\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { type EnvironmentProviders, makeEnvironmentProviders } from '@angular/core';\n\nimport type { WrConfig } from './interfaces';\nimport { WR_CONFIG } from './tokens';\n\n/**\n * Set app-wide component defaults.\n *\n * Nothing is activated by this and no service is constructed — unlike\n * `provideWrDensity()`, which has to instantiate its service to write an\n * attribute onto `<html>`. A config is read on demand by whichever component\n * wants a default, so providing it costs one token.\n *\n * @example\n * ```ts\n * bootstrapApplication(App, {\n * providers: [provideWrConfig({ button: { size: 'sm' }, select: { rounded: true } })],\n * });\n * ```\n *\n * Scoped use works the same way: put it in a route's `providers` and only that\n * branch of the tree sees it, because the components resolve the token through\n * their own injector.\n *\n * @see https://ngwr.dev/start/configuration\n */\nexport function provideWrConfig(config: WrConfig): EnvironmentProviders {\n return makeEnvironmentProviders([{ provide: WR_CONFIG, useValue: config }]);\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { type Signal, computed, inject } from '@angular/core';\n\nimport type { WrConfig } from './interfaces';\nimport { WR_CONFIG } from './tokens';\n\n/**\n * Resolve an input against the app's {@link WrConfig}, then a built-in fallback.\n *\n * The same shape as `useI18nText` from `ngwr/i18n`, and for the same reason: a\n * component's default has three possible sources and exactly one precedence\n * order, so it is worth writing once.\n *\n * 1. What the template bound, if it bound anything.\n * 2. What `provideWrConfig()` set for this component.\n * 3. The component's own fallback.\n *\n * A bound value always wins. That is what keeps a global config from becoming\n * something templates have to escape — the mistake NG-ZORRO's `NzConfigService`\n * is remembered for.\n *\n * Call it from a field initializer (it injects), and give the input `null` as its\n * own default so \"not set\" is expressible:\n *\n * ```ts\n * readonly size = input<WrButtonSize | null>(null);\n * protected readonly resolvedSize = useConfigValue(this.size, c => c.button?.size, 'md');\n * ```\n *\n * The generic is the COMPONENT's type, not the config's, so a component whose\n * size scale is narrower than {@link WrControlSize} stops compiling here rather\n * than accepting a value it cannot render — the type checker doing the work a\n * parity script would otherwise have to.\n */\nexport function useConfigValue<T>(\n binding: Signal<T | null | undefined>,\n pick: (config: WrConfig) => T | undefined,\n fallback: T\n): Signal<T> {\n const config = inject(WR_CONFIG);\n\n return computed(() => {\n const bound = binding();\n // `null` and `undefined` both mean \"the template did not say\". `false` and\n // `0` do not, which is why this is not `??` on a falsy check — a\n // `[rounded]=\"false\"` has to be able to turn a configured `true` back off.\n if (bound !== null && bound !== undefined) return bound;\n\n return pick(config) ?? fallback;\n });\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;AAAA;;;;;AAKG;AAMH;;;;;;;;AAQG;MACU,SAAS,GAAG,IAAI,cAAc,CAAW,WAAW,EAAE;AACjE,IAAA,UAAU,EAAE,MAAM;AAClB,IAAA,OAAO,EAAE,OAAiB,EAAE,CAAC;AAC9B,CAAA;;ACvBD;;;;;AAKG;AAOH;;;;;;;;;;;;;;;;;;;;AAoBG;AACG,SAAU,eAAe,CAAC,MAAgB,EAAA;AAC9C,IAAA,OAAO,wBAAwB,CAAC,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;AAC7E;;ACnCA;;;;;AAKG;AAOH;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BG;SACa,cAAc,CAC5B,OAAqC,EACrC,IAAyC,EACzC,QAAW,EAAA;AAEX,IAAA,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC;IAEhC,OAAO,QAAQ,CAAC,MAAK;AACnB,QAAA,MAAM,KAAK,GAAG,OAAO,EAAE;;;;AAIvB,QAAA,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;AAAE,YAAA,OAAO,KAAK;AAEvD,QAAA,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,QAAQ;AACjC,IAAA,CAAC,CAAC;AACJ;;ACxDA;;AAEG;;;;"}