ngwr 14.7.0 → 14.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (482) hide show
  1. package/README.md +66 -332
  2. package/alert/styles/_index.scss +10 -0
  3. package/avatar/styles/_index.scss +18 -7
  4. package/badge/styles/_index.scss +7 -0
  5. package/badge/styles/_tag.scss +7 -1
  6. package/bar-chart/styles/_index.scss +1 -0
  7. package/button/styles/_index.scss +6 -0
  8. package/calendar-heatmap/styles/_index.scss +1 -0
  9. package/cascader/styles/_rules.scss +87 -15
  10. package/checkbox/styles/_index.scss +4 -0
  11. package/command-palette/styles/_index.scss +1 -1
  12. package/date-picker/styles/_index.scss +30 -0
  13. package/density/styles/_index.scss +4 -2
  14. package/divider/styles/_index.scss +2 -0
  15. package/donut-chart/styles/_index.scss +10 -0
  16. package/dropdown/styles/_index.scss +67 -5
  17. package/editor/styles/_index.scss +441 -0
  18. package/event-calendar/styles/_index.scss +209 -35
  19. package/fesm2022/ngwr-action-sheet-testing.mjs.map +1 -1
  20. package/fesm2022/ngwr-action-sheet.mjs +3 -3
  21. package/fesm2022/ngwr-action-sheet.mjs.map +1 -1
  22. package/fesm2022/ngwr-affix.mjs +3 -3
  23. package/fesm2022/ngwr-affix.mjs.map +1 -1
  24. package/fesm2022/ngwr-alert.mjs +3 -3
  25. package/fesm2022/ngwr-alert.mjs.map +1 -1
  26. package/fesm2022/ngwr-anchor.mjs +3 -3
  27. package/fesm2022/ngwr-anchor.mjs.map +1 -1
  28. package/fesm2022/ngwr-aurora.mjs +3 -3
  29. package/fesm2022/ngwr-aurora.mjs.map +1 -1
  30. package/fesm2022/ngwr-avatar.mjs +3 -3
  31. package/fesm2022/ngwr-avatar.mjs.map +1 -1
  32. package/fesm2022/ngwr-back-top.mjs +3 -3
  33. package/fesm2022/ngwr-back-top.mjs.map +1 -1
  34. package/fesm2022/ngwr-badge.mjs +28 -13
  35. package/fesm2022/ngwr-badge.mjs.map +1 -1
  36. package/fesm2022/ngwr-bar-chart-testing.mjs.map +1 -1
  37. package/fesm2022/ngwr-bar-chart.mjs +31 -6
  38. package/fesm2022/ngwr-bar-chart.mjs.map +1 -1
  39. package/fesm2022/ngwr-blur-text-testing.mjs.map +1 -1
  40. package/fesm2022/ngwr-blur-text.mjs +3 -3
  41. package/fesm2022/ngwr-blur-text.mjs.map +1 -1
  42. package/fesm2022/ngwr-border-glow-testing.mjs.map +1 -1
  43. package/fesm2022/ngwr-border-glow.mjs +3 -3
  44. package/fesm2022/ngwr-border-glow.mjs.map +1 -1
  45. package/fesm2022/ngwr-breadcrumbs.mjs +6 -6
  46. package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
  47. package/fesm2022/ngwr-burger.mjs +3 -3
  48. package/fesm2022/ngwr-burger.mjs.map +1 -1
  49. package/fesm2022/ngwr-button-testing.mjs.map +1 -1
  50. package/fesm2022/ngwr-button.mjs +6 -6
  51. package/fesm2022/ngwr-button.mjs.map +1 -1
  52. package/fesm2022/ngwr-calendar-heatmap-testing.mjs.map +1 -1
  53. package/fesm2022/ngwr-calendar-heatmap.mjs +61 -6
  54. package/fesm2022/ngwr-calendar-heatmap.mjs.map +1 -1
  55. package/fesm2022/ngwr-calendar-testing.mjs.map +1 -1
  56. package/fesm2022/ngwr-calendar.mjs +3 -3
  57. package/fesm2022/ngwr-calendar.mjs.map +1 -1
  58. package/fesm2022/ngwr-card.mjs +9 -9
  59. package/fesm2022/ngwr-card.mjs.map +1 -1
  60. package/fesm2022/ngwr-carousel-testing.mjs.map +1 -1
  61. package/fesm2022/ngwr-carousel.mjs +6 -6
  62. package/fesm2022/ngwr-carousel.mjs.map +1 -1
  63. package/fesm2022/ngwr-cascader-testing.mjs.map +1 -1
  64. package/fesm2022/ngwr-cascader.mjs +4 -4
  65. package/fesm2022/ngwr-cascader.mjs.map +1 -1
  66. package/fesm2022/ngwr-checkbox-testing.mjs.map +1 -1
  67. package/fesm2022/ngwr-checkbox.mjs +18 -8
  68. package/fesm2022/ngwr-checkbox.mjs.map +1 -1
  69. package/fesm2022/ngwr-circular-text-testing.mjs.map +1 -1
  70. package/fesm2022/ngwr-circular-text.mjs +3 -3
  71. package/fesm2022/ngwr-circular-text.mjs.map +1 -1
  72. package/fesm2022/ngwr-click-spark.mjs +3 -3
  73. package/fesm2022/ngwr-click-spark.mjs.map +1 -1
  74. package/fesm2022/ngwr-clipboard.mjs +3 -3
  75. package/fesm2022/ngwr-clipboard.mjs.map +1 -1
  76. package/fesm2022/ngwr-collapse-testing.mjs.map +1 -1
  77. package/fesm2022/ngwr-collapse.mjs +9 -9
  78. package/fesm2022/ngwr-collapse.mjs.map +1 -1
  79. package/fesm2022/ngwr-color-picker-testing.mjs.map +1 -1
  80. package/fesm2022/ngwr-color-picker.mjs +6 -6
  81. package/fesm2022/ngwr-color-picker.mjs.map +1 -1
  82. package/fesm2022/ngwr-command-palette-testing.mjs.map +1 -1
  83. package/fesm2022/ngwr-command-palette.mjs +3 -3
  84. package/fesm2022/ngwr-command-palette.mjs.map +1 -1
  85. package/fesm2022/ngwr-compare.mjs +3 -3
  86. package/fesm2022/ngwr-compare.mjs.map +1 -1
  87. package/fesm2022/ngwr-confetti.mjs +3 -3
  88. package/fesm2022/ngwr-confetti.mjs.map +1 -1
  89. package/fesm2022/ngwr-config.mjs.map +1 -1
  90. package/fesm2022/ngwr-context-menu-testing.mjs.map +1 -1
  91. package/fesm2022/ngwr-context-menu.mjs +12 -12
  92. package/fesm2022/ngwr-context-menu.mjs.map +1 -1
  93. package/fesm2022/ngwr-cookie.mjs +3 -3
  94. package/fesm2022/ngwr-cookie.mjs.map +1 -1
  95. package/fesm2022/ngwr-counter.mjs +6 -6
  96. package/fesm2022/ngwr-counter.mjs.map +1 -1
  97. package/fesm2022/ngwr-date-adapters-fns.mjs +3 -3
  98. package/fesm2022/ngwr-date-adapters-fns.mjs.map +1 -1
  99. package/fesm2022/ngwr-date-adapters-luxon.mjs +3 -3
  100. package/fesm2022/ngwr-date-adapters-luxon.mjs.map +1 -1
  101. package/fesm2022/ngwr-date-picker-testing.mjs.map +1 -1
  102. package/fesm2022/ngwr-date-picker.mjs +721 -62
  103. package/fesm2022/ngwr-date-picker.mjs.map +1 -1
  104. package/fesm2022/ngwr-date.mjs +3 -3
  105. package/fesm2022/ngwr-date.mjs.map +1 -1
  106. package/fesm2022/ngwr-decrypt-text-testing.mjs.map +1 -1
  107. package/fesm2022/ngwr-decrypt-text.mjs +3 -3
  108. package/fesm2022/ngwr-decrypt-text.mjs.map +1 -1
  109. package/fesm2022/ngwr-density.mjs +6 -6
  110. package/fesm2022/ngwr-density.mjs.map +1 -1
  111. package/fesm2022/ngwr-descriptions.mjs +6 -6
  112. package/fesm2022/ngwr-descriptions.mjs.map +1 -1
  113. package/fesm2022/ngwr-dialog-testing.mjs.map +1 -1
  114. package/fesm2022/ngwr-dialog.mjs +15 -15
  115. package/fesm2022/ngwr-dialog.mjs.map +1 -1
  116. package/fesm2022/ngwr-directives.mjs +12 -12
  117. package/fesm2022/ngwr-directives.mjs.map +1 -1
  118. package/fesm2022/ngwr-divider.mjs +3 -3
  119. package/fesm2022/ngwr-divider.mjs.map +1 -1
  120. package/fesm2022/ngwr-donut-chart-testing.mjs.map +1 -1
  121. package/fesm2022/ngwr-donut-chart.mjs +48 -6
  122. package/fesm2022/ngwr-donut-chart.mjs.map +1 -1
  123. package/fesm2022/ngwr-drag-drop.mjs +6 -6
  124. package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
  125. package/fesm2022/ngwr-drawer-testing.mjs.map +1 -1
  126. package/fesm2022/ngwr-drawer.mjs +18 -18
  127. package/fesm2022/ngwr-drawer.mjs.map +1 -1
  128. package/fesm2022/ngwr-dropdown-testing.mjs.map +1 -1
  129. package/fesm2022/ngwr-dropdown.mjs +174 -25
  130. package/fesm2022/ngwr-dropdown.mjs.map +1 -1
  131. package/fesm2022/ngwr-editor-testing.mjs +568 -0
  132. package/fesm2022/ngwr-editor-testing.mjs.map +1 -0
  133. package/fesm2022/ngwr-editor.mjs +2601 -0
  134. package/fesm2022/ngwr-editor.mjs.map +1 -0
  135. package/fesm2022/ngwr-empty.mjs +3 -3
  136. package/fesm2022/ngwr-empty.mjs.map +1 -1
  137. package/fesm2022/ngwr-event-calendar-testing.mjs.map +1 -1
  138. package/fesm2022/ngwr-event-calendar.mjs +14 -7
  139. package/fesm2022/ngwr-event-calendar.mjs.map +1 -1
  140. package/fesm2022/ngwr-falling-text-testing.mjs.map +1 -1
  141. package/fesm2022/ngwr-falling-text.mjs +3 -3
  142. package/fesm2022/ngwr-falling-text.mjs.map +1 -1
  143. package/fesm2022/ngwr-file-upload-testing.mjs.map +1 -1
  144. package/fesm2022/ngwr-file-upload.mjs +3 -3
  145. package/fesm2022/ngwr-file-upload.mjs.map +1 -1
  146. package/fesm2022/ngwr-form-testing.mjs.map +1 -1
  147. package/fesm2022/ngwr-form.mjs +61 -10
  148. package/fesm2022/ngwr-form.mjs.map +1 -1
  149. package/fesm2022/ngwr-fuzzy-text-testing.mjs.map +1 -1
  150. package/fesm2022/ngwr-fuzzy-text.mjs +3 -3
  151. package/fesm2022/ngwr-fuzzy-text.mjs.map +1 -1
  152. package/fesm2022/ngwr-gauge-testing.mjs.map +1 -1
  153. package/fesm2022/ngwr-gauge.mjs +35 -6
  154. package/fesm2022/ngwr-gauge.mjs.map +1 -1
  155. package/fesm2022/ngwr-glitch-text-testing.mjs.map +1 -1
  156. package/fesm2022/ngwr-glitch-text.mjs +3 -3
  157. package/fesm2022/ngwr-glitch-text.mjs.map +1 -1
  158. package/fesm2022/ngwr-gradient-text-testing.mjs.map +1 -1
  159. package/fesm2022/ngwr-gradient-text.mjs +3 -3
  160. package/fesm2022/ngwr-gradient-text.mjs.map +1 -1
  161. package/fesm2022/ngwr-graph-testing.mjs.map +1 -1
  162. package/fesm2022/ngwr-graph.mjs +6 -6
  163. package/fesm2022/ngwr-graph.mjs.map +1 -1
  164. package/fesm2022/ngwr-hotkey.mjs +6 -6
  165. package/fesm2022/ngwr-hotkey.mjs.map +1 -1
  166. package/fesm2022/ngwr-i18n-ar.mjs +31 -0
  167. package/fesm2022/ngwr-i18n-ar.mjs.map +1 -1
  168. package/fesm2022/ngwr-i18n-cs.mjs +31 -0
  169. package/fesm2022/ngwr-i18n-cs.mjs.map +1 -1
  170. package/fesm2022/ngwr-i18n-de.mjs +31 -0
  171. package/fesm2022/ngwr-i18n-de.mjs.map +1 -1
  172. package/fesm2022/ngwr-i18n-en.mjs +39 -0
  173. package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
  174. package/fesm2022/ngwr-i18n-es.mjs +31 -0
  175. package/fesm2022/ngwr-i18n-es.mjs.map +1 -1
  176. package/fesm2022/ngwr-i18n-fr.mjs +31 -0
  177. package/fesm2022/ngwr-i18n-fr.mjs.map +1 -1
  178. package/fesm2022/ngwr-i18n-he.mjs +31 -0
  179. package/fesm2022/ngwr-i18n-he.mjs.map +1 -1
  180. package/fesm2022/ngwr-i18n-hi.mjs +31 -0
  181. package/fesm2022/ngwr-i18n-hi.mjs.map +1 -1
  182. package/fesm2022/ngwr-i18n-id.mjs +31 -0
  183. package/fesm2022/ngwr-i18n-id.mjs.map +1 -1
  184. package/fesm2022/ngwr-i18n-it.mjs +31 -0
  185. package/fesm2022/ngwr-i18n-it.mjs.map +1 -1
  186. package/fesm2022/ngwr-i18n-ja.mjs +31 -0
  187. package/fesm2022/ngwr-i18n-ja.mjs.map +1 -1
  188. package/fesm2022/ngwr-i18n-ko.mjs +31 -0
  189. package/fesm2022/ngwr-i18n-ko.mjs.map +1 -1
  190. package/fesm2022/ngwr-i18n-nl.mjs +31 -0
  191. package/fesm2022/ngwr-i18n-nl.mjs.map +1 -1
  192. package/fesm2022/ngwr-i18n-pl.mjs +31 -0
  193. package/fesm2022/ngwr-i18n-pl.mjs.map +1 -1
  194. package/fesm2022/ngwr-i18n-pt.mjs +31 -0
  195. package/fesm2022/ngwr-i18n-pt.mjs.map +1 -1
  196. package/fesm2022/ngwr-i18n-ru.mjs +31 -0
  197. package/fesm2022/ngwr-i18n-ru.mjs.map +1 -1
  198. package/fesm2022/ngwr-i18n-sv.mjs +31 -0
  199. package/fesm2022/ngwr-i18n-sv.mjs.map +1 -1
  200. package/fesm2022/ngwr-i18n-tr.mjs +31 -0
  201. package/fesm2022/ngwr-i18n-tr.mjs.map +1 -1
  202. package/fesm2022/ngwr-i18n-uk.mjs +31 -0
  203. package/fesm2022/ngwr-i18n-uk.mjs.map +1 -1
  204. package/fesm2022/ngwr-i18n-vi.mjs +31 -0
  205. package/fesm2022/ngwr-i18n-vi.mjs.map +1 -1
  206. package/fesm2022/ngwr-i18n-zh-TW.mjs +31 -0
  207. package/fesm2022/ngwr-i18n-zh-TW.mjs.map +1 -1
  208. package/fesm2022/ngwr-i18n-zh.mjs +31 -0
  209. package/fesm2022/ngwr-i18n-zh.mjs.map +1 -1
  210. package/fesm2022/ngwr-i18n.mjs +9 -9
  211. package/fesm2022/ngwr-i18n.mjs.map +1 -1
  212. package/fesm2022/ngwr-icon-adapters-feather.mjs.map +1 -1
  213. package/fesm2022/ngwr-icon-adapters-lucide.mjs.map +1 -1
  214. package/fesm2022/ngwr-icon.mjs +6 -6
  215. package/fesm2022/ngwr-icon.mjs.map +1 -1
  216. package/fesm2022/ngwr-image-cropper-testing.mjs.map +1 -1
  217. package/fesm2022/ngwr-image-cropper.mjs +3 -3
  218. package/fesm2022/ngwr-image-cropper.mjs.map +1 -1
  219. package/fesm2022/ngwr-input-number-testing.mjs.map +1 -1
  220. package/fesm2022/ngwr-input-number.mjs +15 -3
  221. package/fesm2022/ngwr-input-number.mjs.map +1 -1
  222. package/fesm2022/ngwr-input-otp-testing.mjs.map +1 -1
  223. package/fesm2022/ngwr-input-otp.mjs +3 -3
  224. package/fesm2022/ngwr-input-otp.mjs.map +1 -1
  225. package/fesm2022/ngwr-input-testing.mjs.map +1 -1
  226. package/fesm2022/ngwr-input.mjs +15 -15
  227. package/fesm2022/ngwr-input.mjs.map +1 -1
  228. package/fesm2022/ngwr-keyboard.mjs +3 -3
  229. package/fesm2022/ngwr-keyboard.mjs.map +1 -1
  230. package/fesm2022/ngwr-knob-testing.mjs.map +1 -1
  231. package/fesm2022/ngwr-knob.mjs +3 -3
  232. package/fesm2022/ngwr-knob.mjs.map +1 -1
  233. package/fesm2022/ngwr-layout.mjs +15 -15
  234. package/fesm2022/ngwr-layout.mjs.map +1 -1
  235. package/fesm2022/ngwr-lightbox-testing.mjs.map +1 -1
  236. package/fesm2022/ngwr-lightbox.mjs +3 -3
  237. package/fesm2022/ngwr-lightbox.mjs.map +1 -1
  238. package/fesm2022/ngwr-line-chart-testing.mjs.map +1 -1
  239. package/fesm2022/ngwr-line-chart.mjs +18 -7
  240. package/fesm2022/ngwr-line-chart.mjs.map +1 -1
  241. package/fesm2022/ngwr-list.mjs +6 -6
  242. package/fesm2022/ngwr-list.mjs.map +1 -1
  243. package/fesm2022/ngwr-loading-bar-router.mjs.map +1 -1
  244. package/fesm2022/ngwr-loading-bar.mjs +6 -6
  245. package/fesm2022/ngwr-loading-bar.mjs.map +1 -1
  246. package/fesm2022/ngwr-markdown-testing.mjs.map +1 -1
  247. package/fesm2022/ngwr-markdown.mjs +798 -17
  248. package/fesm2022/ngwr-markdown.mjs.map +1 -1
  249. package/fesm2022/ngwr-marquee-testing.mjs.map +1 -1
  250. package/fesm2022/ngwr-marquee.mjs +3 -3
  251. package/fesm2022/ngwr-marquee.mjs.map +1 -1
  252. package/fesm2022/ngwr-media.mjs +3 -3
  253. package/fesm2022/ngwr-media.mjs.map +1 -1
  254. package/fesm2022/ngwr-mention-testing.mjs.map +1 -1
  255. package/fesm2022/ngwr-mention.mjs +6 -6
  256. package/fesm2022/ngwr-mention.mjs.map +1 -1
  257. package/fesm2022/ngwr-meta.mjs +6 -6
  258. package/fesm2022/ngwr-meta.mjs.map +1 -1
  259. package/fesm2022/ngwr-meter-group-testing.mjs +7 -3
  260. package/fesm2022/ngwr-meter-group-testing.mjs.map +1 -1
  261. package/fesm2022/ngwr-meter-group.mjs +26 -6
  262. package/fesm2022/ngwr-meter-group.mjs.map +1 -1
  263. package/fesm2022/ngwr-overlay.mjs +6 -6
  264. package/fesm2022/ngwr-overlay.mjs.map +1 -1
  265. package/fesm2022/ngwr-page-header.mjs +13 -5
  266. package/fesm2022/ngwr-page-header.mjs.map +1 -1
  267. package/fesm2022/ngwr-pagination-testing.mjs.map +1 -1
  268. package/fesm2022/ngwr-pagination.mjs +3 -3
  269. package/fesm2022/ngwr-pagination.mjs.map +1 -1
  270. package/fesm2022/ngwr-pipes.mjs +21 -21
  271. package/fesm2022/ngwr-pipes.mjs.map +1 -1
  272. package/fesm2022/ngwr-platform.mjs +9 -9
  273. package/fesm2022/ngwr-platform.mjs.map +1 -1
  274. package/fesm2022/ngwr-popconfirm-testing.mjs.map +1 -1
  275. package/fesm2022/ngwr-popconfirm.mjs +6 -6
  276. package/fesm2022/ngwr-popconfirm.mjs.map +1 -1
  277. package/fesm2022/ngwr-popover-testing.mjs.map +1 -1
  278. package/fesm2022/ngwr-popover.mjs +578 -16
  279. package/fesm2022/ngwr-popover.mjs.map +1 -1
  280. package/fesm2022/ngwr-progress.mjs +3 -3
  281. package/fesm2022/ngwr-progress.mjs.map +1 -1
  282. package/fesm2022/ngwr-pull-to-refresh.mjs +3 -3
  283. package/fesm2022/ngwr-pull-to-refresh.mjs.map +1 -1
  284. package/fesm2022/ngwr-qr.mjs +3 -3
  285. package/fesm2022/ngwr-qr.mjs.map +1 -1
  286. package/fesm2022/ngwr-radio-testing.mjs.map +1 -1
  287. package/fesm2022/ngwr-radio.mjs +6 -6
  288. package/fesm2022/ngwr-radio.mjs.map +1 -1
  289. package/fesm2022/ngwr-rating-testing.mjs.map +1 -1
  290. package/fesm2022/ngwr-rating.mjs +3 -3
  291. package/fesm2022/ngwr-rating.mjs.map +1 -1
  292. package/fesm2022/ngwr-result.mjs +12 -12
  293. package/fesm2022/ngwr-result.mjs.map +1 -1
  294. package/fesm2022/ngwr-rotating-text-testing.mjs.map +1 -1
  295. package/fesm2022/ngwr-rotating-text.mjs +3 -3
  296. package/fesm2022/ngwr-rotating-text.mjs.map +1 -1
  297. package/fesm2022/ngwr-schema-form.mjs +3 -3
  298. package/fesm2022/ngwr-schema-form.mjs.map +1 -1
  299. package/fesm2022/ngwr-scroll.mjs +3 -3
  300. package/fesm2022/ngwr-scroll.mjs.map +1 -1
  301. package/fesm2022/ngwr-segmented-testing.mjs.map +1 -1
  302. package/fesm2022/ngwr-segmented.mjs +3 -3
  303. package/fesm2022/ngwr-segmented.mjs.map +1 -1
  304. package/fesm2022/ngwr-select-testing.mjs.map +1 -1
  305. package/fesm2022/ngwr-select.mjs +12 -12
  306. package/fesm2022/ngwr-select.mjs.map +1 -1
  307. package/fesm2022/ngwr-shiny-text-testing.mjs.map +1 -1
  308. package/fesm2022/ngwr-shiny-text.mjs +6 -6
  309. package/fesm2022/ngwr-shiny-text.mjs.map +1 -1
  310. package/fesm2022/ngwr-sidebar.mjs +10 -3
  311. package/fesm2022/ngwr-sidebar.mjs.map +1 -1
  312. package/fesm2022/ngwr-skeleton.mjs +3 -3
  313. package/fesm2022/ngwr-skeleton.mjs.map +1 -1
  314. package/fesm2022/ngwr-slider-testing.mjs.map +1 -1
  315. package/fesm2022/ngwr-slider.mjs +3 -3
  316. package/fesm2022/ngwr-slider.mjs.map +1 -1
  317. package/fesm2022/ngwr-sparkline-testing.mjs.map +1 -1
  318. package/fesm2022/ngwr-sparkline.mjs +84 -10
  319. package/fesm2022/ngwr-sparkline.mjs.map +1 -1
  320. package/fesm2022/ngwr-speed-dial-testing.mjs.map +1 -1
  321. package/fesm2022/ngwr-speed-dial.mjs +3 -3
  322. package/fesm2022/ngwr-speed-dial.mjs.map +1 -1
  323. package/fesm2022/ngwr-spinner.mjs +3 -3
  324. package/fesm2022/ngwr-spinner.mjs.map +1 -1
  325. package/fesm2022/ngwr-splash-cursor-testing.mjs.map +1 -1
  326. package/fesm2022/ngwr-splash-cursor.mjs +3 -3
  327. package/fesm2022/ngwr-splash-cursor.mjs.map +1 -1
  328. package/fesm2022/ngwr-split-text-testing.mjs.map +1 -1
  329. package/fesm2022/ngwr-split-text.mjs +3 -3
  330. package/fesm2022/ngwr-split-text.mjs.map +1 -1
  331. package/fesm2022/ngwr-splitter-testing.mjs.map +1 -1
  332. package/fesm2022/ngwr-splitter.mjs +3 -3
  333. package/fesm2022/ngwr-splitter.mjs.map +1 -1
  334. package/fesm2022/ngwr-spotlight-card-testing.mjs.map +1 -1
  335. package/fesm2022/ngwr-spotlight-card.mjs +6 -6
  336. package/fesm2022/ngwr-spotlight-card.mjs.map +1 -1
  337. package/fesm2022/ngwr-squircle.mjs +6 -6
  338. package/fesm2022/ngwr-squircle.mjs.map +1 -1
  339. package/fesm2022/ngwr-star-border-testing.mjs.map +1 -1
  340. package/fesm2022/ngwr-star-border.mjs +3 -3
  341. package/fesm2022/ngwr-star-border.mjs.map +1 -1
  342. package/fesm2022/ngwr-statistic.mjs +9 -9
  343. package/fesm2022/ngwr-statistic.mjs.map +1 -1
  344. package/fesm2022/ngwr-stepper-testing.mjs.map +1 -1
  345. package/fesm2022/ngwr-stepper.mjs +6 -6
  346. package/fesm2022/ngwr-stepper.mjs.map +1 -1
  347. package/fesm2022/ngwr-storage.mjs +3 -3
  348. package/fesm2022/ngwr-storage.mjs.map +1 -1
  349. package/fesm2022/ngwr-switch-testing.mjs.map +1 -1
  350. package/fesm2022/ngwr-switch.mjs +3 -3
  351. package/fesm2022/ngwr-switch.mjs.map +1 -1
  352. package/fesm2022/ngwr-table-testing.mjs.map +1 -1
  353. package/fesm2022/ngwr-table.mjs +18 -18
  354. package/fesm2022/ngwr-table.mjs.map +1 -1
  355. package/fesm2022/ngwr-tabs-router.mjs +3 -3
  356. package/fesm2022/ngwr-tabs-router.mjs.map +1 -1
  357. package/fesm2022/ngwr-tabs-testing.mjs.map +1 -1
  358. package/fesm2022/ngwr-tabs.mjs +6 -6
  359. package/fesm2022/ngwr-tabs.mjs.map +1 -1
  360. package/fesm2022/ngwr-textarea-testing.mjs.map +1 -1
  361. package/fesm2022/ngwr-textarea.mjs +3 -3
  362. package/fesm2022/ngwr-textarea.mjs.map +1 -1
  363. package/fesm2022/ngwr-theme.mjs +3 -3
  364. package/fesm2022/ngwr-theme.mjs.map +1 -1
  365. package/fesm2022/ngwr-tilt-card-testing.mjs.map +1 -1
  366. package/fesm2022/ngwr-tilt-card.mjs +6 -6
  367. package/fesm2022/ngwr-tilt-card.mjs.map +1 -1
  368. package/fesm2022/ngwr-timeline.mjs +6 -6
  369. package/fesm2022/ngwr-timeline.mjs.map +1 -1
  370. package/fesm2022/ngwr-toast-testing.mjs.map +1 -1
  371. package/fesm2022/ngwr-toast.mjs +9 -9
  372. package/fesm2022/ngwr-toast.mjs.map +1 -1
  373. package/fesm2022/ngwr-toolbar.mjs +10 -3
  374. package/fesm2022/ngwr-toolbar.mjs.map +1 -1
  375. package/fesm2022/ngwr-tour-testing.mjs.map +1 -1
  376. package/fesm2022/ngwr-tour.mjs +6 -6
  377. package/fesm2022/ngwr-tour.mjs.map +1 -1
  378. package/fesm2022/ngwr-transfer-testing.mjs.map +1 -1
  379. package/fesm2022/ngwr-transfer.mjs +3 -3
  380. package/fesm2022/ngwr-transfer.mjs.map +1 -1
  381. package/fesm2022/ngwr-tree-testing.mjs.map +1 -1
  382. package/fesm2022/ngwr-tree.mjs +3 -3
  383. package/fesm2022/ngwr-tree.mjs.map +1 -1
  384. package/fesm2022/ngwr-typewriter-testing.mjs.map +1 -1
  385. package/fesm2022/ngwr-typewriter.mjs +3 -3
  386. package/fesm2022/ngwr-typewriter.mjs.map +1 -1
  387. package/fesm2022/ngwr-typography.mjs +7 -3
  388. package/fesm2022/ngwr-typography.mjs.map +1 -1
  389. package/fesm2022/ngwr-utils.mjs.map +1 -1
  390. package/fesm2022/ngwr-validators.mjs.map +1 -1
  391. package/fesm2022/ngwr-version.mjs +1 -1
  392. package/fesm2022/ngwr-version.mjs.map +1 -1
  393. package/fesm2022/ngwr-virtual-scroll.mjs +3 -3
  394. package/fesm2022/ngwr-virtual-scroll.mjs.map +1 -1
  395. package/fesm2022/ngwr-waves-testing.mjs.map +1 -1
  396. package/fesm2022/ngwr-waves.mjs +3 -3
  397. package/fesm2022/ngwr-waves.mjs.map +1 -1
  398. package/fesm2022/ngwr-window-testing.mjs.map +1 -1
  399. package/fesm2022/ngwr-window.mjs +12 -12
  400. package/fesm2022/ngwr-window.mjs.map +1 -1
  401. package/form/styles/_index.scss +16 -1
  402. package/gauge/styles/_index.scss +1 -0
  403. package/i18n/ar.json +32 -1
  404. package/i18n/cs.json +32 -1
  405. package/i18n/de.json +32 -1
  406. package/i18n/en.json +32 -1
  407. package/i18n/es.json +32 -1
  408. package/i18n/fr.json +32 -1
  409. package/i18n/he.json +32 -1
  410. package/i18n/hi.json +32 -1
  411. package/i18n/id.json +32 -1
  412. package/i18n/it.json +32 -1
  413. package/i18n/ja.json +32 -1
  414. package/i18n/ko.json +32 -1
  415. package/i18n/nl.json +32 -1
  416. package/i18n/pl.json +32 -1
  417. package/i18n/pt.json +32 -1
  418. package/i18n/ru.json +32 -1
  419. package/i18n/sv.json +32 -1
  420. package/i18n/tr.json +32 -1
  421. package/i18n/uk.json +32 -1
  422. package/i18n/vi.json +32 -1
  423. package/i18n/zh-TW.json +32 -1
  424. package/i18n/zh.json +32 -1
  425. package/input/styles/_index.scss +24 -1
  426. package/input-number/styles/_index.scss +69 -0
  427. package/input-otp/styles/_index.scss +5 -5
  428. package/line-chart/styles/_index.scss +30 -2
  429. package/llms-full.txt +14 -4
  430. package/llms.txt +188 -132
  431. package/mcp/providers.js +2 -2
  432. package/mcp/server.js +1 -1
  433. package/meter-group/styles/_index.scss +1 -0
  434. package/overlay/styles/_arrow.scss +30 -2
  435. package/package.json +43 -2
  436. package/page-header/styles/_index.scss +37 -1
  437. package/pagination/styles/_index.scss +9 -5
  438. package/popover/styles/_index.scss +73 -5
  439. package/progress/styles/_index.scss +4 -0
  440. package/radio/styles/_index.scss +4 -1
  441. package/schematics/use/symbol-map.json +1 -0
  442. package/select/styles/_index.scss +51 -12
  443. package/sidebar/styles/_index.scss +44 -2
  444. package/skeleton/styles/_index.scss +3 -0
  445. package/skills/ngwr/SKILL.md +5 -5
  446. package/skills/ngwr/references/catalog.md +2 -0
  447. package/skills/ngwr/references/setup.md +3 -3
  448. package/sparkline/styles/_index.scss +19 -0
  449. package/styles.scss +1 -0
  450. package/table/styles/_index.scss +7 -0
  451. package/textarea/styles/_index.scss +12 -3
  452. package/theme/styles/_colors.scss +39 -13
  453. package/theme/styles/_contrast.scss +9 -7
  454. package/toast/styles/_index.scss +4 -0
  455. package/toolbar/styles/_index.scss +35 -1
  456. package/tree/styles/_index.scss +46 -7
  457. package/types/ngwr-badge.d.ts +22 -7
  458. package/types/ngwr-bar-chart.d.ts +19 -1
  459. package/types/ngwr-calendar-heatmap.d.ts +29 -1
  460. package/types/ngwr-checkbox.d.ts +2 -0
  461. package/types/ngwr-config.d.ts +12 -0
  462. package/types/ngwr-date-picker.d.ts +308 -43
  463. package/types/ngwr-donut-chart.d.ts +24 -1
  464. package/types/ngwr-dropdown.d.ts +22 -2
  465. package/types/ngwr-editor-testing.d.ts +378 -0
  466. package/types/ngwr-editor.d.ts +449 -0
  467. package/types/ngwr-event-calendar.d.ts +8 -0
  468. package/types/ngwr-form.d.ts +35 -5
  469. package/types/ngwr-gauge.d.ts +20 -1
  470. package/types/ngwr-input-number.d.ts +7 -0
  471. package/types/ngwr-line-chart.d.ts +9 -1
  472. package/types/ngwr-markdown.d.ts +61 -2
  473. package/types/ngwr-meter-group-testing.d.ts +3 -2
  474. package/types/ngwr-meter-group.d.ts +14 -1
  475. package/types/ngwr-page-header.d.ts +10 -2
  476. package/types/ngwr-popover.d.ts +154 -3
  477. package/types/ngwr-sidebar.d.ts +7 -0
  478. package/types/ngwr-sparkline.d.ts +43 -1
  479. package/types/ngwr-toolbar.d.ts +7 -0
  480. package/types/ngwr-typography.d.ts +4 -0
  481. package/types/ngwr-version.d.ts +1 -1
  482. package/typography/styles/_index.scss +16 -0
@@ -250,10 +250,10 @@ class WrTextarea {
250
250
  el.style.overflowY = 'hidden';
251
251
  }
252
252
  }
253
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrTextarea, deps: [], target: i0.ɵɵFactoryTarget.Component });
254
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: WrTextarea, isStandalone: true, selector: "wr-textarea", inputs: { placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, resizable: { classPropertyName: "resizable", publicName: "resizable", isSignal: true, isRequired: false, transformFunction: null }, resize: { classPropertyName: "resize", publicName: "resize", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, autosize: { classPropertyName: "autosize", publicName: "autosize", isSignal: true, isRequired: false, transformFunction: null }, maxRows: { classPropertyName: "maxRows", publicName: "maxRows", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { properties: { "class": "classes()" } }, viewQueries: [{ propertyName: "native", first: true, predicate: ["native"], descendants: true, isSignal: true }], ngImport: i0, template: "<textarea\n #native\n class=\"wr-textarea__native\"\n [attr.id]=\"controlId()\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n [placeholder]=\"placeholder()\"\n [rows]=\"rows()\"\n [readonly]=\"readonly()\"\n [disabled]=\"disabled()\"\n [attr.aria-invalid]=\"fieldAria.ariaInvalid()\"\n [attr.aria-describedby]=\"fieldAria.describedBy()\"\n [value]=\"value()\"\n (input)=\"onInput($event)\"\n (focus)=\"focused.set(true)\"\n (blur)=\"onBlur()\"\n></textarea>\n\n@if (showHandle()) {\n <!-- Custom corner grip \u2014 the lucide icon + cursor follow the `resize`\n direction. Icons inlined so no icon registration is required. -->\n <span\n [class]=\"`wr-textarea__resize wr-textarea__resize--${effectiveResize()}`\"\n aria-hidden=\"true\"\n (pointerdown)=\"startResize($event)\"\n (pointermove)=\"onResize($event)\"\n (pointerup)=\"endResize($event)\"\n (pointercancel)=\"endResize($event)\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n @switch (effectiveResize()) {\n @case ('vertical') {\n <path d=\"M12 2v20\" />\n <path d=\"m8 18 4 4 4-4\" />\n <path d=\"m8 6 4-4 4 4\" />\n }\n @case ('horizontal') {\n <path d=\"M2 12h20\" />\n <path d=\"m18 8 4 4-4 4\" />\n <path d=\"m6 8-4 4 4 4\" />\n }\n @default {\n <path d=\"M19 13v6h-6\" />\n <path d=\"M5 11V5h6\" />\n <path d=\"m5 5 14 14\" />\n }\n }\n </svg>\n </span>\n}\n", encapsulation: i0.ViewEncapsulation.None });
253
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrTextarea, deps: [], target: i0.ɵɵFactoryTarget.Component });
254
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: WrTextarea, isStandalone: true, selector: "wr-textarea", inputs: { placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, resizable: { classPropertyName: "resizable", publicName: "resizable", isSignal: true, isRequired: false, transformFunction: null }, resize: { classPropertyName: "resize", publicName: "resize", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, autosize: { classPropertyName: "autosize", publicName: "autosize", isSignal: true, isRequired: false, transformFunction: null }, maxRows: { classPropertyName: "maxRows", publicName: "maxRows", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { properties: { "class": "classes()" } }, viewQueries: [{ propertyName: "native", first: true, predicate: ["native"], descendants: true, isSignal: true }], ngImport: i0, template: "<textarea\n #native\n class=\"wr-textarea__native\"\n [attr.id]=\"controlId()\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n [placeholder]=\"placeholder()\"\n [rows]=\"rows()\"\n [readonly]=\"readonly()\"\n [disabled]=\"disabled()\"\n [attr.aria-invalid]=\"fieldAria.ariaInvalid()\"\n [attr.aria-describedby]=\"fieldAria.describedBy()\"\n [value]=\"value()\"\n (input)=\"onInput($event)\"\n (focus)=\"focused.set(true)\"\n (blur)=\"onBlur()\"\n></textarea>\n\n@if (showHandle()) {\n <!-- Custom corner grip \u2014 the lucide icon + cursor follow the `resize`\n direction. Icons inlined so no icon registration is required. -->\n <span\n [class]=\"`wr-textarea__resize wr-textarea__resize--${effectiveResize()}`\"\n aria-hidden=\"true\"\n (pointerdown)=\"startResize($event)\"\n (pointermove)=\"onResize($event)\"\n (pointerup)=\"endResize($event)\"\n (pointercancel)=\"endResize($event)\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n @switch (effectiveResize()) {\n @case ('vertical') {\n <path d=\"M12 2v20\" />\n <path d=\"m8 18 4 4 4-4\" />\n <path d=\"m8 6 4-4 4 4\" />\n }\n @case ('horizontal') {\n <path d=\"M2 12h20\" />\n <path d=\"m18 8 4 4-4 4\" />\n <path d=\"m6 8-4 4 4 4\" />\n }\n @default {\n <path d=\"M19 13v6h-6\" />\n <path d=\"M5 11V5h6\" />\n <path d=\"m5 5 14 14\" />\n }\n }\n </svg>\n </span>\n}\n", encapsulation: i0.ViewEncapsulation.None });
255
255
  }
256
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrTextarea, decorators: [{
256
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrTextarea, decorators: [{
257
257
  type: Component,
258
258
  args: [{ selector: 'wr-textarea', encapsulation: ViewEncapsulation.None, host: { '[class]': 'classes()' }, template: "<textarea\n #native\n class=\"wr-textarea__native\"\n [attr.id]=\"controlId()\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n [placeholder]=\"placeholder()\"\n [rows]=\"rows()\"\n [readonly]=\"readonly()\"\n [disabled]=\"disabled()\"\n [attr.aria-invalid]=\"fieldAria.ariaInvalid()\"\n [attr.aria-describedby]=\"fieldAria.describedBy()\"\n [value]=\"value()\"\n (input)=\"onInput($event)\"\n (focus)=\"focused.set(true)\"\n (blur)=\"onBlur()\"\n></textarea>\n\n@if (showHandle()) {\n <!-- Custom corner grip \u2014 the lucide icon + cursor follow the `resize`\n direction. Icons inlined so no icon registration is required. -->\n <span\n [class]=\"`wr-textarea__resize wr-textarea__resize--${effectiveResize()}`\"\n aria-hidden=\"true\"\n (pointerdown)=\"startResize($event)\"\n (pointermove)=\"onResize($event)\"\n (pointerup)=\"endResize($event)\"\n (pointercancel)=\"endResize($event)\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n @switch (effectiveResize()) {\n @case ('vertical') {\n <path d=\"M12 2v20\" />\n <path d=\"m8 18 4 4 4-4\" />\n <path d=\"m8 6 4-4 4 4\" />\n }\n @case ('horizontal') {\n <path d=\"M2 12h20\" />\n <path d=\"m18 8 4 4-4 4\" />\n <path d=\"m6 8-4 4 4 4\" />\n }\n @default {\n <path d=\"M19 13v6h-6\" />\n <path d=\"M5 11V5h6\" />\n <path d=\"m5 5 14 14\" />\n }\n }\n </svg>\n </span>\n}\n" }]
259
259
  }], ctorParameters: () => [], propDecorators: { placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }], resizable: [{ type: i0.Input, args: [{ isSignal: true, alias: "resizable", required: false }] }], resize: [{ type: i0.Input, args: [{ isSignal: true, alias: "resize", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], autosize: [{ type: i0.Input, args: [{ isSignal: true, alias: "autosize", required: false }] }], maxRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxRows", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], touch: [{ type: i0.Output, args: ["touch"] }], native: [{ type: i0.ViewChild, args: ['native', { isSignal: true }] }] } });
@@ -1 +1 @@
1
- {"version":3,"file":"ngwr-textarea.mjs","sources":["../../../projects/lib/textarea/textarea.ts","../../../projects/lib/textarea/textarea.html","../../../projects/lib/textarea/ngwr-textarea.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 { isPlatformBrowser } from '@angular/common';\nimport {\n Component,\n ElementRef,\n PLATFORM_ID,\n ViewEncapsulation,\n computed,\n effect,\n inject,\n input,\n model,\n output,\n signal,\n viewChild,\n} from '@angular/core';\nimport type { FormValueControl } from '@angular/forms/signals';\n\nimport { useConfigValue } from 'ngwr/config';\nimport { WR_FORM_FIELD, useFormFieldAria } from 'ngwr/form';\n\n/**\n * Multi-line text input.\n *\n * A signal-forms native control: it implements `FormValueControl<string>`, so\n * `[formField]` binds straight to its `value` model — no\n * `ControlValueAccessor` in between. `[(value)]` works standalone.\n *\n * Optional `autosize` grows the textarea with its content, capped at\n * `maxRows` if provided.\n *\n * @example\n * ```html\n * <!-- signal forms -->\n * <wr-textarea placeholder=\"Notes\" [formField]=\"form.notes\" />\n *\n * <!-- standalone two-way binding -->\n * <wr-textarea autosize [maxRows]=\"6\" [(value)]=\"text\" />\n * ```\n *\n * @see https://ngwr.dev/reference/components/textarea\n */\nexport type WrTextareaSize = 'sm' | 'md' | 'lg';\n\nexport type WrTextareaResize = 'none' | 'vertical' | 'horizontal' | 'both';\n\n@Component({\n selector: 'wr-textarea',\n templateUrl: './textarea.html',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n})\nexport class WrTextarea implements FormValueControl<string> {\n /** Native placeholder text. @default '' */\n readonly placeholder = input<string>('');\n\n /**\n * Accessible name for the field. Falls back to the placeholder — the native\n * `<textarea>` lives inside the component, so a `<label for>` outside cannot\n * reach it.\n */\n readonly ariaLabel = input<string | null>(null);\n\n protected readonly resolvedAriaLabel = computed(() => {\n // Not `??`: an empty placeholder is no name at all, so it must fall through.\n const explicit = this.ariaLabel();\n if (explicit) return explicit;\n const placeholder = this.placeholder();\n return placeholder ? placeholder : null;\n });\n\n /**\n * Control size — shares the `--wr-control-*` contract. Unset, it falls back to\n * `provideWrConfig({ textarea: { size } })`. @default 'md'\n */\n readonly size = input<WrTextareaSize | null>(null);\n\n // `null` as the input's own default, not `'md'`: with a literal sitting there,\n // \"the template said nothing\" and \"the template said md\" are the same value, so no\n // app-wide default could ever apply. The effective default is the last argument\n // below, which is where the old inline one moved to.\n protected readonly resolvedSize = useConfigValue(this.size, c => c.textarea?.size, 'md');\n\n /** Visible row count. @default 3 */\n readonly rows = input(3, { transform: (v: unknown): number => coerceNumberProperty(v, 3) });\n\n /** Allow user resize via the corner grip. @default true */\n readonly resizable = input(true, { transform: coerceBooleanProperty });\n\n /** Resize direction of the corner grip (the grip icon adapts). @default 'vertical' */\n readonly resize = input<WrTextareaResize>('vertical');\n\n /** Read-only state. @default false */\n readonly readonly = input(false, { transform: coerceBooleanProperty });\n\n /** Grow the textarea to fit its content. @default false */\n readonly autosize = input(false, { transform: coerceBooleanProperty });\n\n /** Cap autosize at this many rows. Ignored when `autosize` is false. */\n readonly maxRows = input<number | null>(null);\n\n /**\n * Disable the textarea. Bound automatically from the field's disabled state\n * when used with `[formField]`.\n *\n * @default false\n */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n /** The edited text. Bound by `[formField]`, or two-way via `[(value)]`. */\n readonly value = model<string>('');\n\n /** Emitted on blur so a bound field can mark itself touched. */\n readonly touch = output<void>();\n\n protected readonly focused = signal(false);\n\n protected readonly native = viewChild.required<ElementRef<HTMLTextAreaElement>>('native');\n\n /** Resize direction, gated by `resizable` (false → 'none'). */\n protected readonly effectiveResize = computed<WrTextareaResize>(() => (this.resizable() ? this.resize() : 'none'));\n\n /** The surrounding `<wr-form-field>`'s error state. @internal */\n protected readonly fieldAria = useFormFieldAria();\n\n private readonly field = inject(WR_FORM_FIELD, { optional: true });\n\n /**\n * Id the surrounding `<wr-form-field>`'s `<label for>` points at.\n *\n * The field renders its label before it can see what was projected into it, so\n * the id travels the other way and the control adopts it, exactly as\n * `[wrInput]` and `wr-select` do. Without it the `for` named an element that\n * was nowhere in the document: clicking the label did nothing, and the field\n * was, to a screen reader, an unlabelled block.\n *\n * It lands on the native `<textarea>` rather than on the host, because only a\n * labelable element can be a label's target and `<wr-textarea>` is not one.\n *\n * What it does NOT change is the NAME: `aria-label` outranks a `<label>` in\n * the accname order and `resolvedAriaLabel()` still wins, the same call\n * `wr-select` and `wr-slider` make — the field renders a label only when its\n * `label` input is set, so it cannot promise a name to fall back on. Set\n * `[ariaLabel]` to the field's label where the two should read alike.\n */\n protected readonly controlId = computed(() => this.field?.controlId() ?? null);\n\n protected readonly classes = computed(() => {\n const parts = ['wr-textarea'];\n const size = this.resolvedSize();\n if (size !== 'md') parts.push(`wr-textarea--${size}`);\n if (this.autosize()) parts.push('wr-textarea--no-resize');\n const resize = this.effectiveResize();\n if (resize === 'horizontal' || resize === 'both') parts.push('wr-textarea--resize-x');\n if (this.focused()) parts.push('wr-textarea--focused');\n if (this.disabled()) parts.push('wr-textarea--disabled');\n return parts.join(' ');\n });\n\n /** Show the corner grip (hidden when direction is 'none' / autosize / disabled). */\n protected readonly showHandle = computed(\n () => this.effectiveResize() !== 'none' && !this.autosize() && !this.disabled()\n );\n\n private readonly platformId = inject(PLATFORM_ID);\n private readonly isBrowser = isPlatformBrowser(this.platformId);\n private readonly hostEl = inject<ElementRef<HTMLElement>>(ElementRef);\n\n /**\n * Ambient reading direction, read by the horizontal half of the resize drag.\n *\n * Optional so a bare `TestBed` — or any consumer that never set a direction —\n * needs no provider; `Directionality` is root-provided, so `null` only ever\n * means \"nobody asked\", which is LTR. Read inside the handler rather than\n * cached, so a runtime flip needs no subscription to `Directionality.change`.\n */\n private readonly dir = inject(Directionality, { optional: true });\n\n // Custom resize-grip drag state (replaces the native corner handle).\n private resizing = false;\n private resizeStartY = 0;\n private resizeStartX = 0;\n private resizeStartHeight = 0;\n private resizeStartWidth = 0;\n private resizeMinHeight = 36;\n private resizeMaxWidth = Number.POSITIVE_INFINITY;\n\n constructor() {\n // Autosize: re-fit whenever value or autosize toggles.\n effect(() => {\n if (!this.isBrowser) return;\n if (!this.autosize()) {\n // Hand the height back. Left behind, the field stays frozen at whatever\n // was last fitted and `rows` silently stops meaning anything, which reads\n // as the input having done nothing.\n this.releaseHeight();\n return;\n }\n // Read `value` to register dependency\n this.value();\n requestAnimationFrame(() => this.autofit());\n });\n }\n\n // Template handlers\n\n protected onInput(event: Event): void {\n this.value.set((event.target as HTMLTextAreaElement).value);\n }\n\n protected onBlur(): void {\n this.focused.set(false);\n this.touch.emit();\n }\n\n // Custom resize — drag the corner grip; direction comes from `effectiveResize`.\n // Pointer capture keeps move/up on the grip even when the cursor leaves it.\n protected startResize(event: PointerEvent): void {\n const el = this.native()?.nativeElement;\n if (!el) return;\n const host = this.hostEl.nativeElement;\n this.resizing = true;\n this.resizeStartY = event.clientY;\n this.resizeStartX = event.clientX;\n this.resizeStartHeight = el.offsetHeight;\n this.resizeStartWidth = host.offsetWidth;\n // Height floor = fits the current content, so shrinking never opens an\n // overflow scrollbar. Measured once, synchronously (no paint between).\n const borderY = el.offsetHeight - el.clientHeight;\n const prevHeight = el.style.height;\n el.style.height = 'auto';\n this.resizeMinHeight = el.scrollHeight + borderY;\n el.style.height = prevHeight;\n // Width ceiling = parent inner width, so horizontal drag can't overflow.\n this.resizeMaxWidth = host.parentElement?.clientWidth ?? Number.POSITIVE_INFINITY;\n (event.target as HTMLElement).setPointerCapture(event.pointerId);\n event.preventDefault();\n }\n\n protected onResize(event: PointerEvent): void {\n if (!this.resizing) return;\n const el = this.native()?.nativeElement;\n if (!el) return;\n const dir = this.effectiveResize();\n if (dir === 'vertical' || dir === 'both') {\n const h = Math.max(this.resizeMinHeight, this.resizeStartHeight + (event.clientY - this.resizeStartY));\n el.style.height = `${h}px`;\n }\n if (dir === 'horizontal' || dir === 'both') {\n // The grip sits at the field's INLINE END — physically bottom-right in LTR,\n // bottom-left in RTL, where a block-level box grows because it is anchored\n // at the right edge of its containing block. So the pointer's physical\n // delta means \"wider\" in one direction and \"narrower\" in the other, and the\n // sign has to follow the reading direction. It did not, so under `dir=\"rtl\"`\n // the grip sat on the corner the box does NOT extend toward and dragging it\n // outward shrank the field.\n const dx = event.clientX - this.resizeStartX;\n const inline = this.dir?.value === 'rtl' ? -dx : dx;\n const w = Math.min(this.resizeMaxWidth, Math.max(64, this.resizeStartWidth + inline));\n this.hostEl.nativeElement.style.width = `${w}px`;\n }\n }\n\n protected endResize(event: PointerEvent): void {\n if (!this.resizing) return;\n this.resizing = false;\n (event.target as HTMLElement).releasePointerCapture(event.pointerId);\n }\n\n private releaseHeight(): void {\n const el = this.native()?.nativeElement;\n if (!el) return;\n el.style.height = '';\n el.style.overflowY = '';\n }\n\n private autofit(): void {\n const el = this.native()?.nativeElement;\n if (!el) return;\n // A frame can outlive the reason it was scheduled: toggling `autosize` off\n // between the effect and the frame would otherwise fit a height nobody asked\n // for, and `releaseHeight` has already run by then.\n if (!this.autosize()) return;\n el.style.height = 'auto';\n\n const maxRows = this.maxRows();\n if (maxRows && maxRows > 0) {\n const cs = getComputedStyle(el);\n const lineHeight = parseFloat(cs.lineHeight) || parseFloat(cs.fontSize) * 1.2;\n const cap = lineHeight * maxRows;\n const next = Math.min(el.scrollHeight, cap);\n el.style.height = `${next}px`;\n el.style.overflowY = el.scrollHeight > cap ? 'auto' : 'hidden';\n } else {\n el.style.height = `${el.scrollHeight}px`;\n el.style.overflowY = 'hidden';\n }\n }\n}\n","<textarea\n #native\n class=\"wr-textarea__native\"\n [attr.id]=\"controlId()\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n [placeholder]=\"placeholder()\"\n [rows]=\"rows()\"\n [readonly]=\"readonly()\"\n [disabled]=\"disabled()\"\n [attr.aria-invalid]=\"fieldAria.ariaInvalid()\"\n [attr.aria-describedby]=\"fieldAria.describedBy()\"\n [value]=\"value()\"\n (input)=\"onInput($event)\"\n (focus)=\"focused.set(true)\"\n (blur)=\"onBlur()\"\n></textarea>\n\n@if (showHandle()) {\n <!-- Custom corner grip — the lucide icon + cursor follow the `resize`\n direction. Icons inlined so no icon registration is required. -->\n <span\n [class]=\"`wr-textarea__resize wr-textarea__resize--${effectiveResize()}`\"\n aria-hidden=\"true\"\n (pointerdown)=\"startResize($event)\"\n (pointermove)=\"onResize($event)\"\n (pointerup)=\"endResize($event)\"\n (pointercancel)=\"endResize($event)\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n @switch (effectiveResize()) {\n @case ('vertical') {\n <path d=\"M12 2v20\" />\n <path d=\"m8 18 4 4 4-4\" />\n <path d=\"m8 6 4-4 4 4\" />\n }\n @case ('horizontal') {\n <path d=\"M2 12h20\" />\n <path d=\"m18 8 4 4-4 4\" />\n <path d=\"m6 8-4 4 4 4\" />\n }\n @default {\n <path d=\"M19 13v6h-6\" />\n <path d=\"M5 11V5h6\" />\n <path d=\"m5 5 14 14\" />\n }\n }\n </svg>\n </span>\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ngwr-textarea.mjs","sources":["../../../projects/lib/textarea/textarea.ts","../../../projects/lib/textarea/textarea.html","../../../projects/lib/textarea/ngwr-textarea.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 { isPlatformBrowser } from '@angular/common';\nimport {\n Component,\n ElementRef,\n PLATFORM_ID,\n ViewEncapsulation,\n computed,\n effect,\n inject,\n input,\n model,\n output,\n signal,\n viewChild,\n} from '@angular/core';\nimport type { FormValueControl } from '@angular/forms/signals';\n\nimport { useConfigValue } from 'ngwr/config';\nimport { WR_FORM_FIELD, useFormFieldAria } from 'ngwr/form';\n\n/**\n * Multi-line text input.\n *\n * A signal-forms native control: it implements `FormValueControl<string>`, so\n * `[formField]` binds straight to its `value` model — no\n * `ControlValueAccessor` in between. `[(value)]` works standalone.\n *\n * Optional `autosize` grows the textarea with its content, capped at\n * `maxRows` if provided.\n *\n * @example\n * ```html\n * <!-- signal forms -->\n * <wr-textarea placeholder=\"Notes\" [formField]=\"form.notes\" />\n *\n * <!-- standalone two-way binding -->\n * <wr-textarea autosize [maxRows]=\"6\" [(value)]=\"text\" />\n * ```\n *\n * @see https://ngwr.dev/reference/components/textarea\n */\nexport type WrTextareaSize = 'sm' | 'md' | 'lg';\n\nexport type WrTextareaResize = 'none' | 'vertical' | 'horizontal' | 'both';\n\n@Component({\n selector: 'wr-textarea',\n templateUrl: './textarea.html',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n})\nexport class WrTextarea implements FormValueControl<string> {\n /** Native placeholder text. @default '' */\n readonly placeholder = input<string>('');\n\n /**\n * Accessible name for the field. Falls back to the placeholder — the native\n * `<textarea>` lives inside the component, so a `<label for>` outside cannot\n * reach it.\n */\n readonly ariaLabel = input<string | null>(null);\n\n protected readonly resolvedAriaLabel = computed(() => {\n // Not `??`: an empty placeholder is no name at all, so it must fall through.\n const explicit = this.ariaLabel();\n if (explicit) return explicit;\n const placeholder = this.placeholder();\n return placeholder ? placeholder : null;\n });\n\n /**\n * Control size — shares the `--wr-control-*` contract. Unset, it falls back to\n * `provideWrConfig({ textarea: { size } })`. @default 'md'\n */\n readonly size = input<WrTextareaSize | null>(null);\n\n // `null` as the input's own default, not `'md'`: with a literal sitting there,\n // \"the template said nothing\" and \"the template said md\" are the same value, so no\n // app-wide default could ever apply. The effective default is the last argument\n // below, which is where the old inline one moved to.\n protected readonly resolvedSize = useConfigValue(this.size, c => c.textarea?.size, 'md');\n\n /** Visible row count. @default 3 */\n readonly rows = input(3, { transform: (v: unknown): number => coerceNumberProperty(v, 3) });\n\n /** Allow user resize via the corner grip. @default true */\n readonly resizable = input(true, { transform: coerceBooleanProperty });\n\n /** Resize direction of the corner grip (the grip icon adapts). @default 'vertical' */\n readonly resize = input<WrTextareaResize>('vertical');\n\n /** Read-only state. @default false */\n readonly readonly = input(false, { transform: coerceBooleanProperty });\n\n /** Grow the textarea to fit its content. @default false */\n readonly autosize = input(false, { transform: coerceBooleanProperty });\n\n /** Cap autosize at this many rows. Ignored when `autosize` is false. */\n readonly maxRows = input<number | null>(null);\n\n /**\n * Disable the textarea. Bound automatically from the field's disabled state\n * when used with `[formField]`.\n *\n * @default false\n */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n /** The edited text. Bound by `[formField]`, or two-way via `[(value)]`. */\n readonly value = model<string>('');\n\n /** Emitted on blur so a bound field can mark itself touched. */\n readonly touch = output<void>();\n\n protected readonly focused = signal(false);\n\n protected readonly native = viewChild.required<ElementRef<HTMLTextAreaElement>>('native');\n\n /** Resize direction, gated by `resizable` (false → 'none'). */\n protected readonly effectiveResize = computed<WrTextareaResize>(() => (this.resizable() ? this.resize() : 'none'));\n\n /** The surrounding `<wr-form-field>`'s error state. @internal */\n protected readonly fieldAria = useFormFieldAria();\n\n private readonly field = inject(WR_FORM_FIELD, { optional: true });\n\n /**\n * Id the surrounding `<wr-form-field>`'s `<label for>` points at.\n *\n * The field renders its label before it can see what was projected into it, so\n * the id travels the other way and the control adopts it, exactly as\n * `[wrInput]` and `wr-select` do. Without it the `for` named an element that\n * was nowhere in the document: clicking the label did nothing, and the field\n * was, to a screen reader, an unlabelled block.\n *\n * It lands on the native `<textarea>` rather than on the host, because only a\n * labelable element can be a label's target and `<wr-textarea>` is not one.\n *\n * What it does NOT change is the NAME: `aria-label` outranks a `<label>` in\n * the accname order and `resolvedAriaLabel()` still wins, the same call\n * `wr-select` and `wr-slider` make — the field renders a label only when its\n * `label` input is set, so it cannot promise a name to fall back on. Set\n * `[ariaLabel]` to the field's label where the two should read alike.\n */\n protected readonly controlId = computed(() => this.field?.controlId() ?? null);\n\n protected readonly classes = computed(() => {\n const parts = ['wr-textarea'];\n const size = this.resolvedSize();\n if (size !== 'md') parts.push(`wr-textarea--${size}`);\n if (this.autosize()) parts.push('wr-textarea--no-resize');\n const resize = this.effectiveResize();\n if (resize === 'horizontal' || resize === 'both') parts.push('wr-textarea--resize-x');\n if (this.focused()) parts.push('wr-textarea--focused');\n if (this.disabled()) parts.push('wr-textarea--disabled');\n return parts.join(' ');\n });\n\n /** Show the corner grip (hidden when direction is 'none' / autosize / disabled). */\n protected readonly showHandle = computed(\n () => this.effectiveResize() !== 'none' && !this.autosize() && !this.disabled()\n );\n\n private readonly platformId = inject(PLATFORM_ID);\n private readonly isBrowser = isPlatformBrowser(this.platformId);\n private readonly hostEl = inject<ElementRef<HTMLElement>>(ElementRef);\n\n /**\n * Ambient reading direction, read by the horizontal half of the resize drag.\n *\n * Optional so a bare `TestBed` — or any consumer that never set a direction —\n * needs no provider; `Directionality` is root-provided, so `null` only ever\n * means \"nobody asked\", which is LTR. Read inside the handler rather than\n * cached, so a runtime flip needs no subscription to `Directionality.change`.\n */\n private readonly dir = inject(Directionality, { optional: true });\n\n // Custom resize-grip drag state (replaces the native corner handle).\n private resizing = false;\n private resizeStartY = 0;\n private resizeStartX = 0;\n private resizeStartHeight = 0;\n private resizeStartWidth = 0;\n private resizeMinHeight = 36;\n private resizeMaxWidth = Number.POSITIVE_INFINITY;\n\n constructor() {\n // Autosize: re-fit whenever value or autosize toggles.\n effect(() => {\n if (!this.isBrowser) return;\n if (!this.autosize()) {\n // Hand the height back. Left behind, the field stays frozen at whatever\n // was last fitted and `rows` silently stops meaning anything, which reads\n // as the input having done nothing.\n this.releaseHeight();\n return;\n }\n // Read `value` to register dependency\n this.value();\n requestAnimationFrame(() => this.autofit());\n });\n }\n\n // Template handlers\n\n protected onInput(event: Event): void {\n this.value.set((event.target as HTMLTextAreaElement).value);\n }\n\n protected onBlur(): void {\n this.focused.set(false);\n this.touch.emit();\n }\n\n // Custom resize — drag the corner grip; direction comes from `effectiveResize`.\n // Pointer capture keeps move/up on the grip even when the cursor leaves it.\n protected startResize(event: PointerEvent): void {\n const el = this.native()?.nativeElement;\n if (!el) return;\n const host = this.hostEl.nativeElement;\n this.resizing = true;\n this.resizeStartY = event.clientY;\n this.resizeStartX = event.clientX;\n this.resizeStartHeight = el.offsetHeight;\n this.resizeStartWidth = host.offsetWidth;\n // Height floor = fits the current content, so shrinking never opens an\n // overflow scrollbar. Measured once, synchronously (no paint between).\n const borderY = el.offsetHeight - el.clientHeight;\n const prevHeight = el.style.height;\n el.style.height = 'auto';\n this.resizeMinHeight = el.scrollHeight + borderY;\n el.style.height = prevHeight;\n // Width ceiling = parent inner width, so horizontal drag can't overflow.\n this.resizeMaxWidth = host.parentElement?.clientWidth ?? Number.POSITIVE_INFINITY;\n (event.target as HTMLElement).setPointerCapture(event.pointerId);\n event.preventDefault();\n }\n\n protected onResize(event: PointerEvent): void {\n if (!this.resizing) return;\n const el = this.native()?.nativeElement;\n if (!el) return;\n const dir = this.effectiveResize();\n if (dir === 'vertical' || dir === 'both') {\n const h = Math.max(this.resizeMinHeight, this.resizeStartHeight + (event.clientY - this.resizeStartY));\n el.style.height = `${h}px`;\n }\n if (dir === 'horizontal' || dir === 'both') {\n // The grip sits at the field's INLINE END — physically bottom-right in LTR,\n // bottom-left in RTL, where a block-level box grows because it is anchored\n // at the right edge of its containing block. So the pointer's physical\n // delta means \"wider\" in one direction and \"narrower\" in the other, and the\n // sign has to follow the reading direction. It did not, so under `dir=\"rtl\"`\n // the grip sat on the corner the box does NOT extend toward and dragging it\n // outward shrank the field.\n const dx = event.clientX - this.resizeStartX;\n const inline = this.dir?.value === 'rtl' ? -dx : dx;\n const w = Math.min(this.resizeMaxWidth, Math.max(64, this.resizeStartWidth + inline));\n this.hostEl.nativeElement.style.width = `${w}px`;\n }\n }\n\n protected endResize(event: PointerEvent): void {\n if (!this.resizing) return;\n this.resizing = false;\n (event.target as HTMLElement).releasePointerCapture(event.pointerId);\n }\n\n private releaseHeight(): void {\n const el = this.native()?.nativeElement;\n if (!el) return;\n el.style.height = '';\n el.style.overflowY = '';\n }\n\n private autofit(): void {\n const el = this.native()?.nativeElement;\n if (!el) return;\n // A frame can outlive the reason it was scheduled: toggling `autosize` off\n // between the effect and the frame would otherwise fit a height nobody asked\n // for, and `releaseHeight` has already run by then.\n if (!this.autosize()) return;\n el.style.height = 'auto';\n\n const maxRows = this.maxRows();\n if (maxRows && maxRows > 0) {\n const cs = getComputedStyle(el);\n const lineHeight = parseFloat(cs.lineHeight) || parseFloat(cs.fontSize) * 1.2;\n const cap = lineHeight * maxRows;\n const next = Math.min(el.scrollHeight, cap);\n el.style.height = `${next}px`;\n el.style.overflowY = el.scrollHeight > cap ? 'auto' : 'hidden';\n } else {\n el.style.height = `${el.scrollHeight}px`;\n el.style.overflowY = 'hidden';\n }\n }\n}\n","<textarea\n #native\n class=\"wr-textarea__native\"\n [attr.id]=\"controlId()\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n [placeholder]=\"placeholder()\"\n [rows]=\"rows()\"\n [readonly]=\"readonly()\"\n [disabled]=\"disabled()\"\n [attr.aria-invalid]=\"fieldAria.ariaInvalid()\"\n [attr.aria-describedby]=\"fieldAria.describedBy()\"\n [value]=\"value()\"\n (input)=\"onInput($event)\"\n (focus)=\"focused.set(true)\"\n (blur)=\"onBlur()\"\n></textarea>\n\n@if (showHandle()) {\n <!-- Custom corner grip — the lucide icon + cursor follow the `resize`\n direction. Icons inlined so no icon registration is required. -->\n <span\n [class]=\"`wr-textarea__resize wr-textarea__resize--${effectiveResize()}`\"\n aria-hidden=\"true\"\n (pointerdown)=\"startResize($event)\"\n (pointermove)=\"onResize($event)\"\n (pointerup)=\"endResize($event)\"\n (pointercancel)=\"endResize($event)\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n @switch (effectiveResize()) {\n @case ('vertical') {\n <path d=\"M12 2v20\" />\n <path d=\"m8 18 4 4 4-4\" />\n <path d=\"m8 6 4-4 4 4\" />\n }\n @case ('horizontal') {\n <path d=\"M2 12h20\" />\n <path d=\"m18 8 4 4-4 4\" />\n <path d=\"m6 8-4 4 4 4\" />\n }\n @default {\n <path d=\"M19 13v6h-6\" />\n <path d=\"M5 11V5h6\" />\n <path d=\"m5 5 14 14\" />\n }\n }\n </svg>\n </span>\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -359,10 +359,10 @@ class WrTheme {
359
359
  return;
360
360
  this.storage.set(this.config.storageKey, mode);
361
361
  }
362
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrTheme, deps: [], target: i0.ɵɵFactoryTarget.Service });
363
- static ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.6", ngImport: i0, type: WrTheme });
362
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrTheme, deps: [], target: i0.ɵɵFactoryTarget.Service });
363
+ static ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.7", ngImport: i0, type: WrTheme });
364
364
  }
365
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrTheme, decorators: [{
365
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrTheme, decorators: [{
366
366
  type: Service
367
367
  }], ctorParameters: () => [] });
368
368
 
@@ -1 +1 @@
1
- {"version":3,"file":"ngwr-theme.mjs","sources":["../../../projects/lib/theme/colors.ts","../../../projects/lib/theme/palette.ts","../../../projects/lib/theme/wr-theme-config.ts","../../../projects/lib/theme/services/wr-theme.ts","../../../projects/lib/theme/provide-wr-theme.ts","../../../projects/lib/theme/pre-paint.ts","../../../projects/lib/theme/ngwr-theme.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\n/**\n * Built-in color variants available to NGWR components.\n *\n * Kept in sync manually with the SCSS `$base-colors` map in\n * `theme/styles/_colors.scss`. Both sources must stay aligned —\n * adding a color requires updating both this array and the SCSS map.\n * Nothing enforces that, and it has already drifted once: `info` landed\n * in the map without landing here, so v8.0.0 shipped every\n * `--wr-color-info*` token — plus an `--info` modifier from each of the\n * five stylesheets that iterate the map — while this type refused the\n * value. Order matches the map so the two read as one list.\n *\n * @example\n * ```ts\n * import { WR_COLORS } from 'ngwr/theme';\n *\n * // Iterate all colors for demos or documentation\n * WR_COLORS.forEach(color => console.log(color));\n * ```\n */\nexport const WR_COLORS = [\n 'primary',\n 'secondary',\n 'success',\n 'warning',\n 'danger',\n 'info',\n 'light',\n 'medium',\n 'dark',\n] as const;\n\n/**\n * A color variant name.\n *\n * Use as an input type on components that accept a color:\n *\n * @example\n * ```ts\n * import type { WrColor } from 'ngwr/theme';\n *\n * @Component({...})\n * export class MyComponent {\n * readonly color = input<WrColor>('primary');\n * }\n * ```\n */\nexport type WrColor = (typeof WR_COLORS)[number];\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\n/**\n * The palette recipe, in TypeScript.\n *\n * `theme/styles/_colors.scss` derives seven tokens per intent from one hex, and\n * until now that arithmetic existed only in Sass — so a theme picked at RUNTIME\n * (a builder, a tenant colour from an API, a preset fetched from a registry)\n * could not reproduce it. The showcase had half of it copied by hand for its\n * own primary-colour switcher, which is the copy that drifts.\n *\n * **Seven tokens, not twelve, and that is not an omission.** The tint and ink\n * layer is written in terms of `var()`:\n *\n * ```css\n * --wr-color-primary-soft: rgba(var(--wr-color-primary-rgb), 0.12);\n * --wr-color-primary-ink: color-mix(in srgb, var(--wr-color-primary) 78%, var(--wr-color-dark));\n * ```\n *\n * so redefining the base and its channels re-resolves `-soft`, `-soft-border`,\n * `-soft-contrast`, `-active` and `-ink` for free. A preset that also emitted\n * those would be freezing values the stylesheet is meant to keep deriving.\n *\n * **`-contrast` IS re-derived, and must be.** It picks whichever of black and\n * white scores higher against the fill, so a re-tuned intent keeps the label of\n * the colour it replaced unless something recomputes it — that is how the dark\n * theme once put white text on its lightened primary at 3.36:1.\n *\n * The LIGHT recipe only. `_dark.scss` is hand-tuned rather than derived — its\n * `dark-light` uses `color.scale(…, 70%)` where the light block uses\n * `color.adjust(…, 5%)`, and `light-light` goes -2.5% — so a generator claiming\n * to reproduce it would be lying. Feed dark seeds through the same recipe if you\n * want a derived dark theme; you will get a consistent one, not the shipped one.\n *\n * `pnpm check:theme` compiles nothing and trusts nothing: it reads the BUILT\n * stylesheet and asserts this module reproduces every one of those tokens for\n * the nine shipped intents.\n *\n * @example\n * ```ts\n * import { wrThemeTokens } from 'ngwr/theme';\n *\n * const tokens = wrThemeTokens({ primary: '#41598f' });\n * for (const [name, value] of Object.entries(tokens)) {\n * document.documentElement.style.setProperty(name, value);\n * }\n * ```\n */\n\nimport { WR_COLORS, type WrColor } from './colors';\n\n/** Lightness deltas, in PERCENTAGE POINTS, matching `color.adjust` in the SCSS. */\nconst SHADES = [\n ['dark', -5],\n ['darker', -10],\n ['light', 5],\n ['lighter', 10],\n] as const;\n\ninterface Rgb {\n readonly r: number;\n readonly g: number;\n readonly b: number;\n}\n\n/** `#rgb` / `#rrggbb` → channels. Returns `null` for anything else. */\nfunction parseHex(hex: string): Rgb | null {\n const raw = hex.trim().replace(/^#/, '');\n const full = raw.length === 3 ? [...raw].map(c => c + c).join('') : raw;\n if (!/^[0-9a-fA-F]{6}$/.test(full)) return null;\n const n = Number.parseInt(full, 16);\n /* eslint-disable no-bitwise -- unpacking a packed 24-bit colour */\n return { r: (n >> 16) & 255, g: (n >> 8) & 255, b: n & 255 };\n /* eslint-enable no-bitwise */\n}\n\nconst toHex = ({ r, g, b }: Rgb): string =>\n `#${[r, g, b].map(c => Math.round(c).toString(16).padStart(2, '0')).join('')}`;\n\nfunction rgbToHsl({ r, g, b }: Rgb): { h: number; s: number; l: number } {\n const rn = r / 255;\n const gn = g / 255;\n const bn = b / 255;\n const max = Math.max(rn, gn, bn);\n const min = Math.min(rn, gn, bn);\n const d = max - min;\n const l = (max + min) / 2;\n if (d === 0) return { h: 0, s: 0, l };\n\n const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n let h: number;\n if (max === rn) h = (gn - bn) / d + (gn < bn ? 6 : 0);\n else if (max === gn) h = (bn - rn) / d + 2;\n else h = (rn - gn) / d + 4;\n return { h: h * 60, s, l };\n}\n\nfunction hslToRgb(h: number, s: number, l: number): Rgb {\n const c = (1 - Math.abs(2 * l - 1)) * s;\n // Two modulos, not one. `((h % 360) + 360) / 60` reads as normalisation and\n // is not: it maps 222° to sector 9.7 instead of 3.7, so every hue landed in\n // the wrong arm of the sextant table and only greys (c = x = 0) survived.\n // The parity gate caught it on the first run — `dark`'s navy came back red.\n const hp = (((h % 360) + 360) % 360) / 60;\n const x = c * (1 - Math.abs((hp % 2) - 1));\n const [rp, gp, bp] =\n hp < 1 ? [c, x, 0] : hp < 2 ? [x, c, 0] : hp < 3 ? [0, c, x] : hp < 4 ? [0, x, c] : hp < 5 ? [x, 0, c] : [c, 0, x];\n const m = l - c / 2;\n return { r: (rp + m) * 255, g: (gp + m) * 255, b: (bp + m) * 255 };\n}\n\n/** One channel, linearised per WCAG 2.x — the SCSS `_linear`. */\nfunction linear(channel: number): number {\n const s = channel / 255;\n return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;\n}\n\n/** WCAG relative luminance. */\nconst luminance = ({ r, g, b }: Rgb): number => 0.2126 * linear(r) + 0.7152 * linear(g) + 0.0722 * linear(b);\n\n/** WCAG contrast ratio between two colours. */\nfunction ratio(a: Rgb, b: Rgb): number {\n const la = luminance(a);\n const lb = luminance(b);\n return (Math.max(la, lb) + 0.05) / (Math.min(la, lb) + 0.05);\n}\n\nconst BLACK: Rgb = { r: 0, g: 0, b: 0 };\nconst WHITE: Rgb = { r: 255, g: 255, b: 255 };\n\n/**\n * The readable label ON a filled intent — whichever of black and white scores\n * higher, the SCSS `_contrast()`.\n *\n * It PICKS, it does not blend, so those two values are the ceiling for every\n * intent. The comparison is `>=`, so a colour exactly at the flip point\n * (√21 ≈ 4.58 against both) takes the dark label, matching the SCSS.\n */\nfunction wrContrastFor(hex: string): string {\n const rgb = parseHex(hex);\n if (!rgb) return '#000000';\n return ratio(rgb, BLACK) >= ratio(rgb, WHITE) ? '#000000' : '#ffffff';\n}\n\n/** Shift HSL lightness by `deltaPct` PERCENTAGE POINTS, clamped — `color.adjust`. */\nfunction adjustLightness(rgb: Rgb, deltaPct: number): Rgb {\n const { h, s, l } = rgbToHsl(rgb);\n return hslToRgb(h, s, Math.min(1, Math.max(0, l + deltaPct / 100)));\n}\n\n/**\n * The seven `--wr-color-<name>*` tokens one seed produces.\n *\n * Returns an empty record for a hex it cannot parse rather than a palette built\n * on black — a silently black theme is harder to notice than a missing one.\n *\n * `name` is a shipped intent rather than any string: a token layer the\n * stylesheet never declares has nothing reading it, and a typo would otherwise\n * emit `--wr-color-primry-*` and paint nothing.\n */\nfunction wrIntentTokens(name: WrColor, seed: string): Record<string, string> {\n const rgb = parseHex(seed);\n if (!rgb) return {};\n\n const out: Record<string, string> = {\n [`--wr-color-${name}`]: toHex(rgb),\n [`--wr-color-${name}-rgb`]: `${Math.round(rgb.r)}, ${Math.round(rgb.g)}, ${Math.round(rgb.b)}`,\n [`--wr-color-${name}-contrast`]: wrContrastFor(toHex(rgb)),\n };\n for (const [suffix, delta] of SHADES) {\n out[`--wr-color-${name}-${suffix}`] = toHex(adjustLightness(rgb, delta));\n }\n return out;\n}\n\n/**\n * Every token a theme preset needs, for as many intents as it re-tunes.\n *\n * Intents left out keep the values the stylesheet compiled, so a preset that\n * only moves `primary` writes seven declarations and nothing else.\n */\nfunction wrThemeTokens(seeds: Partial<Record<WrColor, string>>): Record<string, string> {\n const out: Record<string, string> = {};\n for (const name of WR_COLORS) {\n const seed = seeds[name];\n if (seed) Object.assign(out, wrIntentTokens(name, seed));\n }\n return out;\n}\n\nexport { wrContrastFor, wrIntentTokens, wrThemeTokens };\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { InjectionToken } from '@angular/core';\n\n/** Mode the user explicitly selected. `auto` follows `prefers-color-scheme`. */\nexport type WrThemeMode = 'light' | 'dark' | 'auto';\n\n/** Resolved theme — what's actually applied to the DOM. */\nexport type WrResolvedTheme = 'light' | 'dark';\n\n/** Configuration for {@link WrTheme}. */\nexport interface WrThemeConfig {\n /** Initial mode used when no persisted value is present. @default 'auto' */\n readonly defaultMode: WrThemeMode;\n /** localStorage key for persistence. Set to `null` to disable persistence. @default 'wr-theme' */\n readonly storageKey: string | null;\n /** Attribute applied to `<html>` to expose the resolved theme. @default 'data-theme' */\n readonly attribute: string;\n}\n\nexport const DEFAULT_WR_THEME_CONFIG: WrThemeConfig = {\n defaultMode: 'auto',\n storageKey: 'wr-theme',\n attribute: 'data-theme',\n};\n\nexport const WR_THEME_CONFIG = new InjectionToken<WrThemeConfig>('WR_THEME_CONFIG', {\n factory: (): WrThemeConfig => DEFAULT_WR_THEME_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 { DOCUMENT } from '@angular/common';\nimport { Service, type Signal, afterNextRender, computed, effect, inject, isDevMode, signal } from '@angular/core';\n\nimport { WrPlatform } from 'ngwr/platform';\nimport { WrStorage } from 'ngwr/storage';\n\nimport { WR_THEME_CONFIG, type WrResolvedTheme, type WrThemeMode } from '../wr-theme-config';\n\nconst VALID_MODES: readonly WrThemeMode[] = ['light', 'dark', 'auto'];\n\nfunction isThemeMode(v: unknown): v is WrThemeMode {\n return typeof v === 'string' && (VALID_MODES as readonly string[]).includes(v);\n}\n\n/**\n * Light / dark theme manager.\n *\n * - `mode` is what the user picked (`light` | `dark` | `auto`).\n * - `resolved` is what's actually applied — `auto` resolves through\n * {@link WrPlatform.prefersDark}.\n * - Writes `[data-theme]` (or your configured attribute) on `<html>`.\n * - Persists the selected mode via {@link WrStorage} (defaults to\n * `localStorage`; swap the storage engine globally to change where).\n *\n * A configured `attribute` has to be given to the STYLESHEET too — a CSS\n * selector cannot read a provider value — so pair it with\n * `@use 'ngwr' with ($theme-attribute: '...')`. In dev mode the service compares\n * the two and warns when they disagree.\n *\n * **Under SSR or prerendering this service cannot prevent a flash of the wrong\n * theme, and nothing inside the application can.** The server has no\n * `localStorage` and no `prefers-color-scheme`, so every rendered page ships the\n * same attribute (`light` under the default config); by the time the client\n * bundle boots and the effect below corrects it, the browser has already\n * painted. Closing that window takes a script that runs before first paint —\n * {@link wrThemePrePaintScript} emits one that reads the persisted mode exactly\n * the way this service does.\n *\n * @example\n * ```ts\n * const theme = inject(WrTheme);\n * theme.set('dark');\n * theme.toggle();\n * theme.resolved(); // 'dark'\n * ```\n *\n * @see https://ngwr.dev/reference/services/theme\n */\n@Service()\nexport class WrTheme {\n private readonly doc = inject(DOCUMENT);\n private readonly platform = inject(WrPlatform);\n private readonly storage = inject(WrStorage);\n private readonly config = inject(WR_THEME_CONFIG);\n\n /** User-selected mode. */\n readonly mode = signal<WrThemeMode>(this.readPersisted() ?? this.config.defaultMode);\n\n /** Resolved theme actually applied to the DOM. */\n readonly resolved: Signal<WrResolvedTheme> = computed(() => {\n const m = this.mode();\n if (m === 'auto') return this.platform.prefersDark() ? 'dark' : 'light';\n return m;\n });\n\n constructor() {\n // Whenever the resolved theme changes, mirror it to the DOM + persist mode.\n effect(() => {\n const value = this.resolved();\n const html = this.doc.documentElement;\n if (html) html.setAttribute(this.config.attribute, value);\n this.persist(this.mode());\n });\n\n if (isDevMode() && this.platform.isBrowser) {\n // After render, so nothing here is constructor-time DOM access — and so\n // the stylesheet has had its chance to apply.\n afterNextRender(() => this.warnOnAttributeMismatch());\n }\n }\n\n /** Switch to a specific mode. */\n set(mode: WrThemeMode): void {\n this.mode.set(mode);\n }\n\n /** Cycle: light → dark → light (skips auto). */\n toggle(): void {\n this.mode.set(this.resolved() === 'dark' ? 'light' : 'dark');\n }\n\n /**\n * Dev-mode check that the STYLESHEET keys on the same attribute this service\n * writes.\n *\n * `attribute` is a runtime value and a CSS selector cannot read one, so the\n * dark block is keyed on a Sass variable (`$theme-attribute`) the consumer\n * configures separately. That makes disagreement possible, and disagreement is\n * silent in the worst way: the service resolves `dark`, writes the attribute,\n * reports success — and the page stays light forever, because nothing matches.\n *\n * The compiled theme publishes the name it keys on as `--wr-theme-attribute`,\n * which is what this reads. An empty value means no ngwr stylesheet is loaded\n * (a unit test, a consumer bundling their own CSS) or that it predates v13, so\n * the check stays quiet — it can only fire on a real mismatch, never on an\n * absence it cannot interpret.\n *\n * Production builds drop the call entirely via `isDevMode()` tree-shaking.\n */\n private warnOnAttributeMismatch(): void {\n const view = this.doc.defaultView;\n if (!view) return;\n\n const declared = view.getComputedStyle(this.doc.documentElement).getPropertyValue('--wr-theme-attribute').trim();\n if (!declared || declared === this.config.attribute) return;\n\n // eslint-disable-next-line no-console -- dev-mode validation\n console.warn(\n `[NGWR] Theme attribute mismatch: provideWrTheme({ attribute: '${this.config.attribute}' }) ` +\n `but the stylesheet keys its dark block on '${declared}'. Dark mode will never apply. ` +\n `Configure both: @use 'ngwr' with ($theme-attribute: '${this.config.attribute}');`\n );\n }\n\n // Persistence\n\n private readPersisted(): WrThemeMode | null {\n if (!this.config.storageKey) return null;\n const raw = this.storage.get<WrThemeMode>(this.config.storageKey);\n return isThemeMode(raw) ? raw : null;\n }\n\n private persist(mode: WrThemeMode): void {\n if (!this.config.storageKey) return;\n this.storage.set(this.config.storageKey, mode);\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 {\n type EnvironmentProviders,\n inject,\n makeEnvironmentProviders,\n provideEnvironmentInitializer,\n} from '@angular/core';\n\nimport { WrTheme } from './services/wr-theme';\nimport { DEFAULT_WR_THEME_CONFIG, WR_THEME_CONFIG, type WrThemeConfig } from './wr-theme-config';\n\n/**\n * Configure and activate {@link WrTheme}. Config is partial — merged with\n * defaults.\n *\n * Calling this is all it takes: the initializer instantiates {@link WrTheme},\n * whose constructor effect mirrors the resolved theme onto `<html>`. Without\n * that, the service (a tree-shakable `@Service()`) would only be created once\n * something injected it, so `[data-theme]` was never written and an app that\n * followed the docs silently ignored `defaultMode: 'auto'`.\n *\n * @example\n * ```ts\n * provideWrTheme({ defaultMode: 'dark', storageKey: 'my-app-theme' })\n * ```\n */\nexport function provideWrTheme(config: Partial<WrThemeConfig> = {}): EnvironmentProviders {\n const merged: WrThemeConfig = { ...DEFAULT_WR_THEME_CONFIG, ...config };\n return makeEnvironmentProviders([\n { provide: WR_THEME_CONFIG, useValue: merged },\n provideEnvironmentInitializer(() => void inject(WrTheme)),\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 { DEFAULT_WR_THEME_CONFIG, type WrThemeMode } from './wr-theme-config';\n\n/** Options for {@link wrThemePrePaintScript}. All optional — defaults mirror the services. */\nexport interface WrThemePrePaintOptions {\n /**\n * The key {@link WrTheme} persists the mode under — `provideWrTheme({ storageKey })`.\n * @default 'wr-theme'\n */\n readonly storageKey?: string;\n /**\n * The attribute written on `<html>` — `provideWrTheme({ attribute })`, which\n * has to agree with `@use 'ngwr' with ($theme-attribute: '…')`.\n * @default 'data-theme'\n */\n readonly attribute?: string;\n /**\n * What to resolve when nothing is persisted — `provideWrTheme({ defaultMode })`.\n * @default 'auto'\n */\n readonly defaultMode?: WrThemeMode;\n /**\n * `WrStorage`'s key prefix — `provideWrStorage({ prefix })`. The script reads\n * the raw key, so a prefixed app has to pass the same string here.\n * @default ''\n */\n readonly storagePrefix?: string;\n /**\n * Whether `WrStorage` wraps values in its JSON envelope —\n * `provideWrStorage({ json })`. The emitted reader accepts both shapes either\n * way; this only decides which one it tries first, and is here so the option\n * cannot be silently forgotten when an app turns the envelope off.\n * @default true\n */\n readonly json?: boolean;\n}\n\n/**\n * Source of the blocking script that resolves the theme BEFORE first paint.\n *\n * A server has no `localStorage` and no `prefers-color-scheme`, so every\n * server-rendered or prerendered page ships the same attribute — `light` under\n * the default config — and a dark-mode visitor sees a white page until the\n * client bundle boots and {@link WrTheme}'s effect corrects it. That window is\n * milliseconds on localhost and seconds on a slow connection, and it is not\n * something the service can close from inside the application: by the time\n * Angular runs, the paint has happened.\n *\n * The only fix is a script that runs before the first paint, and the only thing\n * it needs to know is how {@link WrTheme} and `WrStorage` agree to spell the\n * persisted mode. That agreement — the key, the prefix, the JSON envelope\n * `{ v, e }`, the expiry, the `auto` fallback — is what this function writes\n * out, so an app never has to re-derive it from the bundle and never has to keep\n * a hand-copied version in step with a library upgrade.\n *\n * Returns the JS source WITHOUT a `<script>` wrapper, so it can be inlined into\n * `index.html`, emitted from an SSR template, or hashed for a CSP\n * `script-src 'sha256-…'`. It is plain ES5 with no dependency on the app bundle,\n * and every step is wrapped so a blocked `localStorage` (private mode, a\n * sandboxed iframe) leaves the prerendered default in place rather than throwing\n * before anything has rendered.\n *\n * Pass the same values given to `provideWrTheme()` / `provideWrStorage()`; the\n * defaults here are the defaults there.\n *\n * @example\n * ```ts\n * // Build step / SSR template:\n * const html = template.replace('<!--theme-->', `<script>${wrThemePrePaintScript()}</script>`);\n *\n * // Or paste the output straight into <head>, above every stylesheet:\n * // <script>(function(){ … })();</script>\n * ```\n *\n * @see https://ngwr.dev/reference/services/theme\n */\nexport function wrThemePrePaintScript(options: WrThemePrePaintOptions = {}): string {\n const key = (options.storagePrefix ?? '') + (options.storageKey ?? DEFAULT_WR_THEME_CONFIG.storageKey ?? 'wr-theme');\n const attribute = options.attribute ?? DEFAULT_WR_THEME_CONFIG.attribute;\n const defaultMode = options.defaultMode ?? DEFAULT_WR_THEME_CONFIG.defaultMode;\n const json = options.json ?? true;\n\n // Every interpolated value goes through JSON.stringify rather than into a\n // quoted literal: a key or an attribute name is a configuration string, and a\n // hand-rolled `'${x}'` turns an apostrophe in one into a syntax error at best.\n const k = JSON.stringify(key);\n const a = JSON.stringify(attribute);\n const d = JSON.stringify(defaultMode);\n\n // Reading the envelope mirrors `WrStorage.get`, including its fall-throughs:\n // an unparseable string is returned verbatim (that is what `json: false`\n // writes), a parsed non-envelope is the value itself, and an envelope past its\n // `e` expiry counts as absent. `json: false` skips the parse entirely, which\n // is the same answer by a shorter path.\n const read = json\n ? `try{var p=JSON.parse(r);` +\n `if(p!==null&&typeof p===\"object\"&&\"v\" in p){if(p.e===undefined||p.e>=Date.now())m=p.v;}` +\n `else{m=p;}}catch(e){m=r;}`\n : `m=r;`;\n\n return (\n `(function(){try{` +\n `var m=null,r=null;` +\n `try{r=window.localStorage.getItem(${k});}catch(e){}` +\n `if(r!==null){${read}}` +\n `if(m!==\"light\"&&m!==\"dark\"&&m!==\"auto\")m=${d};` +\n `var dark=m===\"dark\"||(m===\"auto\"&&typeof window.matchMedia===\"function\"&&` +\n `window.matchMedia(\"(prefers-color-scheme: dark)\").matches);` +\n `document.documentElement.setAttribute(${a},dark?\"dark\":\"light\");` +\n `}catch(e){}})();`\n );\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ngwr-theme.mjs","sources":["../../../projects/lib/theme/colors.ts","../../../projects/lib/theme/palette.ts","../../../projects/lib/theme/wr-theme-config.ts","../../../projects/lib/theme/services/wr-theme.ts","../../../projects/lib/theme/provide-wr-theme.ts","../../../projects/lib/theme/pre-paint.ts","../../../projects/lib/theme/ngwr-theme.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\n/**\n * Built-in color variants available to NGWR components.\n *\n * Kept in sync manually with the SCSS `$base-colors` map in\n * `theme/styles/_colors.scss`. Both sources must stay aligned —\n * adding a color requires updating both this array and the SCSS map.\n * Nothing enforces that, and it has already drifted once: `info` landed\n * in the map without landing here, so v8.0.0 shipped every\n * `--wr-color-info*` token — plus an `--info` modifier from each of the\n * five stylesheets that iterate the map — while this type refused the\n * value. Order matches the map so the two read as one list.\n *\n * @example\n * ```ts\n * import { WR_COLORS } from 'ngwr/theme';\n *\n * // Iterate all colors for demos or documentation\n * WR_COLORS.forEach(color => console.log(color));\n * ```\n */\nexport const WR_COLORS = [\n 'primary',\n 'secondary',\n 'success',\n 'warning',\n 'danger',\n 'info',\n 'light',\n 'medium',\n 'dark',\n] as const;\n\n/**\n * A color variant name.\n *\n * Use as an input type on components that accept a color:\n *\n * @example\n * ```ts\n * import type { WrColor } from 'ngwr/theme';\n *\n * @Component({...})\n * export class MyComponent {\n * readonly color = input<WrColor>('primary');\n * }\n * ```\n */\nexport type WrColor = (typeof WR_COLORS)[number];\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\n/**\n * The palette recipe, in TypeScript.\n *\n * `theme/styles/_colors.scss` derives seven tokens per intent from one hex, and\n * until now that arithmetic existed only in Sass — so a theme picked at RUNTIME\n * (a builder, a tenant colour from an API, a preset fetched from a registry)\n * could not reproduce it. The showcase had half of it copied by hand for its\n * own primary-colour switcher, which is the copy that drifts.\n *\n * **Seven tokens, not twelve, and that is not an omission.** The tint and ink\n * layer is written in terms of `var()`:\n *\n * ```css\n * --wr-color-primary-soft: rgba(var(--wr-color-primary-rgb), 0.12);\n * --wr-color-primary-ink: color-mix(in srgb, var(--wr-color-primary) 78%, var(--wr-color-dark));\n * ```\n *\n * so redefining the base and its channels re-resolves `-soft`, `-soft-border`,\n * `-soft-contrast`, `-active` and `-ink` for free. A preset that also emitted\n * those would be freezing values the stylesheet is meant to keep deriving.\n *\n * **`-contrast` IS re-derived, and must be.** It picks whichever of black and\n * white scores higher against the fill, so a re-tuned intent keeps the label of\n * the colour it replaced unless something recomputes it — that is how the dark\n * theme once put white text on its lightened primary at 3.36:1.\n *\n * The LIGHT recipe only. `_dark.scss` is hand-tuned rather than derived — its\n * `dark-light` uses `color.scale(…, 70%)` where the light block uses\n * `color.adjust(…, 5%)`, and `light-light` goes -2.5% — so a generator claiming\n * to reproduce it would be lying. Feed dark seeds through the same recipe if you\n * want a derived dark theme; you will get a consistent one, not the shipped one.\n *\n * `pnpm check:theme` compiles nothing and trusts nothing: it reads the BUILT\n * stylesheet and asserts this module reproduces every one of those tokens for\n * the nine shipped intents.\n *\n * @example\n * ```ts\n * import { wrThemeTokens } from 'ngwr/theme';\n *\n * const tokens = wrThemeTokens({ primary: '#41598f' });\n * for (const [name, value] of Object.entries(tokens)) {\n * document.documentElement.style.setProperty(name, value);\n * }\n * ```\n */\n\nimport { WR_COLORS, type WrColor } from './colors';\n\n/** Lightness deltas, in PERCENTAGE POINTS, matching `color.adjust` in the SCSS. */\nconst SHADES = [\n ['dark', -5],\n ['darker', -10],\n ['light', 5],\n ['lighter', 10],\n] as const;\n\ninterface Rgb {\n readonly r: number;\n readonly g: number;\n readonly b: number;\n}\n\n/** `#rgb` / `#rrggbb` → channels. Returns `null` for anything else. */\nfunction parseHex(hex: string): Rgb | null {\n const raw = hex.trim().replace(/^#/, '');\n const full = raw.length === 3 ? [...raw].map(c => c + c).join('') : raw;\n if (!/^[0-9a-fA-F]{6}$/.test(full)) return null;\n const n = Number.parseInt(full, 16);\n /* eslint-disable no-bitwise -- unpacking a packed 24-bit colour */\n return { r: (n >> 16) & 255, g: (n >> 8) & 255, b: n & 255 };\n /* eslint-enable no-bitwise */\n}\n\nconst toHex = ({ r, g, b }: Rgb): string =>\n `#${[r, g, b].map(c => Math.round(c).toString(16).padStart(2, '0')).join('')}`;\n\nfunction rgbToHsl({ r, g, b }: Rgb): { h: number; s: number; l: number } {\n const rn = r / 255;\n const gn = g / 255;\n const bn = b / 255;\n const max = Math.max(rn, gn, bn);\n const min = Math.min(rn, gn, bn);\n const d = max - min;\n const l = (max + min) / 2;\n if (d === 0) return { h: 0, s: 0, l };\n\n const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n let h: number;\n if (max === rn) h = (gn - bn) / d + (gn < bn ? 6 : 0);\n else if (max === gn) h = (bn - rn) / d + 2;\n else h = (rn - gn) / d + 4;\n return { h: h * 60, s, l };\n}\n\nfunction hslToRgb(h: number, s: number, l: number): Rgb {\n const c = (1 - Math.abs(2 * l - 1)) * s;\n // Two modulos, not one. `((h % 360) + 360) / 60` reads as normalisation and\n // is not: it maps 222° to sector 9.7 instead of 3.7, so every hue landed in\n // the wrong arm of the sextant table and only greys (c = x = 0) survived.\n // The parity gate caught it on the first run — `dark`'s navy came back red.\n const hp = (((h % 360) + 360) % 360) / 60;\n const x = c * (1 - Math.abs((hp % 2) - 1));\n const [rp, gp, bp] =\n hp < 1 ? [c, x, 0] : hp < 2 ? [x, c, 0] : hp < 3 ? [0, c, x] : hp < 4 ? [0, x, c] : hp < 5 ? [x, 0, c] : [c, 0, x];\n const m = l - c / 2;\n return { r: (rp + m) * 255, g: (gp + m) * 255, b: (bp + m) * 255 };\n}\n\n/** One channel, linearised per WCAG 2.x — the SCSS `_linear`. */\nfunction linear(channel: number): number {\n const s = channel / 255;\n return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;\n}\n\n/** WCAG relative luminance. */\nconst luminance = ({ r, g, b }: Rgb): number => 0.2126 * linear(r) + 0.7152 * linear(g) + 0.0722 * linear(b);\n\n/** WCAG contrast ratio between two colours. */\nfunction ratio(a: Rgb, b: Rgb): number {\n const la = luminance(a);\n const lb = luminance(b);\n return (Math.max(la, lb) + 0.05) / (Math.min(la, lb) + 0.05);\n}\n\nconst BLACK: Rgb = { r: 0, g: 0, b: 0 };\nconst WHITE: Rgb = { r: 255, g: 255, b: 255 };\n\n/**\n * The readable label ON a filled intent — whichever of black and white scores\n * higher, the SCSS `_contrast()`.\n *\n * It PICKS, it does not blend, so those two values are the ceiling for every\n * intent. The comparison is `>=`, so a colour exactly at the flip point\n * (√21 ≈ 4.58 against both) takes the dark label, matching the SCSS.\n */\nfunction wrContrastFor(hex: string): string {\n const rgb = parseHex(hex);\n if (!rgb) return '#000000';\n return ratio(rgb, BLACK) >= ratio(rgb, WHITE) ? '#000000' : '#ffffff';\n}\n\n/** Shift HSL lightness by `deltaPct` PERCENTAGE POINTS, clamped — `color.adjust`. */\nfunction adjustLightness(rgb: Rgb, deltaPct: number): Rgb {\n const { h, s, l } = rgbToHsl(rgb);\n return hslToRgb(h, s, Math.min(1, Math.max(0, l + deltaPct / 100)));\n}\n\n/**\n * The seven `--wr-color-<name>*` tokens one seed produces.\n *\n * Returns an empty record for a hex it cannot parse rather than a palette built\n * on black — a silently black theme is harder to notice than a missing one.\n *\n * `name` is a shipped intent rather than any string: a token layer the\n * stylesheet never declares has nothing reading it, and a typo would otherwise\n * emit `--wr-color-primry-*` and paint nothing.\n */\nfunction wrIntentTokens(name: WrColor, seed: string): Record<string, string> {\n const rgb = parseHex(seed);\n if (!rgb) return {};\n\n const out: Record<string, string> = {\n [`--wr-color-${name}`]: toHex(rgb),\n [`--wr-color-${name}-rgb`]: `${Math.round(rgb.r)}, ${Math.round(rgb.g)}, ${Math.round(rgb.b)}`,\n [`--wr-color-${name}-contrast`]: wrContrastFor(toHex(rgb)),\n };\n for (const [suffix, delta] of SHADES) {\n out[`--wr-color-${name}-${suffix}`] = toHex(adjustLightness(rgb, delta));\n }\n return out;\n}\n\n/**\n * Every token a theme preset needs, for as many intents as it re-tunes.\n *\n * Intents left out keep the values the stylesheet compiled, so a preset that\n * only moves `primary` writes seven declarations and nothing else.\n */\nfunction wrThemeTokens(seeds: Partial<Record<WrColor, string>>): Record<string, string> {\n const out: Record<string, string> = {};\n for (const name of WR_COLORS) {\n const seed = seeds[name];\n if (seed) Object.assign(out, wrIntentTokens(name, seed));\n }\n return out;\n}\n\nexport { wrContrastFor, wrIntentTokens, wrThemeTokens };\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { InjectionToken } from '@angular/core';\n\n/** Mode the user explicitly selected. `auto` follows `prefers-color-scheme`. */\nexport type WrThemeMode = 'light' | 'dark' | 'auto';\n\n/** Resolved theme — what's actually applied to the DOM. */\nexport type WrResolvedTheme = 'light' | 'dark';\n\n/** Configuration for {@link WrTheme}. */\nexport interface WrThemeConfig {\n /** Initial mode used when no persisted value is present. @default 'auto' */\n readonly defaultMode: WrThemeMode;\n /** localStorage key for persistence. Set to `null` to disable persistence. @default 'wr-theme' */\n readonly storageKey: string | null;\n /** Attribute applied to `<html>` to expose the resolved theme. @default 'data-theme' */\n readonly attribute: string;\n}\n\nexport const DEFAULT_WR_THEME_CONFIG: WrThemeConfig = {\n defaultMode: 'auto',\n storageKey: 'wr-theme',\n attribute: 'data-theme',\n};\n\nexport const WR_THEME_CONFIG = new InjectionToken<WrThemeConfig>('WR_THEME_CONFIG', {\n factory: (): WrThemeConfig => DEFAULT_WR_THEME_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 { DOCUMENT } from '@angular/common';\nimport { Service, type Signal, afterNextRender, computed, effect, inject, isDevMode, signal } from '@angular/core';\n\nimport { WrPlatform } from 'ngwr/platform';\nimport { WrStorage } from 'ngwr/storage';\n\nimport { WR_THEME_CONFIG, type WrResolvedTheme, type WrThemeMode } from '../wr-theme-config';\n\nconst VALID_MODES: readonly WrThemeMode[] = ['light', 'dark', 'auto'];\n\nfunction isThemeMode(v: unknown): v is WrThemeMode {\n return typeof v === 'string' && (VALID_MODES as readonly string[]).includes(v);\n}\n\n/**\n * Light / dark theme manager.\n *\n * - `mode` is what the user picked (`light` | `dark` | `auto`).\n * - `resolved` is what's actually applied — `auto` resolves through\n * {@link WrPlatform.prefersDark}.\n * - Writes `[data-theme]` (or your configured attribute) on `<html>`.\n * - Persists the selected mode via {@link WrStorage} (defaults to\n * `localStorage`; swap the storage engine globally to change where).\n *\n * A configured `attribute` has to be given to the STYLESHEET too — a CSS\n * selector cannot read a provider value — so pair it with\n * `@use 'ngwr' with ($theme-attribute: '...')`. In dev mode the service compares\n * the two and warns when they disagree.\n *\n * **Under SSR or prerendering this service cannot prevent a flash of the wrong\n * theme, and nothing inside the application can.** The server has no\n * `localStorage` and no `prefers-color-scheme`, so every rendered page ships the\n * same attribute (`light` under the default config); by the time the client\n * bundle boots and the effect below corrects it, the browser has already\n * painted. Closing that window takes a script that runs before first paint —\n * {@link wrThemePrePaintScript} emits one that reads the persisted mode exactly\n * the way this service does.\n *\n * @example\n * ```ts\n * const theme = inject(WrTheme);\n * theme.set('dark');\n * theme.toggle();\n * theme.resolved(); // 'dark'\n * ```\n *\n * @see https://ngwr.dev/reference/services/theme\n */\n@Service()\nexport class WrTheme {\n private readonly doc = inject(DOCUMENT);\n private readonly platform = inject(WrPlatform);\n private readonly storage = inject(WrStorage);\n private readonly config = inject(WR_THEME_CONFIG);\n\n /** User-selected mode. */\n readonly mode = signal<WrThemeMode>(this.readPersisted() ?? this.config.defaultMode);\n\n /** Resolved theme actually applied to the DOM. */\n readonly resolved: Signal<WrResolvedTheme> = computed(() => {\n const m = this.mode();\n if (m === 'auto') return this.platform.prefersDark() ? 'dark' : 'light';\n return m;\n });\n\n constructor() {\n // Whenever the resolved theme changes, mirror it to the DOM + persist mode.\n effect(() => {\n const value = this.resolved();\n const html = this.doc.documentElement;\n if (html) html.setAttribute(this.config.attribute, value);\n this.persist(this.mode());\n });\n\n if (isDevMode() && this.platform.isBrowser) {\n // After render, so nothing here is constructor-time DOM access — and so\n // the stylesheet has had its chance to apply.\n afterNextRender(() => this.warnOnAttributeMismatch());\n }\n }\n\n /** Switch to a specific mode. */\n set(mode: WrThemeMode): void {\n this.mode.set(mode);\n }\n\n /** Cycle: light → dark → light (skips auto). */\n toggle(): void {\n this.mode.set(this.resolved() === 'dark' ? 'light' : 'dark');\n }\n\n /**\n * Dev-mode check that the STYLESHEET keys on the same attribute this service\n * writes.\n *\n * `attribute` is a runtime value and a CSS selector cannot read one, so the\n * dark block is keyed on a Sass variable (`$theme-attribute`) the consumer\n * configures separately. That makes disagreement possible, and disagreement is\n * silent in the worst way: the service resolves `dark`, writes the attribute,\n * reports success — and the page stays light forever, because nothing matches.\n *\n * The compiled theme publishes the name it keys on as `--wr-theme-attribute`,\n * which is what this reads. An empty value means no ngwr stylesheet is loaded\n * (a unit test, a consumer bundling their own CSS) or that it predates v13, so\n * the check stays quiet — it can only fire on a real mismatch, never on an\n * absence it cannot interpret.\n *\n * Production builds drop the call entirely via `isDevMode()` tree-shaking.\n */\n private warnOnAttributeMismatch(): void {\n const view = this.doc.defaultView;\n if (!view) return;\n\n const declared = view.getComputedStyle(this.doc.documentElement).getPropertyValue('--wr-theme-attribute').trim();\n if (!declared || declared === this.config.attribute) return;\n\n // eslint-disable-next-line no-console -- dev-mode validation\n console.warn(\n `[NGWR] Theme attribute mismatch: provideWrTheme({ attribute: '${this.config.attribute}' }) ` +\n `but the stylesheet keys its dark block on '${declared}'. Dark mode will never apply. ` +\n `Configure both: @use 'ngwr' with ($theme-attribute: '${this.config.attribute}');`\n );\n }\n\n // Persistence\n\n private readPersisted(): WrThemeMode | null {\n if (!this.config.storageKey) return null;\n const raw = this.storage.get<WrThemeMode>(this.config.storageKey);\n return isThemeMode(raw) ? raw : null;\n }\n\n private persist(mode: WrThemeMode): void {\n if (!this.config.storageKey) return;\n this.storage.set(this.config.storageKey, mode);\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 {\n type EnvironmentProviders,\n inject,\n makeEnvironmentProviders,\n provideEnvironmentInitializer,\n} from '@angular/core';\n\nimport { WrTheme } from './services/wr-theme';\nimport { DEFAULT_WR_THEME_CONFIG, WR_THEME_CONFIG, type WrThemeConfig } from './wr-theme-config';\n\n/**\n * Configure and activate {@link WrTheme}. Config is partial — merged with\n * defaults.\n *\n * Calling this is all it takes: the initializer instantiates {@link WrTheme},\n * whose constructor effect mirrors the resolved theme onto `<html>`. Without\n * that, the service (a tree-shakable `@Service()`) would only be created once\n * something injected it, so `[data-theme]` was never written and an app that\n * followed the docs silently ignored `defaultMode: 'auto'`.\n *\n * @example\n * ```ts\n * provideWrTheme({ defaultMode: 'dark', storageKey: 'my-app-theme' })\n * ```\n */\nexport function provideWrTheme(config: Partial<WrThemeConfig> = {}): EnvironmentProviders {\n const merged: WrThemeConfig = { ...DEFAULT_WR_THEME_CONFIG, ...config };\n return makeEnvironmentProviders([\n { provide: WR_THEME_CONFIG, useValue: merged },\n provideEnvironmentInitializer(() => void inject(WrTheme)),\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 { DEFAULT_WR_THEME_CONFIG, type WrThemeMode } from './wr-theme-config';\n\n/** Options for {@link wrThemePrePaintScript}. All optional — defaults mirror the services. */\nexport interface WrThemePrePaintOptions {\n /**\n * The key {@link WrTheme} persists the mode under — `provideWrTheme({ storageKey })`.\n * @default 'wr-theme'\n */\n readonly storageKey?: string;\n /**\n * The attribute written on `<html>` — `provideWrTheme({ attribute })`, which\n * has to agree with `@use 'ngwr' with ($theme-attribute: '…')`.\n * @default 'data-theme'\n */\n readonly attribute?: string;\n /**\n * What to resolve when nothing is persisted — `provideWrTheme({ defaultMode })`.\n * @default 'auto'\n */\n readonly defaultMode?: WrThemeMode;\n /**\n * `WrStorage`'s key prefix — `provideWrStorage({ prefix })`. The script reads\n * the raw key, so a prefixed app has to pass the same string here.\n * @default ''\n */\n readonly storagePrefix?: string;\n /**\n * Whether `WrStorage` wraps values in its JSON envelope —\n * `provideWrStorage({ json })`. The emitted reader accepts both shapes either\n * way; this only decides which one it tries first, and is here so the option\n * cannot be silently forgotten when an app turns the envelope off.\n * @default true\n */\n readonly json?: boolean;\n}\n\n/**\n * Source of the blocking script that resolves the theme BEFORE first paint.\n *\n * A server has no `localStorage` and no `prefers-color-scheme`, so every\n * server-rendered or prerendered page ships the same attribute — `light` under\n * the default config — and a dark-mode visitor sees a white page until the\n * client bundle boots and {@link WrTheme}'s effect corrects it. That window is\n * milliseconds on localhost and seconds on a slow connection, and it is not\n * something the service can close from inside the application: by the time\n * Angular runs, the paint has happened.\n *\n * The only fix is a script that runs before the first paint, and the only thing\n * it needs to know is how {@link WrTheme} and `WrStorage` agree to spell the\n * persisted mode. That agreement — the key, the prefix, the JSON envelope\n * `{ v, e }`, the expiry, the `auto` fallback — is what this function writes\n * out, so an app never has to re-derive it from the bundle and never has to keep\n * a hand-copied version in step with a library upgrade.\n *\n * Returns the JS source WITHOUT a `<script>` wrapper, so it can be inlined into\n * `index.html`, emitted from an SSR template, or hashed for a CSP\n * `script-src 'sha256-…'`. It is plain ES5 with no dependency on the app bundle,\n * and every step is wrapped so a blocked `localStorage` (private mode, a\n * sandboxed iframe) leaves the prerendered default in place rather than throwing\n * before anything has rendered.\n *\n * Pass the same values given to `provideWrTheme()` / `provideWrStorage()`; the\n * defaults here are the defaults there.\n *\n * @example\n * ```ts\n * // Build step / SSR template:\n * const html = template.replace('<!--theme-->', `<script>${wrThemePrePaintScript()}</script>`);\n *\n * // Or paste the output straight into <head>, above every stylesheet:\n * // <script>(function(){ … })();</script>\n * ```\n *\n * @see https://ngwr.dev/reference/services/theme\n */\nexport function wrThemePrePaintScript(options: WrThemePrePaintOptions = {}): string {\n const key = (options.storagePrefix ?? '') + (options.storageKey ?? DEFAULT_WR_THEME_CONFIG.storageKey ?? 'wr-theme');\n const attribute = options.attribute ?? DEFAULT_WR_THEME_CONFIG.attribute;\n const defaultMode = options.defaultMode ?? DEFAULT_WR_THEME_CONFIG.defaultMode;\n const json = options.json ?? true;\n\n // Every interpolated value goes through JSON.stringify rather than into a\n // quoted literal: a key or an attribute name is a configuration string, and a\n // hand-rolled `'${x}'` turns an apostrophe in one into a syntax error at best.\n const k = JSON.stringify(key);\n const a = JSON.stringify(attribute);\n const d = JSON.stringify(defaultMode);\n\n // Reading the envelope mirrors `WrStorage.get`, including its fall-throughs:\n // an unparseable string is returned verbatim (that is what `json: false`\n // writes), a parsed non-envelope is the value itself, and an envelope past its\n // `e` expiry counts as absent. `json: false` skips the parse entirely, which\n // is the same answer by a shorter path.\n const read = json\n ? `try{var p=JSON.parse(r);` +\n `if(p!==null&&typeof p===\"object\"&&\"v\" in p){if(p.e===undefined||p.e>=Date.now())m=p.v;}` +\n `else{m=p;}}catch(e){m=r;}`\n : `m=r;`;\n\n return (\n `(function(){try{` +\n `var m=null,r=null;` +\n `try{r=window.localStorage.getItem(${k});}catch(e){}` +\n `if(r!==null){${read}}` +\n `if(m!==\"light\"&&m!==\"dark\"&&m!==\"auto\")m=${d};` +\n `var dark=m===\"dark\"||(m===\"auto\"&&typeof window.matchMedia===\"function\"&&` +\n `window.matchMedia(\"(prefers-color-scheme: dark)\").matches);` +\n `document.documentElement.setAttribute(${a},dark?\"dark\":\"light\");` +\n `}catch(e){}})();`\n );\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ngwr-tilt-card-testing.mjs","sources":["../../../projects/lib/tilt-card/testing/wr-tilt-harness.ts","../../../projects/lib/tilt-card/testing/ngwr-tilt-card-testing.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';\n\nimport type { WrTiltHarnessFilters, WrTiltRotation } from './interfaces';\n\n/** The overlay `[glare]` appends — `aria-hidden`, and the only node the directive adds. */\nconst GLARE = '.wr-tilt-glare';\n\n/** Pull one `name(value)` out of a transform string. */\nfunction fromTransform(transform: string, fn: string): number | null {\n const match = new RegExp(`${fn}\\\\(([-\\\\d.]+)`).exec(transform);\n return match ? Number.parseFloat(match[1]) : null;\n}\n\n/**\n * Test harness for `[wrTilt]` and for `<wr-tilt-card>`, which applies it as a host\n * directive — one class, because they are one behaviour on two hosts.\n *\n * **The tilt itself needs a box, and a unit test has none.** The directive turns a\n * pointer position into two rotations by dividing by `getBoundingClientRect()`, which\n * is 0×0 in jsdom, so a move dispatched at a component that has not been given\n * dimensions writes `rotateX(NaNdeg)`. {@link movePointerTo} is still here because the\n * fix is one line in the SPEC — stub the host's rect, the way\n * `projects/lib/image-cropper/testing` documents — and because the two things worth\n * asserting on this component are only reachable through it: that a move writes a\n * transform at all, and that {@link leave} takes it away again.\n *\n * **{@link isFlat} is the reduced-motion assertion.** `onMove` returns before touching\n * the host when the user asked for less motion, so \"no inline transform after a move\"\n * is the whole contract, and it is one of the few reduced-motion behaviours in the\n * animation set that a test can actually see — most of the others live in a `@media`\n * block. Provide the `WrPlatform` stub and assert this.\n *\n * There is no `getGlareOpacity()` or `isGlareVisible()`: the overlay's gradient, its\n * blend mode and its fade all live in the stylesheet. And no `getMaxTilt()` /\n * `getPerspectiveInput()` — those would echo an input back rather than report what the\n * directive wrote; {@link getPerspective} and {@link getScale} read the transform the\n * host is actually carrying, which is the value that can be wrong.\n *\n * @example\n * ```ts\n * const card = await loader.getHarness(WrTiltHarness);\n * expect(await card.isFlat()).toBe(true);\n *\n * await card.movePointerTo(150, 50); // the spec stubbed the rect first\n * expect((await card.getTilt())?.rotateY).toBeGreaterThan(0);\n *\n * await card.leave();\n * expect(await card.isFlat()).toBe(true);\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrTiltHarness extends ComponentHarness {\n /** The directive on a consumer's element, and the card that hosts it. */\n static hostSelector = '[wrTilt], wr-tilt-card';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrTiltHarnessFilters = {}): HarnessPredicate<WrTiltHarness> {\n return new HarnessPredicate(WrTiltHarness, options)\n .addOption('glare', options.glare, async (harness, glare) => (await harness.hasGlare()) === glare)\n .addOption('flat', options.flat, async (harness, flat) => (await harness.isFlat()) === flat);\n }\n\n /**\n * Whether the host is at rest — no inline transform at all.\n *\n * True before the first move, after {@link leave}, and for the whole life of a card\n * whose user asked for less motion. It is the difference between \"flat\" and\n * \"rotated by zero\": the directive CLEARS the property rather than writing an\n * identity transform, so an empty string is the state and `rotateX(0deg)` would be\n * a component that tilted and came back the long way.\n */\n async isFlat(): Promise<boolean> {\n return (await this.getTransform()) === '';\n }\n\n /** The inline `transform` exactly as written, or `''` at rest. */\n async getTransform(): Promise<string> {\n return this.inlineStyle('transform');\n }\n\n /**\n * The two rotations the host is holding, in degrees, or `null` while it is flat.\n *\n * Parsed from the transform rather than recomputed: the harness has no more access\n * to the pointer maths than a consumer does, and the string is what the compositor\n * will read.\n */\n async getTilt(): Promise<WrTiltRotation | null> {\n const transform = await this.getTransform();\n if (transform === '') return null;\n\n const rotateX = fromTransform(transform, 'rotateX');\n const rotateY = fromTransform(transform, 'rotateY');\n return rotateX === null || rotateY === null ? null : { rotateX, rotateY };\n }\n\n /** The perspective the transform was written with, in pixels, or `null` while flat. */\n async getPerspective(): Promise<number | null> {\n return fromTransform(await this.getTransform(), 'perspective');\n }\n\n /** The scale the transform was written with, or `null` while flat. */\n async getScale(): Promise<number | null> {\n return fromTransform(await this.getTransform(), 'scale');\n }\n\n /**\n * Whether the host was set up to hold children in 3-D.\n *\n * Written once in the constructor, so it is true from first render and stays true —\n * which makes it the cheapest evidence that the directive is applied at all, on a\n * host where every other read is `''` until something moves.\n */\n async isPreserve3d(): Promise<boolean> {\n return (await this.inlineStyle('transform-style')) === 'preserve-3d';\n }\n\n /** Whether the glare overlay is installed (`[glare]`). */\n async hasGlare(): Promise<boolean> {\n return (await this.locatorForOptional(GLARE)()) !== null;\n }\n\n /**\n * Whether the glare is kept out of the accessibility tree.\n *\n * It is a decorative highlight with no text, so a screen reader must not stop on\n * it. Asserted rather than assumed because the overlay is created imperatively —\n * there is no template line for a reader to check.\n */\n async isGlareDecorative(): Promise<boolean> {\n const glare = await this.locatorForOptional(GLARE)();\n return glare !== null && (await glare.getAttribute('aria-hidden')) === 'true';\n }\n\n /**\n * Where the glare is pointing, as the two percentages the directive writes, or\n * `null` when there is no glare or nothing has moved yet.\n *\n * Cleared when the overlay is removed: a card that has given `[glare]` back should\n * not look like it is still tracking a pointer.\n */\n async getGlarePosition(): Promise<{ x: string; y: string } | null> {\n const x = await this.inlineStyle('--wr-tilt-glare-x');\n const y = await this.inlineStyle('--wr-tilt-glare-y');\n return x === '' || y === '' ? null : { x, y };\n }\n\n /**\n * Move a pointer over the host.\n *\n * **Stub the host's rect in your spec first.** The directive divides the pointer\n * offset by the host's width and height, and jsdom measures every element at 0×0,\n * so without a box the transform comes out as `NaN` — which is not a failure the\n * component would ever produce in a browser. One line does it:\n *\n * ```ts\n * host.getBoundingClientRect = () => ({ left: 0, top: 0, width: 200, height: 100 }) as DOMRect;\n * ```\n */\n async movePointerTo(clientX: number, clientY: number): Promise<void> {\n await (await this.host()).dispatchEvent('pointermove', { clientX, clientY });\n }\n\n /** Take the pointer off the host — which clears the transform and settles it flat. */\n async leave(): Promise<void> {\n await (await this.host()).dispatchEvent('pointerleave');\n }\n\n /** The projected content's text, trimmed. */\n async getContentText(): Promise<string> {\n return (await this.host()).text();\n }\n\n /**\n * One inline declaration, read off the `style` ATTRIBUTE.\n *\n * Not `getCssValue`, which is `getComputedStyle`: that resolves the stylesheet as\n * well, so `transform` would come back as the resolved matrix in a browser and\n * `--wr-tilt-glare-x` would answer with the sheet's own default. The attribute holds\n * what the directive wrote and nothing else, which is the only thing worth pinning.\n */\n private async inlineStyle(property: string): Promise<string> {\n const style = (await (await this.host()).getAttribute('style')) ?? '';\n\n for (const declaration of style.split(';')) {\n const colon = declaration.indexOf(':');\n if (colon === -1) continue;\n if (declaration.slice(0, colon).trim() !== property) continue;\n return declaration.slice(colon + 1).trim();\n }\n return '';\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ngwr-tilt-card-testing.mjs","sources":["../../../projects/lib/tilt-card/testing/wr-tilt-harness.ts","../../../projects/lib/tilt-card/testing/ngwr-tilt-card-testing.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';\n\nimport type { WrTiltHarnessFilters, WrTiltRotation } from './interfaces';\n\n/** The overlay `[glare]` appends — `aria-hidden`, and the only node the directive adds. */\nconst GLARE = '.wr-tilt-glare';\n\n/** Pull one `name(value)` out of a transform string. */\nfunction fromTransform(transform: string, fn: string): number | null {\n const match = new RegExp(`${fn}\\\\(([-\\\\d.]+)`).exec(transform);\n return match ? Number.parseFloat(match[1]) : null;\n}\n\n/**\n * Test harness for `[wrTilt]` and for `<wr-tilt-card>`, which applies it as a host\n * directive — one class, because they are one behaviour on two hosts.\n *\n * **The tilt itself needs a box, and a unit test has none.** The directive turns a\n * pointer position into two rotations by dividing by `getBoundingClientRect()`, which\n * is 0×0 in jsdom, so a move dispatched at a component that has not been given\n * dimensions writes `rotateX(NaNdeg)`. {@link movePointerTo} is still here because the\n * fix is one line in the SPEC — stub the host's rect, the way\n * `projects/lib/image-cropper/testing` documents — and because the two things worth\n * asserting on this component are only reachable through it: that a move writes a\n * transform at all, and that {@link leave} takes it away again.\n *\n * **{@link isFlat} is the reduced-motion assertion.** `onMove` returns before touching\n * the host when the user asked for less motion, so \"no inline transform after a move\"\n * is the whole contract, and it is one of the few reduced-motion behaviours in the\n * animation set that a test can actually see — most of the others live in a `@media`\n * block. Provide the `WrPlatform` stub and assert this.\n *\n * There is no `getGlareOpacity()` or `isGlareVisible()`: the overlay's gradient, its\n * blend mode and its fade all live in the stylesheet. And no `getMaxTilt()` /\n * `getPerspectiveInput()` — those would echo an input back rather than report what the\n * directive wrote; {@link getPerspective} and {@link getScale} read the transform the\n * host is actually carrying, which is the value that can be wrong.\n *\n * @example\n * ```ts\n * const card = await loader.getHarness(WrTiltHarness);\n * expect(await card.isFlat()).toBe(true);\n *\n * await card.movePointerTo(150, 50); // the spec stubbed the rect first\n * expect((await card.getTilt())?.rotateY).toBeGreaterThan(0);\n *\n * await card.leave();\n * expect(await card.isFlat()).toBe(true);\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrTiltHarness extends ComponentHarness {\n /** The directive on a consumer's element, and the card that hosts it. */\n static hostSelector = '[wrTilt], wr-tilt-card';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrTiltHarnessFilters = {}): HarnessPredicate<WrTiltHarness> {\n return new HarnessPredicate(WrTiltHarness, options)\n .addOption('glare', options.glare, async (harness, glare) => (await harness.hasGlare()) === glare)\n .addOption('flat', options.flat, async (harness, flat) => (await harness.isFlat()) === flat);\n }\n\n /**\n * Whether the host is at rest — no inline transform at all.\n *\n * True before the first move, after {@link leave}, and for the whole life of a card\n * whose user asked for less motion. It is the difference between \"flat\" and\n * \"rotated by zero\": the directive CLEARS the property rather than writing an\n * identity transform, so an empty string is the state and `rotateX(0deg)` would be\n * a component that tilted and came back the long way.\n */\n async isFlat(): Promise<boolean> {\n return (await this.getTransform()) === '';\n }\n\n /** The inline `transform` exactly as written, or `''` at rest. */\n async getTransform(): Promise<string> {\n return this.inlineStyle('transform');\n }\n\n /**\n * The two rotations the host is holding, in degrees, or `null` while it is flat.\n *\n * Parsed from the transform rather than recomputed: the harness has no more access\n * to the pointer maths than a consumer does, and the string is what the compositor\n * will read.\n */\n async getTilt(): Promise<WrTiltRotation | null> {\n const transform = await this.getTransform();\n if (transform === '') return null;\n\n const rotateX = fromTransform(transform, 'rotateX');\n const rotateY = fromTransform(transform, 'rotateY');\n return rotateX === null || rotateY === null ? null : { rotateX, rotateY };\n }\n\n /** The perspective the transform was written with, in pixels, or `null` while flat. */\n async getPerspective(): Promise<number | null> {\n return fromTransform(await this.getTransform(), 'perspective');\n }\n\n /** The scale the transform was written with, or `null` while flat. */\n async getScale(): Promise<number | null> {\n return fromTransform(await this.getTransform(), 'scale');\n }\n\n /**\n * Whether the host was set up to hold children in 3-D.\n *\n * Written once in the constructor, so it is true from first render and stays true —\n * which makes it the cheapest evidence that the directive is applied at all, on a\n * host where every other read is `''` until something moves.\n */\n async isPreserve3d(): Promise<boolean> {\n return (await this.inlineStyle('transform-style')) === 'preserve-3d';\n }\n\n /** Whether the glare overlay is installed (`[glare]`). */\n async hasGlare(): Promise<boolean> {\n return (await this.locatorForOptional(GLARE)()) !== null;\n }\n\n /**\n * Whether the glare is kept out of the accessibility tree.\n *\n * It is a decorative highlight with no text, so a screen reader must not stop on\n * it. Asserted rather than assumed because the overlay is created imperatively —\n * there is no template line for a reader to check.\n */\n async isGlareDecorative(): Promise<boolean> {\n const glare = await this.locatorForOptional(GLARE)();\n return glare !== null && (await glare.getAttribute('aria-hidden')) === 'true';\n }\n\n /**\n * Where the glare is pointing, as the two percentages the directive writes, or\n * `null` when there is no glare or nothing has moved yet.\n *\n * Cleared when the overlay is removed: a card that has given `[glare]` back should\n * not look like it is still tracking a pointer.\n */\n async getGlarePosition(): Promise<{ x: string; y: string } | null> {\n const x = await this.inlineStyle('--wr-tilt-glare-x');\n const y = await this.inlineStyle('--wr-tilt-glare-y');\n return x === '' || y === '' ? null : { x, y };\n }\n\n /**\n * Move a pointer over the host.\n *\n * **Stub the host's rect in your spec first.** The directive divides the pointer\n * offset by the host's width and height, and jsdom measures every element at 0×0,\n * so without a box the transform comes out as `NaN` — which is not a failure the\n * component would ever produce in a browser. One line does it:\n *\n * ```ts\n * host.getBoundingClientRect = () => ({ left: 0, top: 0, width: 200, height: 100 }) as DOMRect;\n * ```\n */\n async movePointerTo(clientX: number, clientY: number): Promise<void> {\n await (await this.host()).dispatchEvent('pointermove', { clientX, clientY });\n }\n\n /** Take the pointer off the host — which clears the transform and settles it flat. */\n async leave(): Promise<void> {\n await (await this.host()).dispatchEvent('pointerleave');\n }\n\n /** The projected content's text, trimmed. */\n async getContentText(): Promise<string> {\n return (await this.host()).text();\n }\n\n /**\n * One inline declaration, read off the `style` ATTRIBUTE.\n *\n * Not `getCssValue`, which is `getComputedStyle`: that resolves the stylesheet as\n * well, so `transform` would come back as the resolved matrix in a browser and\n * `--wr-tilt-glare-x` would answer with the sheet's own default. The attribute holds\n * what the directive wrote and nothing else, which is the only thing worth pinning.\n */\n private async inlineStyle(property: string): Promise<string> {\n const style = (await (await this.host()).getAttribute('style')) ?? '';\n\n for (const declaration of style.split(';')) {\n const colon = declaration.indexOf(':');\n if (colon === -1) continue;\n if (declaration.slice(0, colon).trim() !== property) continue;\n return declaration.slice(colon + 1).trim();\n }\n return '';\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -110,10 +110,10 @@ class WrTilt {
110
110
  host.style.removeProperty('--wr-tilt-glare-x');
111
111
  host.style.removeProperty('--wr-tilt-glare-y');
112
112
  }
113
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrTilt, deps: [], target: i0.ɵɵFactoryTarget.Directive });
114
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.6", type: WrTilt, isStandalone: true, selector: "[wrTilt]", inputs: { maxTilt: { classPropertyName: "maxTilt", publicName: "maxTilt", isSignal: true, isRequired: false, transformFunction: null }, perspective: { classPropertyName: "perspective", publicName: "perspective", isSignal: true, isRequired: false, transformFunction: null }, scale: { classPropertyName: "scale", publicName: "scale", isSignal: true, isRequired: false, transformFunction: null }, glare: { classPropertyName: "glare", publicName: "glare", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "pointermove": "onMove($event)", "pointerleave": "onLeave()" } }, ngImport: i0 });
113
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrTilt, deps: [], target: i0.ɵɵFactoryTarget.Directive });
114
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.7", type: WrTilt, isStandalone: true, selector: "[wrTilt]", inputs: { maxTilt: { classPropertyName: "maxTilt", publicName: "maxTilt", isSignal: true, isRequired: false, transformFunction: null }, perspective: { classPropertyName: "perspective", publicName: "perspective", isSignal: true, isRequired: false, transformFunction: null }, scale: { classPropertyName: "scale", publicName: "scale", isSignal: true, isRequired: false, transformFunction: null }, glare: { classPropertyName: "glare", publicName: "glare", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "pointermove": "onMove($event)", "pointerleave": "onLeave()" } }, ngImport: i0 });
115
115
  }
116
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrTilt, decorators: [{
116
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrTilt, decorators: [{
117
117
  type: Directive,
118
118
  args: [{
119
119
  selector: '[wrTilt]',
@@ -150,10 +150,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
150
150
  * ```
151
151
  */
152
152
  class WrTiltCard {
153
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrTiltCard, deps: [], target: i0.ɵɵFactoryTarget.Component });
154
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.6", type: WrTiltCard, isStandalone: true, selector: "wr-tilt-card", host: { classAttribute: "wr-tilt-card" }, hostDirectives: [{ directive: WrTilt, inputs: ["maxTilt", "maxTilt", "perspective", "perspective", "scale", "scale", "glare", "glare"] }], ngImport: i0, template: '<ng-content />', isInline: true, styles: [".wr-tilt-card{display:block;position:relative;padding:1.5rem;border-radius:.75rem;border:1px solid var(--wr-color-outline);background:var(--wr-color-surface);color:var(--wr-color-on-surface);box-shadow:0 1px 2px rgba(var(--wr-color-backdrop-rgb),.06);transform-style:preserve-3d;transition:transform .15s ease-out}.wr-tilt-glare{position:absolute;inset:0;pointer-events:none;background:radial-gradient(circle at var(--wr-tilt-glare-x, 50%) var(--wr-tilt-glare-y, 50%),var(--wr-tilt-glare-color, rgba(var(--wr-color-on-surface-rgb), .12)),transparent 60%);mix-blend-mode:multiply}\n"], encapsulation: i0.ViewEncapsulation.None });
153
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrTiltCard, deps: [], target: i0.ɵɵFactoryTarget.Component });
154
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.7", type: WrTiltCard, isStandalone: true, selector: "wr-tilt-card", host: { classAttribute: "wr-tilt-card" }, hostDirectives: [{ directive: WrTilt, inputs: ["maxTilt", "maxTilt", "perspective", "perspective", "scale", "scale", "glare", "glare"] }], ngImport: i0, template: '<ng-content />', isInline: true, styles: [".wr-tilt-card{display:block;position:relative;padding:1.5rem;border-radius:.75rem;border:1px solid var(--wr-color-outline);background:var(--wr-color-surface);color:var(--wr-color-on-surface);box-shadow:0 1px 2px rgba(var(--wr-color-backdrop-rgb),.06);transform-style:preserve-3d;transition:transform .15s ease-out}.wr-tilt-glare{position:absolute;inset:0;pointer-events:none;background:radial-gradient(circle at var(--wr-tilt-glare-x, 50%) var(--wr-tilt-glare-y, 50%),var(--wr-tilt-glare-color, rgba(var(--wr-color-on-surface-rgb), .12)),transparent 60%);mix-blend-mode:multiply}\n"], encapsulation: i0.ViewEncapsulation.None });
155
155
  }
156
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrTiltCard, decorators: [{
156
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrTiltCard, decorators: [{
157
157
  type: Component,
158
158
  args: [{ selector: 'wr-tilt-card', template: '<ng-content />', encapsulation: ViewEncapsulation.None, hostDirectives: [
159
159
  {
@@ -1 +1 @@
1
- {"version":3,"file":"ngwr-tilt-card.mjs","sources":["../../../projects/lib/tilt-card/tilt.ts","../../../projects/lib/tilt-card/tilt-card.ts","../../../projects/lib/tilt-card/ngwr-tilt-card.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 { isPlatformBrowser } from '@angular/common';\nimport { DestroyRef, Directive, ElementRef, NgZone, PLATFORM_ID, effect, inject, input } from '@angular/core';\n\nimport { WrPlatform } from 'ngwr/platform';\n\n/**\n * 3D mouse-tilt on hover. Adds `perspective(…) rotateX(…) rotateY(…)` to\n * the host's transform tracking the cursor's position over it.\n *\n * @example\n * ```html\n * <div class=\"card\" wrTilt>…</div>\n * <div class=\"card\" wrTilt maxTilt=\"20\" [glare]=\"true\">…</div>\n * ```\n */\n@Directive({\n selector: '[wrTilt]',\n host: { '(pointermove)': 'onMove($event)', '(pointerleave)': 'onLeave()' },\n})\nexport class WrTilt {\n /** Maximum tilt in degrees. @default 12 */\n readonly maxTilt = input(12, { transform: (v: unknown): number => Math.max(0, coerceNumberProperty(v, 12)) });\n\n /** CSS perspective in pixels. @default 800 */\n readonly perspective = input(800, {\n transform: (v: unknown): number => Math.max(100, coerceNumberProperty(v, 800)),\n });\n\n /** Scale applied while hovered. @default 1.03 */\n readonly scale = input(1.03, { transform: (v: unknown): number => Math.max(1, coerceNumberProperty(v, 1.03)) });\n\n /** Add a moving glare highlight overlay. @default false */\n readonly glare = input(false, { transform: coerceBooleanProperty });\n\n private readonly el = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly zone = inject(NgZone);\n private readonly destroyRef = inject(DestroyRef);\n private readonly platform = inject(WrPlatform);\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n private glareEl: HTMLElement | null = null;\n private priorOverflow = '';\n private priorPosition = '';\n\n constructor() {\n const host = this.el.nativeElement;\n host.style.transformStyle = 'preserve-3d';\n host.style.transition = 'transform 0.15s ease-out';\n\n // Signal inputs are not bound yet while the constructor runs, so reading\n // `glare()` here would always see the default and the overlay would never\n // appear. Track it instead, so toggling the input at runtime works too.\n // Only in the browser: `installGlare` measures with `getComputedStyle`,\n // and the server has no layout to measure.\n if (this.isBrowser) {\n effect(() => (this.glare() ? this.installGlare() : this.removeGlare()));\n }\n\n this.destroyRef.onDestroy(() => {\n host.style.transform = '';\n this.removeGlare();\n });\n }\n\n /** @internal */\n protected onMove(event: PointerEvent): void {\n // Reduced motion: no pointer-tracking tilt — the card stays flat.\n if (this.platform.prefersReducedMotion()) return;\n this.zone.runOutsideAngular(() => {\n const host = this.el.nativeElement;\n const rect = host.getBoundingClientRect();\n const px = (event.clientX - rect.left) / rect.width;\n const py = (event.clientY - rect.top) / rect.height;\n const rx = (0.5 - py) * this.maxTilt();\n const ry = (px - 0.5) * this.maxTilt();\n host.style.transform = `perspective(${this.perspective()}px) rotateX(${rx}deg) rotateY(${ry}deg) scale(${this.scale()})`;\n if (this.glare()) {\n host.style.setProperty('--wr-tilt-glare-x', `${px * 100}%`);\n host.style.setProperty('--wr-tilt-glare-y', `${py * 100}%`);\n }\n });\n }\n\n /** @internal */\n protected onLeave(): void {\n this.el.nativeElement.style.transform = '';\n }\n\n private installGlare(): void {\n if (this.glareEl) return;\n const host = this.el.nativeElement;\n\n // Remembered, not assumed: `overflow` is written unconditionally, so it can be\n // clobbering an author's own inline value, and a blanket `removeProperty` on the\n // way out would delete it. Capturing the empty string is exactly what restores an\n // element that had none — which is the common case, and the one that used to keep\n // `overflow: hidden` for good after `[glare]` was turned back off.\n this.priorOverflow = host.style.overflow;\n this.priorPosition = host.style.position;\n\n if (getComputedStyle(host).position === 'static') host.style.position = 'relative';\n host.style.overflow = 'hidden';\n const glare = host.ownerDocument.createElement('span');\n glare.className = 'wr-tilt-glare';\n glare.setAttribute('aria-hidden', 'true');\n host.appendChild(glare);\n this.glareEl = glare;\n }\n\n private removeGlare(): void {\n if (!this.glareEl) return;\n\n const host = this.el.nativeElement;\n this.glareEl.remove();\n this.glareEl = null;\n host.style.overflow = this.priorOverflow;\n host.style.position = this.priorPosition;\n // Nothing reads these once the overlay is gone; leaving them behind only makes a\n // destroyed directive look like it is still tracking a pointer.\n host.style.removeProperty('--wr-tilt-glare-x');\n host.style.removeProperty('--wr-tilt-glare-y');\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 { Component, ViewEncapsulation } from '@angular/core';\n\nimport { WrTilt } from './tilt';\n\n/**\n * Card wrapper that applies the `[wrTilt]` directive out-of-the-box,\n * plus a small set of card-style defaults (radius, padding, surface).\n * Pass any inputs through — they're forwarded to the hosted directive.\n *\n * For arbitrary elements that just need the tilt behaviour, use the\n * `[wrTilt]` directive directly:\n *\n * ```html\n * <img wrTilt [maxTilt]=\"10\" src=\"…\" />\n * ```\n *\n * @example\n * ```html\n * <wr-tilt-card>\n * <h3>Hello</h3>\n * <p>Move the cursor across me.</p>\n * </wr-tilt-card>\n *\n * <wr-tilt-card [maxTilt]=\"20\" [glare]=\"true\">…</wr-tilt-card>\n * ```\n */\n@Component({\n selector: 'wr-tilt-card',\n template: '<ng-content />',\n styleUrl: './tilt-card.scss',\n encapsulation: ViewEncapsulation.None,\n hostDirectives: [\n {\n directive: WrTilt,\n inputs: ['maxTilt', 'perspective', 'scale', 'glare'],\n },\n ],\n host: { class: 'wr-tilt-card' },\n})\nexport class WrTiltCard {}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ngwr-tilt-card.mjs","sources":["../../../projects/lib/tilt-card/tilt.ts","../../../projects/lib/tilt-card/tilt-card.ts","../../../projects/lib/tilt-card/ngwr-tilt-card.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 { isPlatformBrowser } from '@angular/common';\nimport { DestroyRef, Directive, ElementRef, NgZone, PLATFORM_ID, effect, inject, input } from '@angular/core';\n\nimport { WrPlatform } from 'ngwr/platform';\n\n/**\n * 3D mouse-tilt on hover. Adds `perspective(…) rotateX(…) rotateY(…)` to\n * the host's transform tracking the cursor's position over it.\n *\n * @example\n * ```html\n * <div class=\"card\" wrTilt>…</div>\n * <div class=\"card\" wrTilt maxTilt=\"20\" [glare]=\"true\">…</div>\n * ```\n */\n@Directive({\n selector: '[wrTilt]',\n host: { '(pointermove)': 'onMove($event)', '(pointerleave)': 'onLeave()' },\n})\nexport class WrTilt {\n /** Maximum tilt in degrees. @default 12 */\n readonly maxTilt = input(12, { transform: (v: unknown): number => Math.max(0, coerceNumberProperty(v, 12)) });\n\n /** CSS perspective in pixels. @default 800 */\n readonly perspective = input(800, {\n transform: (v: unknown): number => Math.max(100, coerceNumberProperty(v, 800)),\n });\n\n /** Scale applied while hovered. @default 1.03 */\n readonly scale = input(1.03, { transform: (v: unknown): number => Math.max(1, coerceNumberProperty(v, 1.03)) });\n\n /** Add a moving glare highlight overlay. @default false */\n readonly glare = input(false, { transform: coerceBooleanProperty });\n\n private readonly el = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly zone = inject(NgZone);\n private readonly destroyRef = inject(DestroyRef);\n private readonly platform = inject(WrPlatform);\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n private glareEl: HTMLElement | null = null;\n private priorOverflow = '';\n private priorPosition = '';\n\n constructor() {\n const host = this.el.nativeElement;\n host.style.transformStyle = 'preserve-3d';\n host.style.transition = 'transform 0.15s ease-out';\n\n // Signal inputs are not bound yet while the constructor runs, so reading\n // `glare()` here would always see the default and the overlay would never\n // appear. Track it instead, so toggling the input at runtime works too.\n // Only in the browser: `installGlare` measures with `getComputedStyle`,\n // and the server has no layout to measure.\n if (this.isBrowser) {\n effect(() => (this.glare() ? this.installGlare() : this.removeGlare()));\n }\n\n this.destroyRef.onDestroy(() => {\n host.style.transform = '';\n this.removeGlare();\n });\n }\n\n /** @internal */\n protected onMove(event: PointerEvent): void {\n // Reduced motion: no pointer-tracking tilt — the card stays flat.\n if (this.platform.prefersReducedMotion()) return;\n this.zone.runOutsideAngular(() => {\n const host = this.el.nativeElement;\n const rect = host.getBoundingClientRect();\n const px = (event.clientX - rect.left) / rect.width;\n const py = (event.clientY - rect.top) / rect.height;\n const rx = (0.5 - py) * this.maxTilt();\n const ry = (px - 0.5) * this.maxTilt();\n host.style.transform = `perspective(${this.perspective()}px) rotateX(${rx}deg) rotateY(${ry}deg) scale(${this.scale()})`;\n if (this.glare()) {\n host.style.setProperty('--wr-tilt-glare-x', `${px * 100}%`);\n host.style.setProperty('--wr-tilt-glare-y', `${py * 100}%`);\n }\n });\n }\n\n /** @internal */\n protected onLeave(): void {\n this.el.nativeElement.style.transform = '';\n }\n\n private installGlare(): void {\n if (this.glareEl) return;\n const host = this.el.nativeElement;\n\n // Remembered, not assumed: `overflow` is written unconditionally, so it can be\n // clobbering an author's own inline value, and a blanket `removeProperty` on the\n // way out would delete it. Capturing the empty string is exactly what restores an\n // element that had none — which is the common case, and the one that used to keep\n // `overflow: hidden` for good after `[glare]` was turned back off.\n this.priorOverflow = host.style.overflow;\n this.priorPosition = host.style.position;\n\n if (getComputedStyle(host).position === 'static') host.style.position = 'relative';\n host.style.overflow = 'hidden';\n const glare = host.ownerDocument.createElement('span');\n glare.className = 'wr-tilt-glare';\n glare.setAttribute('aria-hidden', 'true');\n host.appendChild(glare);\n this.glareEl = glare;\n }\n\n private removeGlare(): void {\n if (!this.glareEl) return;\n\n const host = this.el.nativeElement;\n this.glareEl.remove();\n this.glareEl = null;\n host.style.overflow = this.priorOverflow;\n host.style.position = this.priorPosition;\n // Nothing reads these once the overlay is gone; leaving them behind only makes a\n // destroyed directive look like it is still tracking a pointer.\n host.style.removeProperty('--wr-tilt-glare-x');\n host.style.removeProperty('--wr-tilt-glare-y');\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 { Component, ViewEncapsulation } from '@angular/core';\n\nimport { WrTilt } from './tilt';\n\n/**\n * Card wrapper that applies the `[wrTilt]` directive out-of-the-box,\n * plus a small set of card-style defaults (radius, padding, surface).\n * Pass any inputs through — they're forwarded to the hosted directive.\n *\n * For arbitrary elements that just need the tilt behaviour, use the\n * `[wrTilt]` directive directly:\n *\n * ```html\n * <img wrTilt [maxTilt]=\"10\" src=\"…\" />\n * ```\n *\n * @example\n * ```html\n * <wr-tilt-card>\n * <h3>Hello</h3>\n * <p>Move the cursor across me.</p>\n * </wr-tilt-card>\n *\n * <wr-tilt-card [maxTilt]=\"20\" [glare]=\"true\">…</wr-tilt-card>\n * ```\n */\n@Component({\n selector: 'wr-tilt-card',\n template: '<ng-content />',\n styleUrl: './tilt-card.scss',\n encapsulation: ViewEncapsulation.None,\n hostDirectives: [\n {\n directive: WrTilt,\n inputs: ['maxTilt', 'perspective', 'scale', 'glare'],\n },\n ],\n host: { class: 'wr-tilt-card' },\n})\nexport class WrTiltCard {}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -25,10 +25,10 @@ class WrTimeline {
25
25
  ...(ngDevMode ? [{ debugName: "orientation" }] : /* istanbul ignore next */ []));
26
26
  classes = computed(() => `wr-timeline wr-timeline--${this.orientation()}`, /* @ts-ignore */
27
27
  ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
28
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrTimeline, deps: [], target: i0.ɵɵFactoryTarget.Component });
29
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: WrTimeline, isStandalone: true, selector: "wr-timeline", inputs: { orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: '<ng-content />', isInline: true, encapsulation: i0.ViewEncapsulation.None });
28
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrTimeline, deps: [], target: i0.ɵɵFactoryTarget.Component });
29
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.7", type: WrTimeline, isStandalone: true, selector: "wr-timeline", inputs: { orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: '<ng-content />', isInline: true, encapsulation: i0.ViewEncapsulation.None });
30
30
  }
31
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrTimeline, decorators: [{
31
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrTimeline, decorators: [{
32
32
  type: Component,
33
33
  args: [{
34
34
  selector: 'wr-timeline',
@@ -57,10 +57,10 @@ class WrTimelineItem {
57
57
  ...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
58
58
  classes = computed(() => `wr-timeline-item wr-timeline-item--${this.color()}`, /* @ts-ignore */
59
59
  ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
60
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrTimelineItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
61
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: WrTimelineItem, isStandalone: true, selector: "wr-timeline-item", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, time: { classPropertyName: "time", publicName: "time", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: "<span class=\"wr-timeline-item__dot\" aria-hidden=\"true\"></span>\n<div class=\"wr-timeline-item__body\">\n @if (time()) {\n <div class=\"wr-timeline-item__time\">{{ time() }}</div>\n }\n @if (title()) {\n <div class=\"wr-timeline-item__title\">{{ title() }}</div>\n }\n <div class=\"wr-timeline-item__content\">\n <ng-content />\n </div>\n</div>\n", encapsulation: i0.ViewEncapsulation.None });
60
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrTimelineItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
61
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: WrTimelineItem, isStandalone: true, selector: "wr-timeline-item", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, time: { classPropertyName: "time", publicName: "time", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: "<span class=\"wr-timeline-item__dot\" aria-hidden=\"true\"></span>\n<div class=\"wr-timeline-item__body\">\n @if (time()) {\n <div class=\"wr-timeline-item__time\">{{ time() }}</div>\n }\n @if (title()) {\n <div class=\"wr-timeline-item__title\">{{ title() }}</div>\n }\n <div class=\"wr-timeline-item__content\">\n <ng-content />\n </div>\n</div>\n", encapsulation: i0.ViewEncapsulation.None });
62
62
  }
63
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrTimelineItem, decorators: [{
63
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrTimelineItem, decorators: [{
64
64
  type: Component,
65
65
  args: [{ selector: 'wr-timeline-item', encapsulation: ViewEncapsulation.None, host: { '[class]': 'classes()' }, template: "<span class=\"wr-timeline-item__dot\" aria-hidden=\"true\"></span>\n<div class=\"wr-timeline-item__body\">\n @if (time()) {\n <div class=\"wr-timeline-item__time\">{{ time() }}</div>\n }\n @if (title()) {\n <div class=\"wr-timeline-item__title\">{{ title() }}</div>\n }\n <div class=\"wr-timeline-item__content\">\n <ng-content />\n </div>\n</div>\n" }]
66
66
  }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], time: [{ type: i0.Input, args: [{ isSignal: true, alias: "time", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }] } });
@@ -1 +1 @@
1
- {"version":3,"file":"ngwr-timeline.mjs","sources":["../../../projects/lib/timeline/timeline.ts","../../../projects/lib/timeline/timeline-item.ts","../../../projects/lib/timeline/timeline-item.html","../../../projects/lib/timeline/ngwr-timeline.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 { Component, ViewEncapsulation, computed, input } from '@angular/core';\n\n/**\n * Event-list ladder. Project `<wr-timeline-item>` children.\n *\n * @example\n * ```html\n * <wr-timeline>\n * <wr-timeline-item title=\"Created\" time=\"2026-05-01\">Initial commit.</wr-timeline-item>\n * <wr-timeline-item title=\"Deployed\" time=\"2026-05-02\" color=\"success\">Live.</wr-timeline-item>\n * </wr-timeline>\n * ```\n *\n * @see https://ngwr.dev/reference/components/timeline\n */\n@Component({\n selector: 'wr-timeline',\n template: '<ng-content />',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n})\nexport class WrTimeline {\n readonly orientation = input<'vertical' | 'horizontal'>('vertical');\n\n protected readonly classes = computed(() => `wr-timeline wr-timeline--${this.orientation()}`);\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 { Component, ViewEncapsulation, computed, input } from '@angular/core';\n\nimport type { WrTimelineColor } from './interfaces';\n\n/**\n * One event in a {@link WrTimeline}. Project content for the\n * description; `title` and `time` are header inputs.\n */\n@Component({\n selector: 'wr-timeline-item',\n templateUrl: './timeline-item.html',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n})\nexport class WrTimelineItem {\n readonly title = input<string>('');\n readonly time = input<string>('');\n readonly color = input<WrTimelineColor>('primary');\n\n protected readonly classes = computed(() => `wr-timeline-item wr-timeline-item--${this.color()}`);\n}\n\nexport type { WrTimelineColor } from './interfaces';\n","<span class=\"wr-timeline-item__dot\" aria-hidden=\"true\"></span>\n<div class=\"wr-timeline-item__body\">\n @if (time()) {\n <div class=\"wr-timeline-item__time\">{{ time() }}</div>\n }\n @if (title()) {\n <div class=\"wr-timeline-item__title\">{{ title() }}</div>\n }\n <div class=\"wr-timeline-item__content\">\n <ng-content />\n </div>\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;AAAA;;;;;AAKG;AAIH;;;;;;;;;;;;AAYG;MAOU,UAAU,CAAA;IACZ,WAAW,GAAG,KAAK,CAA4B,UAAU;oFAAC;IAEhD,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAA,yBAAA,EAA4B,IAAI,CAAC,WAAW,EAAE,CAAA,CAAE;gFAAC;uGAHlF,UAAU,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAV,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAU,6QAJX,gBAAgB,EAAA,QAAA,EAAA,IAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;2FAIf,UAAU,EAAA,UAAA,EAAA,CAAA;kBANtB,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,aAAa;AACvB,oBAAA,QAAQ,EAAE,gBAAgB;oBAC1B,aAAa,EAAE,iBAAiB,CAAC,IAAI;AACrC,oBAAA,IAAI,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE;AACjC,iBAAA;;;AC3BD;;;;;AAKG;AAMH;;;AAGG;MAOU,cAAc,CAAA;IAChB,KAAK,GAAG,KAAK,CAAS,EAAE;8EAAC;IACzB,IAAI,GAAG,KAAK,CAAS,EAAE;6EAAC;IACxB,KAAK,GAAG,KAAK,CAAkB,SAAS;8EAAC;IAE/B,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAA,mCAAA,EAAsC,IAAI,CAAC,KAAK,EAAE,CAAA,CAAE;gFAAC;uGALtF,cAAc,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAd,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,cAAc,6eCrB3B,8WAYA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;2FDSa,cAAc,EAAA,UAAA,EAAA,CAAA;kBAN1B,SAAS;+BACE,kBAAkB,EAAA,aAAA,EAEb,iBAAiB,CAAC,IAAI,QAC/B,EAAE,SAAS,EAAE,WAAW,EAAE,EAAA,QAAA,EAAA,8WAAA,EAAA;;;AEnBlC;;AAEG;;;;"}
1
+ {"version":3,"file":"ngwr-timeline.mjs","sources":["../../../projects/lib/timeline/timeline.ts","../../../projects/lib/timeline/timeline-item.ts","../../../projects/lib/timeline/timeline-item.html","../../../projects/lib/timeline/ngwr-timeline.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 { Component, ViewEncapsulation, computed, input } from '@angular/core';\n\n/**\n * Event-list ladder. Project `<wr-timeline-item>` children.\n *\n * @example\n * ```html\n * <wr-timeline>\n * <wr-timeline-item title=\"Created\" time=\"2026-05-01\">Initial commit.</wr-timeline-item>\n * <wr-timeline-item title=\"Deployed\" time=\"2026-05-02\" color=\"success\">Live.</wr-timeline-item>\n * </wr-timeline>\n * ```\n *\n * @see https://ngwr.dev/reference/components/timeline\n */\n@Component({\n selector: 'wr-timeline',\n template: '<ng-content />',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n})\nexport class WrTimeline {\n readonly orientation = input<'vertical' | 'horizontal'>('vertical');\n\n protected readonly classes = computed(() => `wr-timeline wr-timeline--${this.orientation()}`);\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 { Component, ViewEncapsulation, computed, input } from '@angular/core';\n\nimport type { WrTimelineColor } from './interfaces';\n\n/**\n * One event in a {@link WrTimeline}. Project content for the\n * description; `title` and `time` are header inputs.\n */\n@Component({\n selector: 'wr-timeline-item',\n templateUrl: './timeline-item.html',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n})\nexport class WrTimelineItem {\n readonly title = input<string>('');\n readonly time = input<string>('');\n readonly color = input<WrTimelineColor>('primary');\n\n protected readonly classes = computed(() => `wr-timeline-item wr-timeline-item--${this.color()}`);\n}\n\nexport type { WrTimelineColor } from './interfaces';\n","<span class=\"wr-timeline-item__dot\" aria-hidden=\"true\"></span>\n<div class=\"wr-timeline-item__body\">\n @if (time()) {\n <div class=\"wr-timeline-item__time\">{{ time() }}</div>\n }\n @if (title()) {\n <div class=\"wr-timeline-item__title\">{{ title() }}</div>\n }\n <div class=\"wr-timeline-item__content\">\n <ng-content />\n </div>\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;AAAA;;;;;AAKG;AAIH;;;;;;;;;;;;AAYG;MAOU,UAAU,CAAA;IACZ,WAAW,GAAG,KAAK,CAA4B,UAAU;oFAAC;IAEhD,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAA,yBAAA,EAA4B,IAAI,CAAC,WAAW,EAAE,CAAA,CAAE;gFAAC;uGAHlF,UAAU,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAV,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAU,6QAJX,gBAAgB,EAAA,QAAA,EAAA,IAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;2FAIf,UAAU,EAAA,UAAA,EAAA,CAAA;kBANtB,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,aAAa;AACvB,oBAAA,QAAQ,EAAE,gBAAgB;oBAC1B,aAAa,EAAE,iBAAiB,CAAC,IAAI;AACrC,oBAAA,IAAI,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE;AACjC,iBAAA;;;AC3BD;;;;;AAKG;AAMH;;;AAGG;MAOU,cAAc,CAAA;IAChB,KAAK,GAAG,KAAK,CAAS,EAAE;8EAAC;IACzB,IAAI,GAAG,KAAK,CAAS,EAAE;6EAAC;IACxB,KAAK,GAAG,KAAK,CAAkB,SAAS;8EAAC;IAE/B,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAA,mCAAA,EAAsC,IAAI,CAAC,KAAK,EAAE,CAAA,CAAE;gFAAC;uGALtF,cAAc,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAd,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,cAAc,6eCrB3B,8WAYA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;2FDSa,cAAc,EAAA,UAAA,EAAA,CAAA;kBAN1B,SAAS;+BACE,kBAAkB,EAAA,aAAA,EAEb,iBAAiB,CAAC,IAAI,QAC/B,EAAE,SAAS,EAAE,WAAW,EAAE,EAAA,QAAA,EAAA,8WAAA,EAAA;;;AEnBlC;;AAEG;;"}