ngwr 8.0.0 → 9.0.1

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 (431) hide show
  1. package/README.md +76 -29
  2. package/action-sheet/styles/_index.scss +93 -0
  3. package/alert/styles/_index.scss +10 -10
  4. package/anchor/styles/_index.scss +3 -3
  5. package/back-top/styles/_index.scss +1 -1
  6. package/badge/styles/_tag.scss +3 -3
  7. package/bar-chart/styles/_index.scss +4 -4
  8. package/border-glow/styles/_index.scss +3 -3
  9. package/breadcrumbs/styles/_index.scss +3 -3
  10. package/burger/styles/_index.scss +1 -1
  11. package/button/styles/_index.scss +4 -4
  12. package/calendar/styles/_index.scss +4 -4
  13. package/calendar-heatmap/styles/_index.scss +3 -3
  14. package/card/styles/_index.scss +5 -5
  15. package/carousel/styles/_index.scss +5 -5
  16. package/cascader/styles/_index.scss +15 -15
  17. package/checkbox/styles/_index.scss +20 -5
  18. package/collapse/styles/_index.scss +6 -6
  19. package/color-picker/styles/_index.scss +15 -9
  20. package/command-palette/styles/_index.scss +19 -16
  21. package/compare/styles/_index.scss +3 -3
  22. package/context-menu/styles/_index.scss +16 -6
  23. package/counter/styles/_index.scss +12 -1
  24. package/date-picker/styles/_index.scss +8 -8
  25. package/descriptions/styles/_index.scss +9 -9
  26. package/dialog/styles/_index.scss +7 -6
  27. package/divider/styles/_index.scss +2 -2
  28. package/donut-chart/styles/_index.scss +3 -3
  29. package/drag-drop/styles/_index.scss +11 -6
  30. package/drawer/styles/_index.scss +15 -6
  31. package/dropdown/styles/_index.scss +5 -5
  32. package/empty/styles/_index.scss +4 -4
  33. package/fesm2022/ngwr-action-sheet.mjs +81 -0
  34. package/fesm2022/ngwr-action-sheet.mjs.map +1 -0
  35. package/fesm2022/ngwr-affix.mjs +3 -3
  36. package/fesm2022/ngwr-alert.mjs +4 -4
  37. package/fesm2022/ngwr-alert.mjs.map +1 -1
  38. package/fesm2022/ngwr-anchor.mjs +4 -4
  39. package/fesm2022/ngwr-anchor.mjs.map +1 -1
  40. package/fesm2022/ngwr-aurora.mjs +5 -4
  41. package/fesm2022/ngwr-aurora.mjs.map +1 -1
  42. package/fesm2022/ngwr-avatar.mjs +4 -4
  43. package/fesm2022/ngwr-avatar.mjs.map +1 -1
  44. package/fesm2022/ngwr-back-top.mjs +4 -4
  45. package/fesm2022/ngwr-back-top.mjs.map +1 -1
  46. package/fesm2022/ngwr-badge.mjs +8 -8
  47. package/fesm2022/ngwr-badge.mjs.map +1 -1
  48. package/fesm2022/ngwr-bar-chart.mjs +4 -4
  49. package/fesm2022/ngwr-bar-chart.mjs.map +1 -1
  50. package/fesm2022/ngwr-blur-text.mjs +3 -3
  51. package/fesm2022/ngwr-border-glow.mjs +4 -4
  52. package/fesm2022/ngwr-border-glow.mjs.map +1 -1
  53. package/fesm2022/ngwr-breadcrumbs.mjs +8 -8
  54. package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
  55. package/fesm2022/ngwr-burger.mjs +4 -4
  56. package/fesm2022/ngwr-burger.mjs.map +1 -1
  57. package/fesm2022/ngwr-button.mjs +8 -8
  58. package/fesm2022/ngwr-button.mjs.map +1 -1
  59. package/fesm2022/ngwr-calendar-heatmap.mjs +4 -4
  60. package/fesm2022/ngwr-calendar-heatmap.mjs.map +1 -1
  61. package/fesm2022/ngwr-calendar.mjs +4 -4
  62. package/fesm2022/ngwr-calendar.mjs.map +1 -1
  63. package/fesm2022/ngwr-card.mjs +11 -11
  64. package/fesm2022/ngwr-card.mjs.map +1 -1
  65. package/fesm2022/ngwr-carousel.mjs +7 -7
  66. package/fesm2022/ngwr-carousel.mjs.map +1 -1
  67. package/fesm2022/ngwr-cascader.mjs +52 -60
  68. package/fesm2022/ngwr-cascader.mjs.map +1 -1
  69. package/fesm2022/ngwr-checkbox.mjs +74 -106
  70. package/fesm2022/ngwr-checkbox.mjs.map +1 -1
  71. package/fesm2022/ngwr-circular-text.mjs +5 -4
  72. package/fesm2022/ngwr-circular-text.mjs.map +1 -1
  73. package/fesm2022/ngwr-click-spark.mjs +5 -4
  74. package/fesm2022/ngwr-click-spark.mjs.map +1 -1
  75. package/fesm2022/ngwr-clipboard.mjs +4 -4
  76. package/fesm2022/ngwr-clipboard.mjs.map +1 -1
  77. package/fesm2022/ngwr-collapse.mjs +12 -12
  78. package/fesm2022/ngwr-collapse.mjs.map +1 -1
  79. package/fesm2022/ngwr-color-picker.mjs +58 -66
  80. package/fesm2022/ngwr-color-picker.mjs.map +1 -1
  81. package/fesm2022/ngwr-command-palette.mjs +4 -4
  82. package/fesm2022/ngwr-command-palette.mjs.map +1 -1
  83. package/fesm2022/ngwr-compare.mjs +4 -4
  84. package/fesm2022/ngwr-compare.mjs.map +1 -1
  85. package/fesm2022/ngwr-confetti.mjs +3 -3
  86. package/fesm2022/ngwr-context-menu.mjs +86 -15
  87. package/fesm2022/ngwr-context-menu.mjs.map +1 -1
  88. package/fesm2022/ngwr-cookie.mjs +19 -6
  89. package/fesm2022/ngwr-cookie.mjs.map +1 -1
  90. package/fesm2022/ngwr-counter.mjs +26 -12
  91. package/fesm2022/ngwr-counter.mjs.map +1 -1
  92. package/fesm2022/ngwr-date-adapter-fns.mjs +3 -3
  93. package/fesm2022/ngwr-date-adapter-luxon.mjs +3 -3
  94. package/fesm2022/ngwr-date-adapter.mjs +10 -5
  95. package/fesm2022/ngwr-date-adapter.mjs.map +1 -1
  96. package/fesm2022/ngwr-date-picker.mjs +128 -123
  97. package/fesm2022/ngwr-date-picker.mjs.map +1 -1
  98. package/fesm2022/ngwr-decrypt-text.mjs +3 -3
  99. package/fesm2022/ngwr-density.mjs +7 -7
  100. package/fesm2022/ngwr-density.mjs.map +1 -1
  101. package/fesm2022/ngwr-descriptions.mjs +7 -7
  102. package/fesm2022/ngwr-descriptions.mjs.map +1 -1
  103. package/fesm2022/ngwr-dialog.mjs +16 -16
  104. package/fesm2022/ngwr-dialog.mjs.map +1 -1
  105. package/fesm2022/ngwr-directives.mjs +21 -15
  106. package/fesm2022/ngwr-directives.mjs.map +1 -1
  107. package/fesm2022/ngwr-divider.mjs +4 -4
  108. package/fesm2022/ngwr-divider.mjs.map +1 -1
  109. package/fesm2022/ngwr-donut-chart.mjs +4 -4
  110. package/fesm2022/ngwr-donut-chart.mjs.map +1 -1
  111. package/fesm2022/ngwr-drag-drop.mjs +10 -9
  112. package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
  113. package/fesm2022/ngwr-drawer.mjs +19 -18
  114. package/fesm2022/ngwr-drawer.mjs.map +1 -1
  115. package/fesm2022/ngwr-dropdown.mjs +13 -12
  116. package/fesm2022/ngwr-dropdown.mjs.map +1 -1
  117. package/fesm2022/ngwr-empty.mjs +4 -4
  118. package/fesm2022/ngwr-empty.mjs.map +1 -1
  119. package/fesm2022/ngwr-falling-text.mjs +5 -4
  120. package/fesm2022/ngwr-falling-text.mjs.map +1 -1
  121. package/fesm2022/ngwr-file-upload.mjs +58 -60
  122. package/fesm2022/ngwr-file-upload.mjs.map +1 -1
  123. package/fesm2022/ngwr-form.mjs +11 -11
  124. package/fesm2022/ngwr-form.mjs.map +1 -1
  125. package/fesm2022/ngwr-fuzzy-text.mjs +5 -4
  126. package/fesm2022/ngwr-fuzzy-text.mjs.map +1 -1
  127. package/fesm2022/ngwr-gauge.mjs +4 -4
  128. package/fesm2022/ngwr-gauge.mjs.map +1 -1
  129. package/fesm2022/ngwr-glitch-text.mjs +4 -4
  130. package/fesm2022/ngwr-glitch-text.mjs.map +1 -1
  131. package/fesm2022/ngwr-gradient-text.mjs +4 -4
  132. package/fesm2022/ngwr-gradient-text.mjs.map +1 -1
  133. package/fesm2022/ngwr-hotkey.mjs +7 -7
  134. package/fesm2022/ngwr-hotkey.mjs.map +1 -1
  135. package/fesm2022/ngwr-i18n.mjs +10 -10
  136. package/fesm2022/ngwr-i18n.mjs.map +1 -1
  137. package/fesm2022/ngwr-icon-adapters-lucide.mjs +6 -7
  138. package/fesm2022/ngwr-icon-adapters-lucide.mjs.map +1 -1
  139. package/fesm2022/ngwr-icon.mjs +4 -4
  140. package/fesm2022/ngwr-icon.mjs.map +1 -1
  141. package/fesm2022/ngwr-image-cropper.mjs +6 -5
  142. package/fesm2022/ngwr-image-cropper.mjs.map +1 -1
  143. package/fesm2022/ngwr-input-number.mjs +56 -73
  144. package/fesm2022/ngwr-input-number.mjs.map +1 -1
  145. package/fesm2022/ngwr-input-otp.mjs +46 -52
  146. package/fesm2022/ngwr-input-otp.mjs.map +1 -1
  147. package/fesm2022/ngwr-input.mjs +17 -17
  148. package/fesm2022/ngwr-input.mjs.map +1 -1
  149. package/fesm2022/ngwr-keyboard.mjs +4 -4
  150. package/fesm2022/ngwr-keyboard.mjs.map +1 -1
  151. package/fesm2022/ngwr-knob.mjs +47 -58
  152. package/fesm2022/ngwr-knob.mjs.map +1 -1
  153. package/fesm2022/ngwr-layout.mjs +16 -16
  154. package/fesm2022/ngwr-layout.mjs.map +1 -1
  155. package/fesm2022/ngwr-lightbox.mjs +7 -6
  156. package/fesm2022/ngwr-lightbox.mjs.map +1 -1
  157. package/fesm2022/ngwr-line-chart.mjs +4 -4
  158. package/fesm2022/ngwr-line-chart.mjs.map +1 -1
  159. package/fesm2022/ngwr-list.mjs +8 -8
  160. package/fesm2022/ngwr-list.mjs.map +1 -1
  161. package/fesm2022/ngwr-loading-bar.mjs +7 -7
  162. package/fesm2022/ngwr-loading-bar.mjs.map +1 -1
  163. package/fesm2022/ngwr-marquee.mjs +6 -5
  164. package/fesm2022/ngwr-marquee.mjs.map +1 -1
  165. package/fesm2022/ngwr-media.mjs +4 -4
  166. package/fesm2022/ngwr-media.mjs.map +1 -1
  167. package/fesm2022/ngwr-mention.mjs +15 -9
  168. package/fesm2022/ngwr-mention.mjs.map +1 -1
  169. package/fesm2022/ngwr-meta.mjs +7 -7
  170. package/fesm2022/ngwr-meta.mjs.map +1 -1
  171. package/fesm2022/ngwr-meter-group.mjs +4 -4
  172. package/fesm2022/ngwr-meter-group.mjs.map +1 -1
  173. package/fesm2022/ngwr-overlay.mjs +9 -4
  174. package/fesm2022/ngwr-overlay.mjs.map +1 -1
  175. package/fesm2022/ngwr-page-header.mjs +4 -4
  176. package/fesm2022/ngwr-page-header.mjs.map +1 -1
  177. package/fesm2022/ngwr-pagination.mjs +4 -4
  178. package/fesm2022/ngwr-pagination.mjs.map +1 -1
  179. package/fesm2022/ngwr-pipes.mjs +21 -21
  180. package/fesm2022/ngwr-platform.mjs +169 -5
  181. package/fesm2022/ngwr-platform.mjs.map +1 -1
  182. package/fesm2022/ngwr-popconfirm.mjs +7 -7
  183. package/fesm2022/ngwr-popconfirm.mjs.map +1 -1
  184. package/fesm2022/ngwr-popover.mjs +7 -7
  185. package/fesm2022/ngwr-popover.mjs.map +1 -1
  186. package/fesm2022/ngwr-progress.mjs +4 -4
  187. package/fesm2022/ngwr-progress.mjs.map +1 -1
  188. package/fesm2022/ngwr-pull-to-refresh.mjs +172 -0
  189. package/fesm2022/ngwr-pull-to-refresh.mjs.map +1 -0
  190. package/fesm2022/ngwr-qr.mjs +5 -5
  191. package/fesm2022/ngwr-qr.mjs.map +1 -1
  192. package/fesm2022/ngwr-radio.mjs +27 -52
  193. package/fesm2022/ngwr-radio.mjs.map +1 -1
  194. package/fesm2022/ngwr-rating.mjs +35 -48
  195. package/fesm2022/ngwr-rating.mjs.map +1 -1
  196. package/fesm2022/ngwr-result.mjs +13 -13
  197. package/fesm2022/ngwr-result.mjs.map +1 -1
  198. package/fesm2022/ngwr-rotating-text.mjs +15 -4
  199. package/fesm2022/ngwr-rotating-text.mjs.map +1 -1
  200. package/fesm2022/ngwr-scroll.mjs +4 -4
  201. package/fesm2022/ngwr-scroll.mjs.map +1 -1
  202. package/fesm2022/ngwr-segmented.mjs +3 -3
  203. package/fesm2022/ngwr-segmented.mjs.map +1 -1
  204. package/fesm2022/ngwr-select.mjs +289 -85
  205. package/fesm2022/ngwr-select.mjs.map +1 -1
  206. package/fesm2022/ngwr-shiny-text.mjs +7 -7
  207. package/fesm2022/ngwr-shiny-text.mjs.map +1 -1
  208. package/fesm2022/ngwr-sidebar.mjs +4 -4
  209. package/fesm2022/ngwr-sidebar.mjs.map +1 -1
  210. package/fesm2022/ngwr-skeleton.mjs +4 -4
  211. package/fesm2022/ngwr-skeleton.mjs.map +1 -1
  212. package/fesm2022/ngwr-slider.mjs +79 -73
  213. package/fesm2022/ngwr-slider.mjs.map +1 -1
  214. package/fesm2022/ngwr-sparkline.mjs +4 -4
  215. package/fesm2022/ngwr-sparkline.mjs.map +1 -1
  216. package/fesm2022/ngwr-speed-dial.mjs +13 -5
  217. package/fesm2022/ngwr-speed-dial.mjs.map +1 -1
  218. package/fesm2022/ngwr-spinner.mjs +4 -4
  219. package/fesm2022/ngwr-spinner.mjs.map +1 -1
  220. package/fesm2022/ngwr-splash-cursor.mjs +4 -4
  221. package/fesm2022/ngwr-splash-cursor.mjs.map +1 -1
  222. package/fesm2022/ngwr-split-text.mjs +3 -3
  223. package/fesm2022/ngwr-splitter.mjs +4 -4
  224. package/fesm2022/ngwr-splitter.mjs.map +1 -1
  225. package/fesm2022/ngwr-spotlight-card.mjs +7 -7
  226. package/fesm2022/ngwr-spotlight-card.mjs.map +1 -1
  227. package/fesm2022/ngwr-squircle.mjs +7 -7
  228. package/fesm2022/ngwr-squircle.mjs.map +1 -1
  229. package/fesm2022/ngwr-star-border.mjs +4 -4
  230. package/fesm2022/ngwr-star-border.mjs.map +1 -1
  231. package/fesm2022/ngwr-statistic.mjs +65 -10
  232. package/fesm2022/ngwr-statistic.mjs.map +1 -1
  233. package/fesm2022/ngwr-stepper.mjs +8 -8
  234. package/fesm2022/ngwr-stepper.mjs.map +1 -1
  235. package/fesm2022/ngwr-storage.mjs +4 -4
  236. package/fesm2022/ngwr-storage.mjs.map +1 -1
  237. package/fesm2022/ngwr-switch.mjs +16 -48
  238. package/fesm2022/ngwr-switch.mjs.map +1 -1
  239. package/fesm2022/ngwr-table.mjs +824 -20
  240. package/fesm2022/ngwr-table.mjs.map +1 -1
  241. package/fesm2022/ngwr-tabs.mjs +9 -8
  242. package/fesm2022/ngwr-tabs.mjs.map +1 -1
  243. package/fesm2022/ngwr-textarea.mjs +18 -50
  244. package/fesm2022/ngwr-textarea.mjs.map +1 -1
  245. package/fesm2022/ngwr-theme.mjs +20 -5
  246. package/fesm2022/ngwr-theme.mjs.map +1 -1
  247. package/fesm2022/ngwr-tilt-card.mjs +27 -11
  248. package/fesm2022/ngwr-tilt-card.mjs.map +1 -1
  249. package/fesm2022/ngwr-timeline.mjs +7 -7
  250. package/fesm2022/ngwr-timeline.mjs.map +1 -1
  251. package/fesm2022/ngwr-toast.mjs +10 -10
  252. package/fesm2022/ngwr-toast.mjs.map +1 -1
  253. package/fesm2022/ngwr-toolbar.mjs +4 -4
  254. package/fesm2022/ngwr-toolbar.mjs.map +1 -1
  255. package/fesm2022/ngwr-tree.mjs +280 -84
  256. package/fesm2022/ngwr-tree.mjs.map +1 -1
  257. package/fesm2022/ngwr-typewriter.mjs +10 -5
  258. package/fesm2022/ngwr-typewriter.mjs.map +1 -1
  259. package/fesm2022/ngwr-typography.mjs +4 -4
  260. package/fesm2022/ngwr-typography.mjs.map +1 -1
  261. package/fesm2022/ngwr-validators.mjs +1 -1
  262. package/fesm2022/ngwr-validators.mjs.map +1 -1
  263. package/fesm2022/ngwr-version.mjs +1 -1
  264. package/fesm2022/ngwr-version.mjs.map +1 -1
  265. package/fesm2022/ngwr-virtual-scroll.mjs +9 -7
  266. package/fesm2022/ngwr-virtual-scroll.mjs.map +1 -1
  267. package/fesm2022/ngwr-waves.mjs +6 -5
  268. package/fesm2022/ngwr-waves.mjs.map +1 -1
  269. package/fesm2022/ngwr-window.mjs +16 -15
  270. package/fesm2022/ngwr-window.mjs.map +1 -1
  271. package/file-upload/styles/_index.scss +11 -11
  272. package/form/styles/_index.scss +4 -4
  273. package/gauge/styles/_index.scss +2 -2
  274. package/glitch-text/styles/_index.scss +1 -1
  275. package/gradient-text/styles/_index.scss +1 -1
  276. package/image-cropper/styles/_index.scss +5 -4
  277. package/input/styles/_index.scss +9 -9
  278. package/input-number/styles/_index.scss +1 -1
  279. package/input-otp/styles/_index.scss +5 -5
  280. package/keyboard/styles/_index.scss +5 -5
  281. package/knob/styles/_index.scss +6 -2
  282. package/layout/styles/_index.scss +12 -12
  283. package/lightbox/styles/_index.scss +10 -8
  284. package/line-chart/styles/_index.scss +5 -5
  285. package/list/styles/_index.scss +3 -3
  286. package/llms-full.txt +31 -5
  287. package/llms.txt +48 -32
  288. package/marquee/styles/_index.scss +1 -1
  289. package/mention/styles/_index.scss +4 -4
  290. package/meter-group/styles/_index.scss +4 -4
  291. package/overlay/styles/_index.scss +8 -0
  292. package/package.json +21 -9
  293. package/page-header/styles/_index.scss +4 -4
  294. package/pagination/styles/_index.scss +3 -3
  295. package/popconfirm/styles/_index.scss +3 -3
  296. package/popover/styles/_index.scss +5 -5
  297. package/progress/styles/_index.scss +1 -1
  298. package/pull-to-refresh/styles/_index.scss +38 -0
  299. package/radio/styles/_index.scss +4 -4
  300. package/rating/styles/_index.scss +1 -1
  301. package/result/styles/_index.scss +3 -3
  302. package/schematics/migrations/v9/index.js +71 -0
  303. package/schematics/migrations.json +5 -0
  304. package/schematics/ng-add/schema.json +1 -1
  305. package/schematics/use/symbol-map.json +13 -0
  306. package/segmented/styles/_index.scss +4 -4
  307. package/select/styles/_index.scss +53 -18
  308. package/shiny-text/styles/_index.scss +4 -4
  309. package/sidebar/styles/_index.scss +12 -12
  310. package/slider/styles/_index.scss +5 -5
  311. package/speed-dial/styles/_index.scss +22 -6
  312. package/splash-cursor/styles/_index.scss +1 -0
  313. package/splitter/styles/_index.scss +7 -4
  314. package/spotlight-card/styles/_index.scss +7 -7
  315. package/star-border/styles/_index.scss +3 -3
  316. package/statistic/styles/_index.scss +51 -4
  317. package/stepper/styles/_index.scss +6 -6
  318. package/styles/_typography.scss +4 -1
  319. package/styles.scss +2 -0
  320. package/switch/styles/_index.scss +4 -4
  321. package/table/styles/_index.scss +447 -17
  322. package/tabs/styles/_index.scss +3 -3
  323. package/textarea/styles/_index.scss +7 -7
  324. package/theme/styles/_colors.scss +27 -3
  325. package/tilt-card/styles/_index.scss +4 -4
  326. package/timeline/styles/_index.scss +7 -6
  327. package/toast/styles/_index.scss +11 -11
  328. package/toolbar/styles/_index.scss +4 -4
  329. package/tree/styles/_index.scss +45 -15
  330. package/types/ngwr-action-sheet.d.ts +75 -0
  331. package/types/ngwr-alert.d.ts +1 -1
  332. package/types/ngwr-anchor.d.ts +1 -1
  333. package/types/ngwr-avatar.d.ts +1 -1
  334. package/types/ngwr-back-top.d.ts +1 -1
  335. package/types/ngwr-badge.d.ts +4 -4
  336. package/types/ngwr-bar-chart.d.ts +1 -1
  337. package/types/ngwr-breadcrumbs.d.ts +1 -1
  338. package/types/ngwr-burger.d.ts +1 -1
  339. package/types/ngwr-button.d.ts +3 -3
  340. package/types/ngwr-calendar-heatmap.d.ts +1 -1
  341. package/types/ngwr-calendar.d.ts +1 -1
  342. package/types/ngwr-card.d.ts +1 -1
  343. package/types/ngwr-carousel.d.ts +1 -1
  344. package/types/ngwr-cascader.d.ts +27 -16
  345. package/types/ngwr-checkbox.d.ts +63 -43
  346. package/types/ngwr-clipboard.d.ts +1 -1
  347. package/types/ngwr-collapse.d.ts +3 -3
  348. package/types/ngwr-color-picker.d.ts +24 -19
  349. package/types/ngwr-command-palette.d.ts +1 -1
  350. package/types/ngwr-compare.d.ts +1 -1
  351. package/types/ngwr-context-menu.d.ts +25 -1
  352. package/types/ngwr-cookie.d.ts +7 -1
  353. package/types/ngwr-counter.d.ts +9 -2
  354. package/types/ngwr-date-picker.d.ts +36 -23
  355. package/types/ngwr-density.d.ts +1 -1
  356. package/types/ngwr-descriptions.d.ts +1 -1
  357. package/types/ngwr-dialog.d.ts +1 -1
  358. package/types/ngwr-directives.d.ts +1 -0
  359. package/types/ngwr-divider.d.ts +2 -2
  360. package/types/ngwr-donut-chart.d.ts +1 -1
  361. package/types/ngwr-drag-drop.d.ts +1 -1
  362. package/types/ngwr-drawer.d.ts +1 -1
  363. package/types/ngwr-dropdown.d.ts +1 -1
  364. package/types/ngwr-empty.d.ts +1 -1
  365. package/types/ngwr-file-upload.d.ts +28 -17
  366. package/types/ngwr-form.d.ts +2 -2
  367. package/types/ngwr-gauge.d.ts +1 -1
  368. package/types/ngwr-hotkey.d.ts +1 -1
  369. package/types/ngwr-i18n.d.ts +1 -1
  370. package/types/ngwr-icon-adapters-lucide.d.ts +5 -3
  371. package/types/ngwr-icon.d.ts +1 -1
  372. package/types/ngwr-image-cropper.d.ts +1 -1
  373. package/types/ngwr-input-number.d.ts +25 -19
  374. package/types/ngwr-input-otp.d.ts +23 -17
  375. package/types/ngwr-input.d.ts +2 -2
  376. package/types/ngwr-keyboard.d.ts +1 -1
  377. package/types/ngwr-knob.d.ts +24 -19
  378. package/types/ngwr-layout.d.ts +1 -1
  379. package/types/ngwr-lightbox.d.ts +1 -1
  380. package/types/ngwr-line-chart.d.ts +1 -1
  381. package/types/ngwr-list.d.ts +1 -1
  382. package/types/ngwr-loading-bar.d.ts +1 -1
  383. package/types/ngwr-marquee.d.ts +1 -1
  384. package/types/ngwr-media.d.ts +1 -1
  385. package/types/ngwr-mention.d.ts +1 -1
  386. package/types/ngwr-meta.d.ts +1 -1
  387. package/types/ngwr-meter-group.d.ts +1 -1
  388. package/types/ngwr-page-header.d.ts +1 -1
  389. package/types/ngwr-pagination.d.ts +1 -1
  390. package/types/ngwr-platform.d.ts +93 -2
  391. package/types/ngwr-popconfirm.d.ts +3 -3
  392. package/types/ngwr-progress.d.ts +2 -2
  393. package/types/ngwr-pull-to-refresh.d.ts +69 -0
  394. package/types/ngwr-qr.d.ts +1 -1
  395. package/types/ngwr-radio.d.ts +25 -22
  396. package/types/ngwr-rating.d.ts +28 -20
  397. package/types/ngwr-result.d.ts +1 -1
  398. package/types/ngwr-rotating-text.d.ts +1 -0
  399. package/types/ngwr-scroll.d.ts +1 -1
  400. package/types/ngwr-segmented.d.ts +1 -1
  401. package/types/ngwr-select.d.ts +93 -26
  402. package/types/ngwr-sidebar.d.ts +1 -1
  403. package/types/ngwr-skeleton.d.ts +2 -2
  404. package/types/ngwr-slider.d.ts +35 -21
  405. package/types/ngwr-sparkline.d.ts +1 -1
  406. package/types/ngwr-speed-dial.d.ts +8 -2
  407. package/types/ngwr-spinner.d.ts +1 -1
  408. package/types/ngwr-splitter.d.ts +1 -1
  409. package/types/ngwr-squircle.d.ts +1 -1
  410. package/types/ngwr-statistic.d.ts +40 -5
  411. package/types/ngwr-stepper.d.ts +2 -2
  412. package/types/ngwr-storage.d.ts +1 -1
  413. package/types/ngwr-switch.d.ts +20 -16
  414. package/types/ngwr-table.d.ts +417 -6
  415. package/types/ngwr-tabs.d.ts +1 -1
  416. package/types/ngwr-textarea.d.ts +21 -18
  417. package/types/ngwr-theme.d.ts +7 -2
  418. package/types/ngwr-tilt-card.d.ts +3 -0
  419. package/types/ngwr-timeline.d.ts +1 -1
  420. package/types/ngwr-toast.d.ts +1 -1
  421. package/types/ngwr-toolbar.d.ts +1 -1
  422. package/types/ngwr-tree.d.ts +100 -19
  423. package/types/ngwr-typography.d.ts +1 -1
  424. package/types/ngwr-validators.d.ts +1 -1
  425. package/types/ngwr-version.d.ts +1 -1
  426. package/types/ngwr-virtual-scroll.d.ts +1 -1
  427. package/types/ngwr-window.d.ts +1 -1
  428. package/typography/styles/_index.scss +11 -11
  429. package/virtual-scroll/styles/_index.scss +1 -1
  430. package/waves/styles/_index.scss +1 -1
  431. package/window/styles/_index.scss +18 -18
@@ -104,7 +104,8 @@ class WrFallingText {
104
104
  /** Font size as a CSS length. @default '1rem' */
105
105
  fontSize = input('1rem', /* @ts-ignore */
106
106
  ...(ngDevMode ? [{ debugName: "fontSize" }] : /* istanbul ignore next */ []));
107
- wordsRef = viewChild.required('wordsContainer');
107
+ wordsRef = viewChild.required('wordsContainer', /* @ts-ignore */
108
+ ...(ngDevMode ? [{ debugName: "wordsRef" }] : /* istanbul ignore next */ []));
108
109
  host = inject(ElementRef);
109
110
  destroyRef = inject(DestroyRef);
110
111
  isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
@@ -300,10 +301,10 @@ class WrFallingText {
300
301
  const rect = host.getBoundingClientRect();
301
302
  return { x: e.clientX - rect.left, y: e.clientY - rect.top };
302
303
  }
303
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: WrFallingText, deps: [], target: i0.ɵɵFactoryTarget.Component });
304
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: WrFallingText, isStandalone: true, selector: "wr-falling-text", inputs: { text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: true, transformFunction: null }, highlightWords: { classPropertyName: "highlightWords", publicName: "highlightWords", isSignal: true, isRequired: false, transformFunction: null }, trigger: { classPropertyName: "trigger", publicName: "trigger", isSignal: true, isRequired: false, transformFunction: null }, gravity: { classPropertyName: "gravity", publicName: "gravity", isSignal: true, isRequired: false, transformFunction: null }, fontSize: { classPropertyName: "fontSize", publicName: "fontSize", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "wr-falling-text" }, viewQueries: [{ propertyName: "wordsRef", first: true, predicate: ["wordsContainer"], descendants: true, isSignal: true }], ngImport: i0, template: "<div #wordsContainer class=\"wr-falling-text__words\" [style.font-size]=\"fontSize()\">\n @for (w of words(); track $index) {\n <span class=\"wr-falling-text__word\" [class.wr-falling-text__word--hl]=\"w.highlighted\">{{ w.text }}</span>\n @if (!$last) {\n <span class=\"wr-falling-text__space\">&nbsp;</span>\n }\n }\n</div>\n", styles: [".wr-falling-text{position:relative;display:block;overflow:hidden;touch-action:none}.wr-falling-text__words{line-height:1.4}.wr-falling-text__word{display:inline-block;will-change:transform;-webkit-user-select:none;user-select:none;cursor:grab}.wr-falling-text__word:active{cursor:grabbing}.wr-falling-text__word--hl{color:var(--wr-color-primary)}.wr-falling-text__space{display:inline;white-space:pre}\n"], encapsulation: i0.ViewEncapsulation.None });
304
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrFallingText, deps: [], target: i0.ɵɵFactoryTarget.Component });
305
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: WrFallingText, isStandalone: true, selector: "wr-falling-text", inputs: { text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: true, transformFunction: null }, highlightWords: { classPropertyName: "highlightWords", publicName: "highlightWords", isSignal: true, isRequired: false, transformFunction: null }, trigger: { classPropertyName: "trigger", publicName: "trigger", isSignal: true, isRequired: false, transformFunction: null }, gravity: { classPropertyName: "gravity", publicName: "gravity", isSignal: true, isRequired: false, transformFunction: null }, fontSize: { classPropertyName: "fontSize", publicName: "fontSize", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "wr-falling-text" }, viewQueries: [{ propertyName: "wordsRef", first: true, predicate: ["wordsContainer"], descendants: true, isSignal: true }], ngImport: i0, template: "<div #wordsContainer class=\"wr-falling-text__words\" [style.font-size]=\"fontSize()\">\n @for (w of words(); track $index) {\n <span class=\"wr-falling-text__word\" [class.wr-falling-text__word--hl]=\"w.highlighted\">{{ w.text }}</span>\n @if (!$last) {\n <span class=\"wr-falling-text__space\">&nbsp;</span>\n }\n }\n</div>\n", styles: [".wr-falling-text{position:relative;display:block;overflow:hidden;touch-action:none}.wr-falling-text__words{line-height:1.4}.wr-falling-text__word{display:inline-block;will-change:transform;-webkit-user-select:none;user-select:none;cursor:grab}.wr-falling-text__word:active{cursor:grabbing}.wr-falling-text__word--hl{color:var(--wr-color-primary)}.wr-falling-text__space{display:inline;white-space:pre}\n"], encapsulation: i0.ViewEncapsulation.None });
305
306
  }
306
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: WrFallingText, decorators: [{
307
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrFallingText, decorators: [{
307
308
  type: Component,
308
309
  args: [{ selector: 'wr-falling-text', encapsulation: ViewEncapsulation.None, host: { class: 'wr-falling-text' }, template: "<div #wordsContainer class=\"wr-falling-text__words\" [style.font-size]=\"fontSize()\">\n @for (w of words(); track $index) {\n <span class=\"wr-falling-text__word\" [class.wr-falling-text__word--hl]=\"w.highlighted\">{{ w.text }}</span>\n @if (!$last) {\n <span class=\"wr-falling-text__space\">&nbsp;</span>\n }\n }\n</div>\n", styles: [".wr-falling-text{position:relative;display:block;overflow:hidden;touch-action:none}.wr-falling-text__words{line-height:1.4}.wr-falling-text__word{display:inline-block;will-change:transform;-webkit-user-select:none;user-select:none;cursor:grab}.wr-falling-text__word:active{cursor:grabbing}.wr-falling-text__word--hl{color:var(--wr-color-primary)}.wr-falling-text__space{display:inline;white-space:pre}\n"] }]
309
310
  }], ctorParameters: () => [], propDecorators: { text: [{ type: i0.Input, args: [{ isSignal: true, alias: "text", required: true }] }], highlightWords: [{ type: i0.Input, args: [{ isSignal: true, alias: "highlightWords", required: false }] }], trigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "trigger", required: false }] }], gravity: [{ type: i0.Input, args: [{ isSignal: true, alias: "gravity", required: false }] }], fontSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "fontSize", required: false }] }], wordsRef: [{ type: i0.ViewChild, args: ['wordsContainer', { isSignal: true }] }] } });
@@ -1 +1 @@
1
- {"version":3,"file":"ngwr-falling-text.mjs","sources":["../../../projects/lib/falling-text/falling-text.ts","../../../projects/lib/falling-text/falling-text.html","../../../projects/lib/falling-text/ngwr-falling-text.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 * Angular adaptation of the FallingText effect by David Haz / reactbits.dev.\n * Original: https://www.reactbits.dev/text-animations/falling-text\n *\n * The reactbits version uses matter-js (~140 KB) for the physics. This\n * port ships a minimal AABB physics simulator (gravity + air drag + wall\n * / floor collision + body-vs-body resolution + cursor drag) so there's\n * no runtime dependency.\n */\n\nimport { isPlatformBrowser } from '@angular/common';\nimport {\n Component,\n DestroyRef,\n ElementRef,\n PLATFORM_ID,\n ViewEncapsulation,\n afterNextRender,\n computed,\n inject,\n input,\n viewChild,\n} from '@angular/core';\n\nimport { WrPlatform } from 'ngwr/platform';\nimport { numAttr } from 'ngwr/utils';\n\nimport type { WrFallingTextTrigger } from './interfaces';\n\ninterface Body {\n el: HTMLElement;\n x: number; // centre x\n y: number; // centre y\n vx: number;\n vy: number;\n angle: number;\n angVel: number;\n w: number;\n h: number;\n}\n\nconst RESTITUTION = 0.55;\nconst AIR_DRAG = 0.005;\nconst FRICTION = 0.4; // tangential damping on wall/floor hits\nconst DRAG_STIFFNESS = 0.6;\n\n/** Resolve AABB-vs-AABB collision between two bodies via min-overlap axis. */\nfunction resolveCollision(a: Body, b: Body): void {\n const dx = b.x - a.x;\n const dy = b.y - a.y;\n const overlapX = a.w / 2 + b.w / 2 - Math.abs(dx);\n const overlapY = a.h / 2 + b.h / 2 - Math.abs(dy);\n if (overlapX <= 0 || overlapY <= 0) return;\n\n if (overlapX < overlapY) {\n // Resolve along x.\n const push = overlapX / 2;\n if (dx > 0) {\n a.x -= push;\n b.x += push;\n } else {\n a.x += push;\n b.x -= push;\n }\n const avg = (a.vx + b.vx) / 2;\n a.vx = avg * RESTITUTION - (a.vx - avg) * RESTITUTION;\n b.vx = avg * RESTITUTION - (b.vx - avg) * RESTITUTION;\n } else {\n const push = overlapY / 2;\n if (dy > 0) {\n a.y -= push;\n b.y += push;\n } else {\n a.y += push;\n b.y -= push;\n }\n const avg = (a.vy + b.vy) / 2;\n a.vy = avg * RESTITUTION - (a.vy - avg) * RESTITUTION;\n b.vy = avg * RESTITUTION - (b.vy - avg) * RESTITUTION;\n }\n\n // Tiny torque so stacked bodies wiggle naturally.\n a.angVel += (Math.random() - 0.5) * 0.2;\n b.angVel += (Math.random() - 0.5) * 0.2;\n}\n\n/**\n * Words fall like physical bodies — gravity, wall/floor collision, and\n * cursor drag-to-pick-up. Words start at their typeset position then\n * release into the simulator on trigger.\n *\n * Triggers:\n * - `'auto'` release immediately on mount\n * - `'scroll'` release on viewport entry\n * - `'hover'` release on first hover\n * - `'click'` release on first click\n *\n * Highlight specific words by passing prefix-matched keywords via\n * `[highlightWords]` — matched spans get `wr-falling-text__word--hl`.\n *\n * @example\n * ```html\n * <wr-falling-text\n * text=\"React-Bits is a library of animated and interactive React components.\"\n * [highlightWords]=\"['React', 'animated', 'components']\"\n * trigger=\"hover\"\n * [gravity]=\"0.6\"\n * />\n * ```\n *\n * @see https://www.reactbits.dev/text-animations/falling-text\n */\n@Component({\n selector: 'wr-falling-text',\n templateUrl: './falling-text.html',\n styleUrl: './falling-text.scss',\n encapsulation: ViewEncapsulation.None,\n host: { class: 'wr-falling-text' },\n})\nexport class WrFallingText {\n /** Text to render. Words are separated by spaces. */\n readonly text = input.required<string>();\n\n /** Prefix-match keywords; any word starting with one of these gets the highlight class. */\n readonly highlightWords = input<readonly string[]>([]);\n\n /** When to release the words into the simulator. @default 'auto' */\n readonly trigger = input<WrFallingTextTrigger>('auto');\n\n /** Gravity in pixels/sec². @default 980 */\n readonly gravity = input(980, { transform: numAttr(980) });\n\n /** Font size as a CSS length. @default '1rem' */\n readonly fontSize = input('1rem');\n\n private readonly wordsRef = viewChild.required<ElementRef<HTMLDivElement>>('wordsContainer');\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly destroyRef = inject(DestroyRef);\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n private readonly platform = inject(WrPlatform);\n\n private started = false;\n private teardownLoop: (() => void) | undefined;\n\n protected readonly words = computed<readonly { text: string; highlighted: boolean }[]>(() => {\n const hl = this.highlightWords();\n return this.text()\n .split(' ')\n .filter(w => w.length > 0)\n .map(text => ({ text, highlighted: hl.some(h => text.startsWith(h)) }));\n });\n\n constructor() {\n if (!this.isBrowser) return;\n\n afterNextRender(() => {\n const trigger = this.trigger();\n if (trigger === 'auto') {\n this.start();\n return;\n }\n if (trigger === 'scroll') {\n const io = new IntersectionObserver(\n (entries, obs) => {\n for (const e of entries) {\n if (e.isIntersecting) {\n obs.disconnect();\n this.start();\n break;\n }\n }\n },\n { threshold: 0.1 }\n );\n io.observe(this.host.nativeElement);\n this.destroyRef.onDestroy(() => io.disconnect());\n return;\n }\n // hover / click — wait for host event\n const startOnce = (): void => {\n if (this.started) return;\n this.start();\n };\n const handler = trigger === 'hover' ? 'mouseenter' : 'click';\n this.host.nativeElement.addEventListener(handler, startOnce, { once: true });\n this.destroyRef.onDestroy(() => this.host.nativeElement.removeEventListener(handler, startOnce));\n });\n\n this.destroyRef.onDestroy(() => this.teardownLoop?.());\n }\n\n // Physics\n\n private start(): void {\n if (this.started) return;\n // Reduced motion: tumbling words are pure decoration — leave the\n // text standing in its normal layout no matter the trigger.\n if (this.platform.prefersReducedMotion()) return;\n this.started = true;\n\n const hostEl = this.host.nativeElement;\n const wordsContainer = this.wordsRef().nativeElement;\n const containerRect = hostEl.getBoundingClientRect();\n const width = containerRect.width;\n const height = containerRect.height;\n if (width <= 0 || height <= 0) return;\n\n // Snapshot each word's position relative to the container, then absolutise.\n const wordEls = Array.from(wordsContainer.querySelectorAll<HTMLElement>('.wr-falling-text__word'));\n if (wordEls.length === 0) return;\n\n const bodies: Body[] = wordEls.map(el => {\n const r = el.getBoundingClientRect();\n const cx = r.left - containerRect.left + r.width / 2;\n const cy = r.top - containerRect.top + r.height / 2;\n return {\n el,\n x: cx,\n y: cy,\n vx: (Math.random() - 0.5) * 5 * 60, // px/s\n vy: 0,\n angle: 0,\n angVel: (Math.random() - 0.5) * 2,\n w: r.width,\n h: r.height,\n };\n });\n\n // Absolutely position all word spans so we can move them freely.\n bodies.forEach(b => {\n b.el.style.position = 'absolute';\n b.el.style.left = '0';\n b.el.style.top = '0';\n b.el.style.willChange = 'transform';\n this.commit(b);\n });\n\n // Drag state.\n let drag: { body: Body; offX: number; offY: number } | null = null;\n\n const onPointerDown = (e: PointerEvent): void => {\n const local = this.toLocal(e, hostEl);\n // Pick the topmost (last) body whose AABB contains the pointer.\n for (let i = bodies.length - 1; i >= 0; i--) {\n const b = bodies[i];\n if (\n local.x >= b.x - b.w / 2 &&\n local.x <= b.x + b.w / 2 &&\n local.y >= b.y - b.h / 2 &&\n local.y <= b.y + b.h / 2\n ) {\n drag = { body: b, offX: local.x - b.x, offY: local.y - b.y };\n hostEl.setPointerCapture(e.pointerId);\n break;\n }\n }\n };\n const onPointerMove = (e: PointerEvent): void => {\n if (!drag) return;\n const local = this.toLocal(e, hostEl);\n const targetX = local.x - drag.offX;\n const targetY = local.y - drag.offY;\n // Spring toward the target — produces a satisfying tug rather than a snap.\n drag.body.vx += (targetX - drag.body.x) * DRAG_STIFFNESS;\n drag.body.vy += (targetY - drag.body.y) * DRAG_STIFFNESS;\n };\n const onPointerUp = (e: PointerEvent): void => {\n if (!drag) return;\n hostEl.releasePointerCapture(e.pointerId);\n drag = null;\n };\n hostEl.addEventListener('pointerdown', onPointerDown);\n hostEl.addEventListener('pointermove', onPointerMove);\n hostEl.addEventListener('pointerup', onPointerUp);\n hostEl.addEventListener('pointercancel', onPointerUp);\n\n let raf = 0;\n let lastTs = 0;\n const tick = (ts: number): void => {\n const dt = lastTs === 0 ? 1 / 60 : Math.min(0.05, (ts - lastTs) / 1000);\n lastTs = ts;\n\n const g = this.gravity();\n for (const b of bodies) {\n // Integrate.\n b.vy += g * dt;\n b.vx *= 1 - AIR_DRAG;\n b.vy *= 1 - AIR_DRAG;\n b.x += b.vx * dt;\n b.y += b.vy * dt;\n b.angle += b.angVel * dt;\n b.angVel *= 1 - AIR_DRAG;\n\n // Walls + floor + ceiling.\n if (b.x - b.w / 2 < 0) {\n b.x = b.w / 2;\n b.vx = Math.abs(b.vx) * RESTITUTION;\n b.angVel *= FRICTION;\n }\n if (b.x + b.w / 2 > width) {\n b.x = width - b.w / 2;\n b.vx = -Math.abs(b.vx) * RESTITUTION;\n b.angVel *= FRICTION;\n }\n if (b.y + b.h / 2 > height) {\n b.y = height - b.h / 2;\n b.vy = -Math.abs(b.vy) * RESTITUTION;\n b.vx *= FRICTION;\n b.angVel *= FRICTION;\n }\n if (b.y - b.h / 2 < 0) {\n b.y = b.h / 2;\n b.vy = Math.abs(b.vy) * RESTITUTION;\n }\n }\n\n // Body-vs-body collisions — O(n²), fine for ~30 words.\n for (let i = 0; i < bodies.length; i++) {\n for (let j = i + 1; j < bodies.length; j++) {\n resolveCollision(bodies[i], bodies[j]);\n }\n }\n\n for (const b of bodies) this.commit(b);\n raf = requestAnimationFrame(tick);\n };\n raf = requestAnimationFrame(tick);\n\n this.teardownLoop = (): void => {\n cancelAnimationFrame(raf);\n hostEl.removeEventListener('pointerdown', onPointerDown);\n hostEl.removeEventListener('pointermove', onPointerMove);\n hostEl.removeEventListener('pointerup', onPointerUp);\n hostEl.removeEventListener('pointercancel', onPointerUp);\n };\n }\n\n /** Apply the body's position + angle to the DOM. */\n private commit(b: Body): void {\n b.el.style.transform = `translate(${b.x - b.w / 2}px, ${b.y - b.h / 2}px) rotate(${b.angle}rad)`;\n b.el.style.transformOrigin = `${b.w / 2}px ${b.h / 2}px`;\n }\n\n private toLocal(e: PointerEvent | MouseEvent, host: HTMLElement): { x: number; y: number } {\n const rect = host.getBoundingClientRect();\n return { x: e.clientX - rect.left, y: e.clientY - rect.top };\n }\n}\n\nexport type { WrFallingTextTrigger } from './interfaces';\n","<div #wordsContainer class=\"wr-falling-text__words\" [style.font-size]=\"fontSize()\">\n @for (w of words(); track $index) {\n <span class=\"wr-falling-text__word\" [class.wr-falling-text__word--hl]=\"w.highlighted\">{{ w.text }}</span>\n @if (!$last) {\n <span class=\"wr-falling-text__space\">&nbsp;</span>\n }\n }\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;AAAA;;;;;;;;;;;;;AAaG;AAiCH,MAAM,WAAW,GAAG,IAAI;AACxB,MAAM,QAAQ,GAAG,KAAK;AACtB,MAAM,QAAQ,GAAG,GAAG,CAAC;AACrB,MAAM,cAAc,GAAG,GAAG;AAE1B;AACA,SAAS,gBAAgB,CAAC,CAAO,EAAE,CAAO,EAAA;IACxC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACpB,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACpB,MAAM,QAAQ,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;IACjD,MAAM,QAAQ,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;AACjD,IAAA,IAAI,QAAQ,IAAI,CAAC,IAAI,QAAQ,IAAI,CAAC;QAAE;AAEpC,IAAA,IAAI,QAAQ,GAAG,QAAQ,EAAE;;AAEvB,QAAA,MAAM,IAAI,GAAG,QAAQ,GAAG,CAAC;AACzB,QAAA,IAAI,EAAE,GAAG,CAAC,EAAE;AACV,YAAA,CAAC,CAAC,CAAC,IAAI,IAAI;AACX,YAAA,CAAC,CAAC,CAAC,IAAI,IAAI;QACb;aAAO;AACL,YAAA,CAAC,CAAC,CAAC,IAAI,IAAI;AACX,YAAA,CAAC,CAAC,CAAC,IAAI,IAAI;QACb;AACA,QAAA,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC;AAC7B,QAAA,CAAC,CAAC,EAAE,GAAG,GAAG,GAAG,WAAW,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,IAAI,WAAW;AACrD,QAAA,CAAC,CAAC,EAAE,GAAG,GAAG,GAAG,WAAW,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,IAAI,WAAW;IACvD;SAAO;AACL,QAAA,MAAM,IAAI,GAAG,QAAQ,GAAG,CAAC;AACzB,QAAA,IAAI,EAAE,GAAG,CAAC,EAAE;AACV,YAAA,CAAC,CAAC,CAAC,IAAI,IAAI;AACX,YAAA,CAAC,CAAC,CAAC,IAAI,IAAI;QACb;aAAO;AACL,YAAA,CAAC,CAAC,CAAC,IAAI,IAAI;AACX,YAAA,CAAC,CAAC,CAAC,IAAI,IAAI;QACb;AACA,QAAA,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC;AAC7B,QAAA,CAAC,CAAC,EAAE,GAAG,GAAG,GAAG,WAAW,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,IAAI,WAAW;AACrD,QAAA,CAAC,CAAC,EAAE,GAAG,GAAG,GAAG,WAAW,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,IAAI,WAAW;IACvD;;AAGA,IAAA,CAAC,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,IAAI,GAAG;AACvC,IAAA,CAAC,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,IAAI,GAAG;AACzC;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;AAyBG;MAQU,aAAa,CAAA;;IAEf,IAAI,GAAG,KAAK,CAAC,QAAQ;6EAAU;;IAG/B,cAAc,GAAG,KAAK,CAAoB,EAAE;uFAAC;;IAG7C,OAAO,GAAG,KAAK,CAAuB,MAAM;gFAAC;;AAG7C,IAAA,OAAO,GAAG,KAAK,CAAC,GAAG,EAAA,EAAA,IAAA,SAAA,GAAA,EAAA,SAAA,EAAA,SAAA,EAAA,8BAAA,EAAA,CAAA,EAAI,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,EAAA,CAAG;;IAGjD,QAAQ,GAAG,KAAK,CAAC,MAAM;iFAAC;AAEhB,IAAA,QAAQ,GAAG,SAAS,CAAC,QAAQ,CAA6B,gBAAgB,CAAC;AAE3E,IAAA,IAAI,GAAG,MAAM,CAA0B,UAAU,CAAC;AAClD,IAAA,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;IAC/B,SAAS,GAAG,iBAAiB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;AAClD,IAAA,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC;IAEtC,OAAO,GAAG,KAAK;AACf,IAAA,YAAY;AAED,IAAA,KAAK,GAAG,QAAQ,CAAoD,MAAK;AAC1F,QAAA,MAAM,EAAE,GAAG,IAAI,CAAC,cAAc,EAAE;QAChC,OAAO,IAAI,CAAC,IAAI;aACb,KAAK,CAAC,GAAG;aACT,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;AACxB,aAAA,GAAG,CAAC,IAAI,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC3E,CAAC;8EAAC;AAEF,IAAA,WAAA,GAAA;QACE,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE;QAErB,eAAe,CAAC,MAAK;AACnB,YAAA,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE;AAC9B,YAAA,IAAI,OAAO,KAAK,MAAM,EAAE;gBACtB,IAAI,CAAC,KAAK,EAAE;gBACZ;YACF;AACA,YAAA,IAAI,OAAO,KAAK,QAAQ,EAAE;gBACxB,MAAM,EAAE,GAAG,IAAI,oBAAoB,CACjC,CAAC,OAAO,EAAE,GAAG,KAAI;AACf,oBAAA,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE;AACvB,wBAAA,IAAI,CAAC,CAAC,cAAc,EAAE;4BACpB,GAAG,CAAC,UAAU,EAAE;4BAChB,IAAI,CAAC,KAAK,EAAE;4BACZ;wBACF;oBACF;AACF,gBAAA,CAAC,EACD,EAAE,SAAS,EAAE,GAAG,EAAE,CACnB;gBACD,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC;AACnC,gBAAA,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,UAAU,EAAE,CAAC;gBAChD;YACF;;YAEA,MAAM,SAAS,GAAG,MAAW;gBAC3B,IAAI,IAAI,CAAC,OAAO;oBAAE;gBAClB,IAAI,CAAC,KAAK,EAAE;AACd,YAAA,CAAC;AACD,YAAA,MAAM,OAAO,GAAG,OAAO,KAAK,OAAO,GAAG,YAAY,GAAG,OAAO;AAC5D,YAAA,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,OAAO,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;YAC5E,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,mBAAmB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;AAClG,QAAA,CAAC,CAAC;AAEF,QAAA,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,MAAM,IAAI,CAAC,YAAY,IAAI,CAAC;IACxD;;IAIQ,KAAK,GAAA;QACX,IAAI,IAAI,CAAC,OAAO;YAAE;;;AAGlB,QAAA,IAAI,IAAI,CAAC,QAAQ,CAAC,oBAAoB,EAAE;YAAE;AAC1C,QAAA,IAAI,CAAC,OAAO,GAAG,IAAI;AAEnB,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa;QACtC,MAAM,cAAc,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,aAAa;AACpD,QAAA,MAAM,aAAa,GAAG,MAAM,CAAC,qBAAqB,EAAE;AACpD,QAAA,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK;AACjC,QAAA,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM;AACnC,QAAA,IAAI,KAAK,IAAI,CAAC,IAAI,MAAM,IAAI,CAAC;YAAE;;AAG/B,QAAA,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,gBAAgB,CAAc,wBAAwB,CAAC,CAAC;AAClG,QAAA,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE;QAE1B,MAAM,MAAM,GAAW,OAAO,CAAC,GAAG,CAAC,EAAE,IAAG;AACtC,YAAA,MAAM,CAAC,GAAG,EAAE,CAAC,qBAAqB,EAAE;AACpC,YAAA,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC;AACpD,YAAA,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,GAAG,aAAa,CAAC,GAAG,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC;YACnD,OAAO;gBACL,EAAE;AACF,gBAAA,CAAC,EAAE,EAAE;AACL,gBAAA,CAAC,EAAE,EAAE;AACL,gBAAA,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;AAClC,gBAAA,EAAE,EAAE,CAAC;AACL,gBAAA,KAAK,EAAE,CAAC;gBACR,MAAM,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,IAAI,CAAC;gBACjC,CAAC,EAAE,CAAC,CAAC,KAAK;gBACV,CAAC,EAAE,CAAC,CAAC,MAAM;aACZ;AACH,QAAA,CAAC,CAAC;;AAGF,QAAA,MAAM,CAAC,OAAO,CAAC,CAAC,IAAG;YACjB,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,GAAG,UAAU;YAChC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,GAAG,GAAG;YACrB,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,GAAG,GAAG;YACpB,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,GAAG,WAAW;AACnC,YAAA,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;AAChB,QAAA,CAAC,CAAC;;QAGF,IAAI,IAAI,GAAsD,IAAI;AAElE,QAAA,MAAM,aAAa,GAAG,CAAC,CAAe,KAAU;YAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC;;AAErC,YAAA,KAAK,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE;AAC3C,gBAAA,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;AACnB,gBAAA,IACE,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;oBACxB,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;oBACxB,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;AACxB,oBAAA,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EACxB;oBACA,IAAI,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;AAC5D,oBAAA,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,SAAS,CAAC;oBACrC;gBACF;YACF;AACF,QAAA,CAAC;AACD,QAAA,MAAM,aAAa,GAAG,CAAC,CAAe,KAAU;AAC9C,YAAA,IAAI,CAAC,IAAI;gBAAE;YACX,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC;YACrC,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI;YACnC,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI;;AAEnC,YAAA,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,cAAc;AACxD,YAAA,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,cAAc;AAC1D,QAAA,CAAC;AACD,QAAA,MAAM,WAAW,GAAG,CAAC,CAAe,KAAU;AAC5C,YAAA,IAAI,CAAC,IAAI;gBAAE;AACX,YAAA,MAAM,CAAC,qBAAqB,CAAC,CAAC,CAAC,SAAS,CAAC;YACzC,IAAI,GAAG,IAAI;AACb,QAAA,CAAC;AACD,QAAA,MAAM,CAAC,gBAAgB,CAAC,aAAa,EAAE,aAAa,CAAC;AACrD,QAAA,MAAM,CAAC,gBAAgB,CAAC,aAAa,EAAE,aAAa,CAAC;AACrD,QAAA,MAAM,CAAC,gBAAgB,CAAC,WAAW,EAAE,WAAW,CAAC;AACjD,QAAA,MAAM,CAAC,gBAAgB,CAAC,eAAe,EAAE,WAAW,CAAC;QAErD,IAAI,GAAG,GAAG,CAAC;QACX,IAAI,MAAM,GAAG,CAAC;AACd,QAAA,MAAM,IAAI,GAAG,CAAC,EAAU,KAAU;AAChC,YAAA,MAAM,EAAE,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,MAAM,IAAI,IAAI,CAAC;YACvE,MAAM,GAAG,EAAE;AAEX,YAAA,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE;AACxB,YAAA,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE;;AAEtB,gBAAA,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,EAAE;AACd,gBAAA,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,QAAQ;AACpB,gBAAA,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,QAAQ;gBACpB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE;gBAChB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE;gBAChB,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,MAAM,GAAG,EAAE;AACxB,gBAAA,CAAC,CAAC,MAAM,IAAI,CAAC,GAAG,QAAQ;;AAGxB,gBAAA,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;oBACrB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;AACb,oBAAA,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,WAAW;AACnC,oBAAA,CAAC,CAAC,MAAM,IAAI,QAAQ;gBACtB;AACA,gBAAA,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,EAAE;oBACzB,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;AACrB,oBAAA,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,WAAW;AACpC,oBAAA,CAAC,CAAC,MAAM,IAAI,QAAQ;gBACtB;AACA,gBAAA,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,MAAM,EAAE;oBAC1B,CAAC,CAAC,CAAC,GAAG,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;AACtB,oBAAA,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,WAAW;AACpC,oBAAA,CAAC,CAAC,EAAE,IAAI,QAAQ;AAChB,oBAAA,CAAC,CAAC,MAAM,IAAI,QAAQ;gBACtB;AACA,gBAAA,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;oBACrB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;AACb,oBAAA,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,WAAW;gBACrC;YACF;;AAGA,YAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AACtC,gBAAA,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;oBAC1C,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;gBACxC;YACF;YAEA,KAAK,MAAM,CAAC,IAAI,MAAM;AAAE,gBAAA,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;AACtC,YAAA,GAAG,GAAG,qBAAqB,CAAC,IAAI,CAAC;AACnC,QAAA,CAAC;AACD,QAAA,GAAG,GAAG,qBAAqB,CAAC,IAAI,CAAC;AAEjC,QAAA,IAAI,CAAC,YAAY,GAAG,MAAW;YAC7B,oBAAoB,CAAC,GAAG,CAAC;AACzB,YAAA,MAAM,CAAC,mBAAmB,CAAC,aAAa,EAAE,aAAa,CAAC;AACxD,YAAA,MAAM,CAAC,mBAAmB,CAAC,aAAa,EAAE,aAAa,CAAC;AACxD,YAAA,MAAM,CAAC,mBAAmB,CAAC,WAAW,EAAE,WAAW,CAAC;AACpD,YAAA,MAAM,CAAC,mBAAmB,CAAC,eAAe,EAAE,WAAW,CAAC;AAC1D,QAAA,CAAC;IACH;;AAGQ,IAAA,MAAM,CAAC,CAAO,EAAA;AACpB,QAAA,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,GAAG,CAAA,UAAA,EAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA,IAAA,EAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA,WAAA,EAAc,CAAC,CAAC,KAAK,MAAM;QAChG,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,eAAe,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI;IAC1D;IAEQ,OAAO,CAAC,CAA4B,EAAE,IAAiB,EAAA;AAC7D,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,qBAAqB,EAAE;QACzC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE;IAC9D;uGApOW,aAAa,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAb,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,aAAa,o4BC5H1B,yVAQA,EAAA,MAAA,EAAA,CAAA,qZAAA,CAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;2FDoHa,aAAa,EAAA,UAAA,EAAA,CAAA;kBAPzB,SAAS;+BACE,iBAAiB,EAAA,aAAA,EAGZ,iBAAiB,CAAC,IAAI,QAC/B,EAAE,KAAK,EAAE,iBAAiB,EAAE,EAAA,QAAA,EAAA,yVAAA,EAAA,MAAA,EAAA,CAAA,qZAAA,CAAA,EAAA;+jBAkByC,gBAAgB,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,EAAA,CAAA;;AE5I7F;;AAEG;;;;"}
1
+ {"version":3,"file":"ngwr-falling-text.mjs","sources":["../../../projects/lib/falling-text/falling-text.ts","../../../projects/lib/falling-text/falling-text.html","../../../projects/lib/falling-text/ngwr-falling-text.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 * Angular adaptation of the FallingText effect by David Haz / reactbits.dev.\n * Original: https://www.reactbits.dev/text-animations/falling-text\n *\n * The reactbits version uses matter-js (~140 KB) for the physics. This\n * port ships a minimal AABB physics simulator (gravity + air drag + wall\n * / floor collision + body-vs-body resolution + cursor drag) so there's\n * no runtime dependency.\n */\n\nimport { isPlatformBrowser } from '@angular/common';\nimport {\n Component,\n DestroyRef,\n ElementRef,\n PLATFORM_ID,\n ViewEncapsulation,\n afterNextRender,\n computed,\n inject,\n input,\n viewChild,\n} from '@angular/core';\n\nimport { WrPlatform } from 'ngwr/platform';\nimport { numAttr } from 'ngwr/utils';\n\nimport type { WrFallingTextTrigger } from './interfaces';\n\ninterface Body {\n el: HTMLElement;\n x: number; // centre x\n y: number; // centre y\n vx: number;\n vy: number;\n angle: number;\n angVel: number;\n w: number;\n h: number;\n}\n\nconst RESTITUTION = 0.55;\nconst AIR_DRAG = 0.005;\nconst FRICTION = 0.4; // tangential damping on wall/floor hits\nconst DRAG_STIFFNESS = 0.6;\n\n/** Resolve AABB-vs-AABB collision between two bodies via min-overlap axis. */\nfunction resolveCollision(a: Body, b: Body): void {\n const dx = b.x - a.x;\n const dy = b.y - a.y;\n const overlapX = a.w / 2 + b.w / 2 - Math.abs(dx);\n const overlapY = a.h / 2 + b.h / 2 - Math.abs(dy);\n if (overlapX <= 0 || overlapY <= 0) return;\n\n if (overlapX < overlapY) {\n // Resolve along x.\n const push = overlapX / 2;\n if (dx > 0) {\n a.x -= push;\n b.x += push;\n } else {\n a.x += push;\n b.x -= push;\n }\n const avg = (a.vx + b.vx) / 2;\n a.vx = avg * RESTITUTION - (a.vx - avg) * RESTITUTION;\n b.vx = avg * RESTITUTION - (b.vx - avg) * RESTITUTION;\n } else {\n const push = overlapY / 2;\n if (dy > 0) {\n a.y -= push;\n b.y += push;\n } else {\n a.y += push;\n b.y -= push;\n }\n const avg = (a.vy + b.vy) / 2;\n a.vy = avg * RESTITUTION - (a.vy - avg) * RESTITUTION;\n b.vy = avg * RESTITUTION - (b.vy - avg) * RESTITUTION;\n }\n\n // Tiny torque so stacked bodies wiggle naturally.\n a.angVel += (Math.random() - 0.5) * 0.2;\n b.angVel += (Math.random() - 0.5) * 0.2;\n}\n\n/**\n * Words fall like physical bodies — gravity, wall/floor collision, and\n * cursor drag-to-pick-up. Words start at their typeset position then\n * release into the simulator on trigger.\n *\n * Triggers:\n * - `'auto'` release immediately on mount\n * - `'scroll'` release on viewport entry\n * - `'hover'` release on first hover\n * - `'click'` release on first click\n *\n * Highlight specific words by passing prefix-matched keywords via\n * `[highlightWords]` — matched spans get `wr-falling-text__word--hl`.\n *\n * @example\n * ```html\n * <wr-falling-text\n * text=\"React-Bits is a library of animated and interactive React components.\"\n * [highlightWords]=\"['React', 'animated', 'components']\"\n * trigger=\"hover\"\n * [gravity]=\"0.6\"\n * />\n * ```\n *\n * @see https://www.reactbits.dev/text-animations/falling-text\n */\n@Component({\n selector: 'wr-falling-text',\n templateUrl: './falling-text.html',\n styleUrl: './falling-text.scss',\n encapsulation: ViewEncapsulation.None,\n host: { class: 'wr-falling-text' },\n})\nexport class WrFallingText {\n /** Text to render. Words are separated by spaces. */\n readonly text = input.required<string>();\n\n /** Prefix-match keywords; any word starting with one of these gets the highlight class. */\n readonly highlightWords = input<readonly string[]>([]);\n\n /** When to release the words into the simulator. @default 'auto' */\n readonly trigger = input<WrFallingTextTrigger>('auto');\n\n /** Gravity in pixels/sec². @default 980 */\n readonly gravity = input(980, { transform: numAttr(980) });\n\n /** Font size as a CSS length. @default '1rem' */\n readonly fontSize = input('1rem');\n\n private readonly wordsRef = viewChild.required<ElementRef<HTMLDivElement>>('wordsContainer');\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly destroyRef = inject(DestroyRef);\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n private readonly platform = inject(WrPlatform);\n\n private started = false;\n private teardownLoop: (() => void) | undefined;\n\n protected readonly words = computed<readonly { text: string; highlighted: boolean }[]>(() => {\n const hl = this.highlightWords();\n return this.text()\n .split(' ')\n .filter(w => w.length > 0)\n .map(text => ({ text, highlighted: hl.some(h => text.startsWith(h)) }));\n });\n\n constructor() {\n if (!this.isBrowser) return;\n\n afterNextRender(() => {\n const trigger = this.trigger();\n if (trigger === 'auto') {\n this.start();\n return;\n }\n if (trigger === 'scroll') {\n const io = new IntersectionObserver(\n (entries, obs) => {\n for (const e of entries) {\n if (e.isIntersecting) {\n obs.disconnect();\n this.start();\n break;\n }\n }\n },\n { threshold: 0.1 }\n );\n io.observe(this.host.nativeElement);\n this.destroyRef.onDestroy(() => io.disconnect());\n return;\n }\n // hover / click — wait for host event\n const startOnce = (): void => {\n if (this.started) return;\n this.start();\n };\n const handler = trigger === 'hover' ? 'mouseenter' : 'click';\n this.host.nativeElement.addEventListener(handler, startOnce, { once: true });\n this.destroyRef.onDestroy(() => this.host.nativeElement.removeEventListener(handler, startOnce));\n });\n\n this.destroyRef.onDestroy(() => this.teardownLoop?.());\n }\n\n // Physics\n\n private start(): void {\n if (this.started) return;\n // Reduced motion: tumbling words are pure decoration — leave the\n // text standing in its normal layout no matter the trigger.\n if (this.platform.prefersReducedMotion()) return;\n this.started = true;\n\n const hostEl = this.host.nativeElement;\n const wordsContainer = this.wordsRef().nativeElement;\n const containerRect = hostEl.getBoundingClientRect();\n const width = containerRect.width;\n const height = containerRect.height;\n if (width <= 0 || height <= 0) return;\n\n // Snapshot each word's position relative to the container, then absolutise.\n const wordEls = Array.from(wordsContainer.querySelectorAll<HTMLElement>('.wr-falling-text__word'));\n if (wordEls.length === 0) return;\n\n const bodies: Body[] = wordEls.map(el => {\n const r = el.getBoundingClientRect();\n const cx = r.left - containerRect.left + r.width / 2;\n const cy = r.top - containerRect.top + r.height / 2;\n return {\n el,\n x: cx,\n y: cy,\n vx: (Math.random() - 0.5) * 5 * 60, // px/s\n vy: 0,\n angle: 0,\n angVel: (Math.random() - 0.5) * 2,\n w: r.width,\n h: r.height,\n };\n });\n\n // Absolutely position all word spans so we can move them freely.\n bodies.forEach(b => {\n b.el.style.position = 'absolute';\n b.el.style.left = '0';\n b.el.style.top = '0';\n b.el.style.willChange = 'transform';\n this.commit(b);\n });\n\n // Drag state.\n let drag: { body: Body; offX: number; offY: number } | null = null;\n\n const onPointerDown = (e: PointerEvent): void => {\n const local = this.toLocal(e, hostEl);\n // Pick the topmost (last) body whose AABB contains the pointer.\n for (let i = bodies.length - 1; i >= 0; i--) {\n const b = bodies[i];\n if (\n local.x >= b.x - b.w / 2 &&\n local.x <= b.x + b.w / 2 &&\n local.y >= b.y - b.h / 2 &&\n local.y <= b.y + b.h / 2\n ) {\n drag = { body: b, offX: local.x - b.x, offY: local.y - b.y };\n hostEl.setPointerCapture(e.pointerId);\n break;\n }\n }\n };\n const onPointerMove = (e: PointerEvent): void => {\n if (!drag) return;\n const local = this.toLocal(e, hostEl);\n const targetX = local.x - drag.offX;\n const targetY = local.y - drag.offY;\n // Spring toward the target — produces a satisfying tug rather than a snap.\n drag.body.vx += (targetX - drag.body.x) * DRAG_STIFFNESS;\n drag.body.vy += (targetY - drag.body.y) * DRAG_STIFFNESS;\n };\n const onPointerUp = (e: PointerEvent): void => {\n if (!drag) return;\n hostEl.releasePointerCapture(e.pointerId);\n drag = null;\n };\n hostEl.addEventListener('pointerdown', onPointerDown);\n hostEl.addEventListener('pointermove', onPointerMove);\n hostEl.addEventListener('pointerup', onPointerUp);\n hostEl.addEventListener('pointercancel', onPointerUp);\n\n let raf = 0;\n let lastTs = 0;\n const tick = (ts: number): void => {\n const dt = lastTs === 0 ? 1 / 60 : Math.min(0.05, (ts - lastTs) / 1000);\n lastTs = ts;\n\n const g = this.gravity();\n for (const b of bodies) {\n // Integrate.\n b.vy += g * dt;\n b.vx *= 1 - AIR_DRAG;\n b.vy *= 1 - AIR_DRAG;\n b.x += b.vx * dt;\n b.y += b.vy * dt;\n b.angle += b.angVel * dt;\n b.angVel *= 1 - AIR_DRAG;\n\n // Walls + floor + ceiling.\n if (b.x - b.w / 2 < 0) {\n b.x = b.w / 2;\n b.vx = Math.abs(b.vx) * RESTITUTION;\n b.angVel *= FRICTION;\n }\n if (b.x + b.w / 2 > width) {\n b.x = width - b.w / 2;\n b.vx = -Math.abs(b.vx) * RESTITUTION;\n b.angVel *= FRICTION;\n }\n if (b.y + b.h / 2 > height) {\n b.y = height - b.h / 2;\n b.vy = -Math.abs(b.vy) * RESTITUTION;\n b.vx *= FRICTION;\n b.angVel *= FRICTION;\n }\n if (b.y - b.h / 2 < 0) {\n b.y = b.h / 2;\n b.vy = Math.abs(b.vy) * RESTITUTION;\n }\n }\n\n // Body-vs-body collisions — O(n²), fine for ~30 words.\n for (let i = 0; i < bodies.length; i++) {\n for (let j = i + 1; j < bodies.length; j++) {\n resolveCollision(bodies[i], bodies[j]);\n }\n }\n\n for (const b of bodies) this.commit(b);\n raf = requestAnimationFrame(tick);\n };\n raf = requestAnimationFrame(tick);\n\n this.teardownLoop = (): void => {\n cancelAnimationFrame(raf);\n hostEl.removeEventListener('pointerdown', onPointerDown);\n hostEl.removeEventListener('pointermove', onPointerMove);\n hostEl.removeEventListener('pointerup', onPointerUp);\n hostEl.removeEventListener('pointercancel', onPointerUp);\n };\n }\n\n /** Apply the body's position + angle to the DOM. */\n private commit(b: Body): void {\n b.el.style.transform = `translate(${b.x - b.w / 2}px, ${b.y - b.h / 2}px) rotate(${b.angle}rad)`;\n b.el.style.transformOrigin = `${b.w / 2}px ${b.h / 2}px`;\n }\n\n private toLocal(e: PointerEvent | MouseEvent, host: HTMLElement): { x: number; y: number } {\n const rect = host.getBoundingClientRect();\n return { x: e.clientX - rect.left, y: e.clientY - rect.top };\n }\n}\n\nexport type { WrFallingTextTrigger } from './interfaces';\n","<div #wordsContainer class=\"wr-falling-text__words\" [style.font-size]=\"fontSize()\">\n @for (w of words(); track $index) {\n <span class=\"wr-falling-text__word\" [class.wr-falling-text__word--hl]=\"w.highlighted\">{{ w.text }}</span>\n @if (!$last) {\n <span class=\"wr-falling-text__space\">&nbsp;</span>\n }\n }\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -1,9 +1,7 @@
1
1
  import { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';
2
2
  import * as i0 from '@angular/core';
3
- import { input, output, viewChild, signal, computed, forwardRef, ViewEncapsulation, Component } from '@angular/core';
4
- import { NG_VALUE_ACCESSOR } from '@angular/forms';
3
+ import { input, model, output, viewChild, signal, computed, effect, untracked, ViewEncapsulation, Component } from '@angular/core';
5
4
  import { useI18nText } from 'ngwr/i18n';
6
- import { noop } from 'ngwr/utils';
7
5
 
8
6
  /**
9
7
  * @license
@@ -44,16 +42,22 @@ function matchesAccept(file, accept) {
44
42
  * Drag-and-drop file upload zone. Click to browse, drag-and-drop to add,
45
43
  * with an optional file list + remove buttons.
46
44
  *
47
- * Implements `ControlValueAccessor` — value is `File | File[] | null`
48
- * (single or array, governed by `multiple`).
45
+ * A signal-forms native control: it implements
46
+ * `FormValueControl<File | readonly File[] | null>`, so `[formField]` binds
47
+ * straight to its `value` model — no `ControlValueAccessor` in between.
48
+ * `[(value)]` works standalone. The value shape follows `multiple`: a single
49
+ * `File` (or `null`), or a `File[]` array.
49
50
  *
50
51
  * @example
51
52
  * ```html
52
- * <wr-file-upload [(ngModel)]="files" [multiple]="true" accept="image/*" />
53
- * <wr-file-upload [(ngModel)]="avatar" accept=".png,.jpg" [maxSize]="2 * 1024 * 1024" />
53
+ * <!-- signal forms -->
54
+ * <wr-file-upload [formField]="form.files" [multiple]="true" accept="image/*" />
55
+ *
56
+ * <!-- standalone two-way binding -->
57
+ * <wr-file-upload [(value)]="avatar" accept=".png,.jpg" [maxSize]="2 * 1024 * 1024" />
54
58
  * ```
55
59
  *
56
- * @see https://ngwr.dev/components/file-upload
60
+ * @see https://ngwr.dev/reference/components/file-upload
57
61
  */
58
62
  class WrFileUpload {
59
63
  /** Allow multiple files. Single mode replaces on each add. @default false */
@@ -67,7 +71,12 @@ class WrFileUpload {
67
71
  maxFiles = input(0, { ...(ngDevMode ? { debugName: "maxFiles" } : /* istanbul ignore next */ {}), transform: (v) => Math.max(0, coerceNumberProperty(v, 0)) });
68
72
  /** Render the picked-files list below the zone. @default true */
69
73
  showList = input(true, { ...(ngDevMode ? { debugName: "showList" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
70
- /** Disable interaction. @default false */
74
+ /**
75
+ * Disable interaction. Bound automatically from the field's disabled state
76
+ * when used with `[formField]`.
77
+ *
78
+ * @default false
79
+ */
71
80
  disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
72
81
  /** Primary call-to-action label. Falls back to `fileUpload.browse`. */
73
82
  pickLabel = input(null, /* @ts-ignore */
@@ -88,49 +97,52 @@ class WrFileUpload {
88
97
  /** Optional helper text shown below the labels (e.g. accepted formats). */
89
98
  helperText = input('', /* @ts-ignore */
90
99
  ...(ngDevMode ? [{ debugName: "helperText" }] : /* istanbul ignore next */ []));
100
+ /**
101
+ * Selected file(s). Bound by `[formField]`, or two-way via `[(value)]`. Shape
102
+ * follows `multiple`: a single `File` (or `null`), or a `File[]` array.
103
+ */
104
+ value = model(null, /* @ts-ignore */
105
+ ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
91
106
  /** Emitted when files are rejected for type / size / count reasons. */
92
107
  rejected = output();
93
- picker = viewChild.required('picker');
108
+ /** Emitted on commit so a bound field can mark itself touched. */
109
+ touch = output();
110
+ picker = viewChild.required('picker', /* @ts-ignore */
111
+ ...(ngDevMode ? [{ debugName: "picker" }] : /* istanbul ignore next */ []));
94
112
  files = signal([], /* @ts-ignore */
95
113
  ...(ngDevMode ? [{ debugName: "files" }] : /* istanbul ignore next */ []));
96
114
  dragging = signal(false, /* @ts-ignore */
97
115
  ...(ngDevMode ? [{ debugName: "dragging" }] : /* istanbul ignore next */ []));
98
- disabledFromCva = signal(false, /* @ts-ignore */
99
- ...(ngDevMode ? [{ debugName: "disabledFromCva" }] : /* istanbul ignore next */ []));
100
- effectiveDisabled = computed(() => this.disabled() || this.disabledFromCva(), /* @ts-ignore */
101
- ...(ngDevMode ? [{ debugName: "effectiveDisabled" }] : /* istanbul ignore next */ []));
102
116
  classes = computed(() => {
103
117
  const parts = ['wr-file-upload'];
104
118
  if (this.dragging())
105
119
  parts.push('wr-file-upload--dragging');
106
- if (this.effectiveDisabled())
120
+ if (this.disabled())
107
121
  parts.push('wr-file-upload--disabled');
108
122
  return parts.join(' ');
109
123
  }, /* @ts-ignore */
110
124
  ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
111
125
  formatBytes = formatBytes;
112
- // ControlValueAccessor
113
- onChange = noop;
114
- onTouched = noop;
115
- writeValue(value) {
116
- if (value === null || value === undefined) {
117
- this.files.set([]);
118
- return;
119
- }
120
- this.files.set(Array.isArray(value) ? value : [value]);
121
- }
122
- registerOnChange(fn) {
123
- this.onChange = fn;
124
- }
125
- registerOnTouched(fn) {
126
- this.onTouched = fn;
127
- }
128
- setDisabledState(isDisabled) {
129
- this.disabledFromCva.set(coerceBooleanProperty(isDisabled));
126
+ constructor() {
127
+ // Rebuild the internal file list from an external `value` write (mirrors the
128
+ // old `writeValue`). Skipped when the value is merely the echo of an
129
+ // in-component edit, so re-syncing can never clobber a live selection.
130
+ effect(() => {
131
+ const v = this.value();
132
+ untracked(() => {
133
+ // Coerce null/undefined to `[]` — a classic-forms binding can write
134
+ // null, which the old `writeValue(v: … | null)` accepted too.
135
+ const next = v === null || v === undefined ? [] : Array.isArray(v) ? v : [v];
136
+ const current = this.files();
137
+ if (current.length === next.length && current.every((file, i) => file === next[i]))
138
+ return;
139
+ this.files.set(next);
140
+ });
141
+ });
130
142
  }
131
143
  // Template handlers
132
144
  openPicker() {
133
- if (this.effectiveDisabled())
145
+ if (this.disabled())
134
146
  return;
135
147
  this.picker().nativeElement.click();
136
148
  }
@@ -148,13 +160,13 @@ class WrFileUpload {
148
160
  target.value = '';
149
161
  }
150
162
  onDragEnter(event) {
151
- if (this.effectiveDisabled())
163
+ if (this.disabled())
152
164
  return;
153
165
  event.preventDefault();
154
166
  this.dragging.set(true);
155
167
  }
156
168
  onDragOver(event) {
157
- if (this.effectiveDisabled())
169
+ if (this.disabled())
158
170
  return;
159
171
  event.preventDefault();
160
172
  if (event.dataTransfer)
@@ -168,14 +180,14 @@ class WrFileUpload {
168
180
  onDrop(event) {
169
181
  event.preventDefault();
170
182
  this.dragging.set(false);
171
- if (this.effectiveDisabled())
183
+ if (this.disabled())
172
184
  return;
173
185
  const dropped = event.dataTransfer?.files ? Array.from(event.dataTransfer.files) : [];
174
186
  if (dropped.length > 0)
175
187
  this.acceptFiles(dropped);
176
188
  }
177
189
  removeAt(index) {
178
- if (this.effectiveDisabled())
190
+ if (this.disabled())
179
191
  return;
180
192
  const next = this.files().filter((_, i) => i !== index);
181
193
  this.files.set(next);
@@ -209,7 +221,7 @@ class WrFileUpload {
209
221
  next = accepted.length > 0 ? [accepted[accepted.length - 1]] : [...this.files()];
210
222
  }
211
223
  this.files.set(next);
212
- this.onTouched();
224
+ this.touch.emit();
213
225
  this.emit();
214
226
  if (rejections.length > 0)
215
227
  this.rejected.emit(rejections);
@@ -224,33 +236,19 @@ class WrFileUpload {
224
236
  emit() {
225
237
  const list = this.files();
226
238
  if (this.multiple()) {
227
- this.onChange(list);
239
+ this.value.set(list);
228
240
  }
229
241
  else {
230
- this.onChange(list.length > 0 ? list[0] : null);
242
+ this.value.set(list.length > 0 ? list[0] : null);
231
243
  }
232
244
  }
233
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: WrFileUpload, deps: [], target: i0.ɵɵFactoryTarget.Component });
234
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: WrFileUpload, isStandalone: true, selector: "wr-file-upload", inputs: { multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, accept: { classPropertyName: "accept", publicName: "accept", isSignal: true, isRequired: false, transformFunction: null }, maxSize: { classPropertyName: "maxSize", publicName: "maxSize", isSignal: true, isRequired: false, transformFunction: null }, maxFiles: { classPropertyName: "maxFiles", publicName: "maxFiles", isSignal: true, isRequired: false, transformFunction: null }, showList: { classPropertyName: "showList", publicName: "showList", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, pickLabel: { classPropertyName: "pickLabel", publicName: "pickLabel", isSignal: true, isRequired: false, transformFunction: null }, dropLabel: { classPropertyName: "dropLabel", publicName: "dropLabel", isSignal: true, isRequired: false, transformFunction: null }, dropZoneLabel: { classPropertyName: "dropZoneLabel", publicName: "dropZoneLabel", isSignal: true, isRequired: false, transformFunction: null }, removeFileLabel: { classPropertyName: "removeFileLabel", publicName: "removeFileLabel", isSignal: true, isRequired: false, transformFunction: null }, helperText: { classPropertyName: "helperText", publicName: "helperText", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { rejected: "rejected" }, host: { properties: { "class": "classes()" } }, providers: [
235
- {
236
- provide: NG_VALUE_ACCESSOR,
237
- // eslint-disable-next-line @angular-eslint/no-forward-ref
238
- useExisting: forwardRef(() => WrFileUpload),
239
- multi: true,
240
- },
241
- ], viewQueries: [{ propertyName: "picker", first: true, predicate: ["picker"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n class=\"wr-file-upload__zone\"\n role=\"button\"\n tabindex=\"0\"\n [attr.aria-label]=\"resolvedDropZone()\"\n [attr.aria-disabled]=\"effectiveDisabled() || null\"\n (click)=\"openPicker()\"\n (keydown)=\"onZoneKey($event)\"\n (dragenter)=\"onDragEnter($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n>\n <svg class=\"wr-file-upload__icon\" width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path\n d=\"M12 16V4M12 4l-4 4M12 4l4 4M4 16v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n <div class=\"wr-file-upload__hint\">\n <strong>{{ resolvedPick() }}</strong>\n <span>{{ resolvedDrop() }}</span>\n @if (helperText()) {\n <small>{{ helperText() }}</small>\n }\n </div>\n <input\n #picker\n class=\"wr-file-upload__picker\"\n type=\"file\"\n [attr.accept]=\"accept() || null\"\n [attr.multiple]=\"multiple() ? '' : null\"\n [disabled]=\"effectiveDisabled()\"\n (change)=\"onPickerChange($event)\"\n />\n</div>\n\n@if (showList() && files().length > 0) {\n <ul class=\"wr-file-upload__list\">\n @for (file of files(); track $index) {\n <li class=\"wr-file-upload__item\">\n <span class=\"wr-file-upload__name\" [title]=\"file.name\">{{ file.name }}</span>\n <span class=\"wr-file-upload__size\">{{ formatBytes(file.size) }}</span>\n <button\n type=\"button\"\n class=\"wr-file-upload__remove\"\n [attr.aria-label]=\"resolvedRemove()\"\n [disabled]=\"effectiveDisabled()\"\n (click)=\"removeAt($index)\"\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" aria-hidden=\"true\">\n <path\n d=\"M2 2 L10 10 M10 2 L2 10\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n </li>\n }\n </ul>\n}\n", encapsulation: i0.ViewEncapsulation.None });
245
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrFileUpload, deps: [], target: i0.ɵɵFactoryTarget.Component });
246
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: WrFileUpload, isStandalone: true, selector: "wr-file-upload", inputs: { multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, accept: { classPropertyName: "accept", publicName: "accept", isSignal: true, isRequired: false, transformFunction: null }, maxSize: { classPropertyName: "maxSize", publicName: "maxSize", isSignal: true, isRequired: false, transformFunction: null }, maxFiles: { classPropertyName: "maxFiles", publicName: "maxFiles", isSignal: true, isRequired: false, transformFunction: null }, showList: { classPropertyName: "showList", publicName: "showList", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, pickLabel: { classPropertyName: "pickLabel", publicName: "pickLabel", isSignal: true, isRequired: false, transformFunction: null }, dropLabel: { classPropertyName: "dropLabel", publicName: "dropLabel", isSignal: true, isRequired: false, transformFunction: null }, dropZoneLabel: { classPropertyName: "dropZoneLabel", publicName: "dropZoneLabel", isSignal: true, isRequired: false, transformFunction: null }, removeFileLabel: { classPropertyName: "removeFileLabel", publicName: "removeFileLabel", isSignal: true, isRequired: false, transformFunction: null }, helperText: { classPropertyName: "helperText", publicName: "helperText", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", rejected: "rejected", touch: "touch" }, host: { properties: { "class": "classes()" } }, viewQueries: [{ propertyName: "picker", first: true, predicate: ["picker"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n class=\"wr-file-upload__zone\"\n role=\"button\"\n tabindex=\"0\"\n [attr.aria-label]=\"resolvedDropZone()\"\n [attr.aria-disabled]=\"disabled() || null\"\n (click)=\"openPicker()\"\n (keydown)=\"onZoneKey($event)\"\n (dragenter)=\"onDragEnter($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n>\n <svg class=\"wr-file-upload__icon\" width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path\n d=\"M12 16V4M12 4l-4 4M12 4l4 4M4 16v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n <div class=\"wr-file-upload__hint\">\n <strong>{{ resolvedPick() }}</strong>\n <span>{{ resolvedDrop() }}</span>\n @if (helperText()) {\n <small>{{ helperText() }}</small>\n }\n </div>\n <input\n #picker\n class=\"wr-file-upload__picker\"\n type=\"file\"\n [attr.accept]=\"accept() || null\"\n [attr.multiple]=\"multiple() ? '' : null\"\n [disabled]=\"disabled()\"\n (change)=\"onPickerChange($event)\"\n />\n</div>\n\n@if (showList() && files().length > 0) {\n <ul class=\"wr-file-upload__list\">\n @for (file of files(); track $index) {\n <li class=\"wr-file-upload__item\">\n <span class=\"wr-file-upload__name\" [title]=\"file.name\">{{ file.name }}</span>\n <span class=\"wr-file-upload__size\">{{ formatBytes(file.size) }}</span>\n <button\n type=\"button\"\n class=\"wr-file-upload__remove\"\n [attr.aria-label]=\"resolvedRemove()\"\n [disabled]=\"disabled()\"\n (click)=\"removeAt($index)\"\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" aria-hidden=\"true\">\n <path\n d=\"M2 2 L10 10 M10 2 L2 10\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n </li>\n }\n </ul>\n}\n", encapsulation: i0.ViewEncapsulation.None });
242
247
  }
243
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: WrFileUpload, decorators: [{
248
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrFileUpload, decorators: [{
244
249
  type: Component,
245
- args: [{ selector: 'wr-file-upload', encapsulation: ViewEncapsulation.None, host: { '[class]': 'classes()' }, imports: [], providers: [
246
- {
247
- provide: NG_VALUE_ACCESSOR,
248
- // eslint-disable-next-line @angular-eslint/no-forward-ref
249
- useExisting: forwardRef(() => WrFileUpload),
250
- multi: true,
251
- },
252
- ], template: "<div\n class=\"wr-file-upload__zone\"\n role=\"button\"\n tabindex=\"0\"\n [attr.aria-label]=\"resolvedDropZone()\"\n [attr.aria-disabled]=\"effectiveDisabled() || null\"\n (click)=\"openPicker()\"\n (keydown)=\"onZoneKey($event)\"\n (dragenter)=\"onDragEnter($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n>\n <svg class=\"wr-file-upload__icon\" width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path\n d=\"M12 16V4M12 4l-4 4M12 4l4 4M4 16v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n <div class=\"wr-file-upload__hint\">\n <strong>{{ resolvedPick() }}</strong>\n <span>{{ resolvedDrop() }}</span>\n @if (helperText()) {\n <small>{{ helperText() }}</small>\n }\n </div>\n <input\n #picker\n class=\"wr-file-upload__picker\"\n type=\"file\"\n [attr.accept]=\"accept() || null\"\n [attr.multiple]=\"multiple() ? '' : null\"\n [disabled]=\"effectiveDisabled()\"\n (change)=\"onPickerChange($event)\"\n />\n</div>\n\n@if (showList() && files().length > 0) {\n <ul class=\"wr-file-upload__list\">\n @for (file of files(); track $index) {\n <li class=\"wr-file-upload__item\">\n <span class=\"wr-file-upload__name\" [title]=\"file.name\">{{ file.name }}</span>\n <span class=\"wr-file-upload__size\">{{ formatBytes(file.size) }}</span>\n <button\n type=\"button\"\n class=\"wr-file-upload__remove\"\n [attr.aria-label]=\"resolvedRemove()\"\n [disabled]=\"effectiveDisabled()\"\n (click)=\"removeAt($index)\"\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" aria-hidden=\"true\">\n <path\n d=\"M2 2 L10 10 M10 2 L2 10\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n </li>\n }\n </ul>\n}\n" }]
253
- }], propDecorators: { multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], accept: [{ type: i0.Input, args: [{ isSignal: true, alias: "accept", required: false }] }], maxSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxSize", required: false }] }], maxFiles: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFiles", required: false }] }], showList: [{ type: i0.Input, args: [{ isSignal: true, alias: "showList", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], pickLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "pickLabel", required: false }] }], dropLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "dropLabel", required: false }] }], dropZoneLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "dropZoneLabel", required: false }] }], removeFileLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "removeFileLabel", required: false }] }], helperText: [{ type: i0.Input, args: [{ isSignal: true, alias: "helperText", required: false }] }], rejected: [{ type: i0.Output, args: ["rejected"] }], picker: [{ type: i0.ViewChild, args: ['picker', { isSignal: true }] }] } });
250
+ args: [{ selector: 'wr-file-upload', encapsulation: ViewEncapsulation.None, host: { '[class]': 'classes()' }, imports: [], template: "<div\n class=\"wr-file-upload__zone\"\n role=\"button\"\n tabindex=\"0\"\n [attr.aria-label]=\"resolvedDropZone()\"\n [attr.aria-disabled]=\"disabled() || null\"\n (click)=\"openPicker()\"\n (keydown)=\"onZoneKey($event)\"\n (dragenter)=\"onDragEnter($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n>\n <svg class=\"wr-file-upload__icon\" width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path\n d=\"M12 16V4M12 4l-4 4M12 4l4 4M4 16v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n <div class=\"wr-file-upload__hint\">\n <strong>{{ resolvedPick() }}</strong>\n <span>{{ resolvedDrop() }}</span>\n @if (helperText()) {\n <small>{{ helperText() }}</small>\n }\n </div>\n <input\n #picker\n class=\"wr-file-upload__picker\"\n type=\"file\"\n [attr.accept]=\"accept() || null\"\n [attr.multiple]=\"multiple() ? '' : null\"\n [disabled]=\"disabled()\"\n (change)=\"onPickerChange($event)\"\n />\n</div>\n\n@if (showList() && files().length > 0) {\n <ul class=\"wr-file-upload__list\">\n @for (file of files(); track $index) {\n <li class=\"wr-file-upload__item\">\n <span class=\"wr-file-upload__name\" [title]=\"file.name\">{{ file.name }}</span>\n <span class=\"wr-file-upload__size\">{{ formatBytes(file.size) }}</span>\n <button\n type=\"button\"\n class=\"wr-file-upload__remove\"\n [attr.aria-label]=\"resolvedRemove()\"\n [disabled]=\"disabled()\"\n (click)=\"removeAt($index)\"\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" aria-hidden=\"true\">\n <path\n d=\"M2 2 L10 10 M10 2 L2 10\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n </li>\n }\n </ul>\n}\n" }]
251
+ }], ctorParameters: () => [], propDecorators: { multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], accept: [{ type: i0.Input, args: [{ isSignal: true, alias: "accept", required: false }] }], maxSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxSize", required: false }] }], maxFiles: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFiles", required: false }] }], showList: [{ type: i0.Input, args: [{ isSignal: true, alias: "showList", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], pickLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "pickLabel", required: false }] }], dropLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "dropLabel", required: false }] }], dropZoneLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "dropZoneLabel", required: false }] }], removeFileLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "removeFileLabel", required: false }] }], helperText: [{ type: i0.Input, args: [{ isSignal: true, alias: "helperText", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], rejected: [{ type: i0.Output, args: ["rejected"] }], touch: [{ type: i0.Output, args: ["touch"] }], picker: [{ type: i0.ViewChild, args: ['picker', { isSignal: true }] }] } });
254
252
 
255
253
  /**
256
254
  * Generated bundle index. Do not edit.
@@ -1 +1 @@
1
- {"version":3,"file":"ngwr-file-upload.mjs","sources":["../../../projects/lib/file-upload/file-upload.ts","../../../projects/lib/file-upload/file-upload.html","../../../projects/lib/file-upload/ngwr-file-upload.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 {\n Component,\n type ElementRef,\n ViewEncapsulation,\n computed,\n forwardRef,\n input,\n output,\n signal,\n viewChild,\n} from '@angular/core';\nimport { type ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\n\nimport { useI18nText } from 'ngwr/i18n';\nimport { noop } from 'ngwr/utils';\n\nimport type { WrFileUploadRejection, WrFileUploadRejectionReason } from './interfaces';\n\n/** Human-readable byte size (e.g. `1.2 MB`). */\nfunction formatBytes(bytes: number): string {\n if (!Number.isFinite(bytes) || bytes <= 0) return '0 B';\n const units = ['B', 'KB', 'MB', 'GB', 'TB'];\n const i = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1);\n const v = bytes / 1024 ** i;\n return `${v.toFixed(v >= 100 || i === 0 ? 0 : 1)} ${units[i]}`;\n}\n\n/** Does `file` match the `accept` attribute (extensions or MIME globs)? */\nfunction matchesAccept(file: File, accept: string): boolean {\n if (!accept) return true;\n const tokens = accept\n .split(',')\n .map(t => t.trim().toLowerCase())\n .filter(Boolean);\n if (tokens.length === 0) return true;\n const name = file.name.toLowerCase();\n const mime = file.type.toLowerCase();\n return tokens.some(token => {\n if (token.startsWith('.')) return name.endsWith(token);\n if (token.endsWith('/*')) return mime.startsWith(token.slice(0, -1));\n return mime === token;\n });\n}\n\n/**\n * Drag-and-drop file upload zone. Click to browse, drag-and-drop to add,\n * with an optional file list + remove buttons.\n *\n * Implements `ControlValueAccessor` — value is `File | File[] | null`\n * (single or array, governed by `multiple`).\n *\n * @example\n * ```html\n * <wr-file-upload [(ngModel)]=\"files\" [multiple]=\"true\" accept=\"image/*\" />\n * <wr-file-upload [(ngModel)]=\"avatar\" accept=\".png,.jpg\" [maxSize]=\"2 * 1024 * 1024\" />\n * ```\n *\n * @see https://ngwr.dev/components/file-upload\n */\n@Component({\n selector: 'wr-file-upload',\n templateUrl: './file-upload.html',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n imports: [],\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n // eslint-disable-next-line @angular-eslint/no-forward-ref\n useExisting: forwardRef(() => WrFileUpload),\n multi: true,\n },\n ],\n})\nexport class WrFileUpload implements ControlValueAccessor {\n /** Allow multiple files. Single mode replaces on each add. @default false */\n readonly multiple = input(false, { transform: coerceBooleanProperty });\n\n /** `accept` attribute — comma-separated MIME types or extensions. @default '' */\n readonly accept = input<string>('');\n\n /** Max bytes per file. `0` disables the check. @default 0 */\n readonly maxSize = input(0, { transform: (v: unknown): number => Math.max(0, coerceNumberProperty(v, 0)) });\n\n /** Max files (multi mode only). `0` disables the check. @default 0 */\n readonly maxFiles = input(0, { transform: (v: unknown): number => Math.max(0, coerceNumberProperty(v, 0)) });\n\n /** Render the picked-files list below the zone. @default true */\n readonly showList = input(true, { transform: coerceBooleanProperty });\n\n /** Disable interaction. @default false */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n /** Primary call-to-action label. Falls back to `fileUpload.browse`. */\n readonly pickLabel = input<string | null>(null);\n\n /** Secondary instruction below the CTA. Falls back to `fileUpload.dropZone`. */\n readonly dropLabel = input<string | null>(null);\n\n /** Drop-zone host aria-label. Falls back to `fileUpload.dropZoneLabel`. */\n readonly dropZoneLabel = input<string | null>(null);\n\n /** Remove-file button aria-label. Falls back to `fileUpload.removeFile`. */\n readonly removeFileLabel = input<string | null>(null);\n\n protected readonly resolvedPick = useI18nText(this.pickLabel, 'fileUpload.browse', 'Click to browse');\n protected readonly resolvedDrop = useI18nText(this.dropLabel, 'fileUpload.dropZone', 'or drop files here');\n protected readonly resolvedDropZone = useI18nText(\n this.dropZoneLabel,\n 'fileUpload.dropZoneLabel',\n 'File upload drop zone — click or drop files'\n );\n protected readonly resolvedRemove = useI18nText(this.removeFileLabel, 'fileUpload.removeFile', 'Remove file');\n\n /** Optional helper text shown below the labels (e.g. accepted formats). */\n readonly helperText = input<string>('');\n\n /** Emitted when files are rejected for type / size / count reasons. */\n readonly rejected = output<readonly WrFileUploadRejection[]>();\n\n protected readonly picker = viewChild.required<ElementRef<HTMLInputElement>>('picker');\n\n protected readonly files = signal<readonly File[]>([]);\n protected readonly dragging = signal(false);\n\n private readonly disabledFromCva = signal(false);\n\n protected readonly effectiveDisabled = computed(() => this.disabled() || this.disabledFromCva());\n\n protected readonly classes = computed(() => {\n const parts = ['wr-file-upload'];\n if (this.dragging()) parts.push('wr-file-upload--dragging');\n if (this.effectiveDisabled()) parts.push('wr-file-upload--disabled');\n return parts.join(' ');\n });\n\n protected readonly formatBytes = formatBytes;\n\n // ControlValueAccessor\n\n private onChange: (value: File | readonly File[] | null) => void = noop;\n private onTouched: () => void = noop;\n\n writeValue(value: File | readonly File[] | null): void {\n if (value === null || value === undefined) {\n this.files.set([]);\n return;\n }\n this.files.set(Array.isArray(value) ? value : [value as File]);\n }\n\n registerOnChange(fn: (value: File | readonly File[] | null) => void): void {\n this.onChange = fn;\n }\n\n registerOnTouched(fn: () => void): void {\n this.onTouched = fn;\n }\n\n setDisabledState(isDisabled: boolean): void {\n this.disabledFromCva.set(coerceBooleanProperty(isDisabled));\n }\n\n // Template handlers\n\n protected openPicker(): void {\n if (this.effectiveDisabled()) return;\n this.picker().nativeElement.click();\n }\n\n protected onZoneKey(event: KeyboardEvent): void {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n this.openPicker();\n }\n }\n\n protected onPickerChange(event: Event): void {\n const target = event.target as HTMLInputElement;\n if (target.files) this.acceptFiles(Array.from(target.files));\n // Reset so picking the same file twice re-fires `change`.\n target.value = '';\n }\n\n protected onDragEnter(event: DragEvent): void {\n if (this.effectiveDisabled()) return;\n event.preventDefault();\n this.dragging.set(true);\n }\n\n protected onDragOver(event: DragEvent): void {\n if (this.effectiveDisabled()) return;\n event.preventDefault();\n if (event.dataTransfer) event.dataTransfer.dropEffect = 'copy';\n }\n\n protected onDragLeave(event: DragEvent): void {\n // Only clear when leaving the zone itself, not internal children.\n if (event.currentTarget === event.target) this.dragging.set(false);\n }\n\n protected onDrop(event: DragEvent): void {\n event.preventDefault();\n this.dragging.set(false);\n if (this.effectiveDisabled()) return;\n const dropped = event.dataTransfer?.files ? Array.from(event.dataTransfer.files) : [];\n if (dropped.length > 0) this.acceptFiles(dropped);\n }\n\n protected removeAt(index: number): void {\n if (this.effectiveDisabled()) return;\n const next = this.files().filter((_, i) => i !== index);\n this.files.set(next);\n this.emit();\n }\n\n // Internals\n\n private acceptFiles(incoming: readonly File[]): void {\n const accept = this.accept();\n const maxSize = this.maxSize();\n const rejections: WrFileUploadRejection[] = [];\n const accepted: File[] = [];\n\n for (const file of incoming) {\n const reason = this.reject(file, accept, maxSize);\n if (reason) rejections.push({ file, reason });\n else accepted.push(file);\n }\n\n let next: File[];\n if (this.multiple()) {\n next = [...this.files(), ...accepted];\n const maxFiles = this.maxFiles();\n if (maxFiles > 0 && next.length > maxFiles) {\n const overflow = next.splice(maxFiles);\n for (const file of overflow) rejections.push({ file, reason: 'count' });\n }\n } else {\n // Single mode — last accepted wins, prior selection cleared.\n next = accepted.length > 0 ? [accepted[accepted.length - 1]] : [...this.files()];\n }\n\n this.files.set(next);\n this.onTouched();\n this.emit();\n if (rejections.length > 0) this.rejected.emit(rejections);\n }\n\n private reject(file: File, accept: string, maxSize: number): WrFileUploadRejectionReason | null {\n if (accept && !matchesAccept(file, accept)) return 'type';\n if (maxSize > 0 && file.size > maxSize) return 'size';\n return null;\n }\n\n private emit(): void {\n const list = this.files();\n if (this.multiple()) {\n this.onChange(list);\n } else {\n this.onChange(list.length > 0 ? list[0] : null);\n }\n }\n}\n","<div\n class=\"wr-file-upload__zone\"\n role=\"button\"\n tabindex=\"0\"\n [attr.aria-label]=\"resolvedDropZone()\"\n [attr.aria-disabled]=\"effectiveDisabled() || null\"\n (click)=\"openPicker()\"\n (keydown)=\"onZoneKey($event)\"\n (dragenter)=\"onDragEnter($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n>\n <svg class=\"wr-file-upload__icon\" width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path\n d=\"M12 16V4M12 4l-4 4M12 4l4 4M4 16v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n <div class=\"wr-file-upload__hint\">\n <strong>{{ resolvedPick() }}</strong>\n <span>{{ resolvedDrop() }}</span>\n @if (helperText()) {\n <small>{{ helperText() }}</small>\n }\n </div>\n <input\n #picker\n class=\"wr-file-upload__picker\"\n type=\"file\"\n [attr.accept]=\"accept() || null\"\n [attr.multiple]=\"multiple() ? '' : null\"\n [disabled]=\"effectiveDisabled()\"\n (change)=\"onPickerChange($event)\"\n />\n</div>\n\n@if (showList() && files().length > 0) {\n <ul class=\"wr-file-upload__list\">\n @for (file of files(); track $index) {\n <li class=\"wr-file-upload__item\">\n <span class=\"wr-file-upload__name\" [title]=\"file.name\">{{ file.name }}</span>\n <span class=\"wr-file-upload__size\">{{ formatBytes(file.size) }}</span>\n <button\n type=\"button\"\n class=\"wr-file-upload__remove\"\n [attr.aria-label]=\"resolvedRemove()\"\n [disabled]=\"effectiveDisabled()\"\n (click)=\"removeAt($index)\"\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" aria-hidden=\"true\">\n <path\n d=\"M2 2 L10 10 M10 2 L2 10\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n </li>\n }\n </ul>\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-file-upload.mjs","sources":["../../../projects/lib/file-upload/file-upload.ts","../../../projects/lib/file-upload/file-upload.html","../../../projects/lib/file-upload/ngwr-file-upload.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 {\n Component,\n type ElementRef,\n ViewEncapsulation,\n computed,\n effect,\n input,\n model,\n output,\n signal,\n untracked,\n viewChild,\n} from '@angular/core';\nimport type { FormValueControl } from '@angular/forms/signals';\n\nimport { useI18nText } from 'ngwr/i18n';\n\nimport type { WrFileUploadRejection, WrFileUploadRejectionReason } from './interfaces';\n\n/** Human-readable byte size (e.g. `1.2 MB`). */\nfunction formatBytes(bytes: number): string {\n if (!Number.isFinite(bytes) || bytes <= 0) return '0 B';\n const units = ['B', 'KB', 'MB', 'GB', 'TB'];\n const i = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1);\n const v = bytes / 1024 ** i;\n return `${v.toFixed(v >= 100 || i === 0 ? 0 : 1)} ${units[i]}`;\n}\n\n/** Does `file` match the `accept` attribute (extensions or MIME globs)? */\nfunction matchesAccept(file: File, accept: string): boolean {\n if (!accept) return true;\n const tokens = accept\n .split(',')\n .map(t => t.trim().toLowerCase())\n .filter(Boolean);\n if (tokens.length === 0) return true;\n const name = file.name.toLowerCase();\n const mime = file.type.toLowerCase();\n return tokens.some(token => {\n if (token.startsWith('.')) return name.endsWith(token);\n if (token.endsWith('/*')) return mime.startsWith(token.slice(0, -1));\n return mime === token;\n });\n}\n\n/**\n * Drag-and-drop file upload zone. Click to browse, drag-and-drop to add,\n * with an optional file list + remove buttons.\n *\n * A signal-forms native control: it implements\n * `FormValueControl<File | readonly File[] | null>`, so `[formField]` binds\n * straight to its `value` model — no `ControlValueAccessor` in between.\n * `[(value)]` works standalone. The value shape follows `multiple`: a single\n * `File` (or `null`), or a `File[]` array.\n *\n * @example\n * ```html\n * <!-- signal forms -->\n * <wr-file-upload [formField]=\"form.files\" [multiple]=\"true\" accept=\"image/*\" />\n *\n * <!-- standalone two-way binding -->\n * <wr-file-upload [(value)]=\"avatar\" accept=\".png,.jpg\" [maxSize]=\"2 * 1024 * 1024\" />\n * ```\n *\n * @see https://ngwr.dev/reference/components/file-upload\n */\n@Component({\n selector: 'wr-file-upload',\n templateUrl: './file-upload.html',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n imports: [],\n})\nexport class WrFileUpload implements FormValueControl<File | readonly File[] | null> {\n /** Allow multiple files. Single mode replaces on each add. @default false */\n readonly multiple = input(false, { transform: coerceBooleanProperty });\n\n /** `accept` attribute — comma-separated MIME types or extensions. @default '' */\n readonly accept = input<string>('');\n\n /** Max bytes per file. `0` disables the check. @default 0 */\n readonly maxSize = input(0, { transform: (v: unknown): number => Math.max(0, coerceNumberProperty(v, 0)) });\n\n /** Max files (multi mode only). `0` disables the check. @default 0 */\n readonly maxFiles = input(0, { transform: (v: unknown): number => Math.max(0, coerceNumberProperty(v, 0)) });\n\n /** Render the picked-files list below the zone. @default true */\n readonly showList = input(true, { transform: coerceBooleanProperty });\n\n /**\n * Disable interaction. 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 /** Primary call-to-action label. Falls back to `fileUpload.browse`. */\n readonly pickLabel = input<string | null>(null);\n\n /** Secondary instruction below the CTA. Falls back to `fileUpload.dropZone`. */\n readonly dropLabel = input<string | null>(null);\n\n /** Drop-zone host aria-label. Falls back to `fileUpload.dropZoneLabel`. */\n readonly dropZoneLabel = input<string | null>(null);\n\n /** Remove-file button aria-label. Falls back to `fileUpload.removeFile`. */\n readonly removeFileLabel = input<string | null>(null);\n\n protected readonly resolvedPick = useI18nText(this.pickLabel, 'fileUpload.browse', 'Click to browse');\n protected readonly resolvedDrop = useI18nText(this.dropLabel, 'fileUpload.dropZone', 'or drop files here');\n protected readonly resolvedDropZone = useI18nText(\n this.dropZoneLabel,\n 'fileUpload.dropZoneLabel',\n 'File upload drop zone — click or drop files'\n );\n protected readonly resolvedRemove = useI18nText(this.removeFileLabel, 'fileUpload.removeFile', 'Remove file');\n\n /** Optional helper text shown below the labels (e.g. accepted formats). */\n readonly helperText = input<string>('');\n\n /**\n * Selected file(s). Bound by `[formField]`, or two-way via `[(value)]`. Shape\n * follows `multiple`: a single `File` (or `null`), or a `File[]` array.\n */\n readonly value = model<File | readonly File[] | null>(null);\n\n /** Emitted when files are rejected for type / size / count reasons. */\n readonly rejected = output<readonly WrFileUploadRejection[]>();\n\n /** Emitted on commit so a bound field can mark itself touched. */\n readonly touch = output<void>();\n\n protected readonly picker = viewChild.required<ElementRef<HTMLInputElement>>('picker');\n\n protected readonly files = signal<readonly File[]>([]);\n protected readonly dragging = signal(false);\n\n protected readonly classes = computed(() => {\n const parts = ['wr-file-upload'];\n if (this.dragging()) parts.push('wr-file-upload--dragging');\n if (this.disabled()) parts.push('wr-file-upload--disabled');\n return parts.join(' ');\n });\n\n protected readonly formatBytes = formatBytes;\n\n constructor() {\n // Rebuild the internal file list from an external `value` write (mirrors the\n // old `writeValue`). Skipped when the value is merely the echo of an\n // in-component edit, so re-syncing can never clobber a live selection.\n effect(() => {\n const v = this.value();\n untracked(() => {\n // Coerce null/undefined to `[]` — a classic-forms binding can write\n // null, which the old `writeValue(v: … | null)` accepted too.\n const next: readonly File[] = v === null || v === undefined ? [] : Array.isArray(v) ? v : [v as File];\n const current = this.files();\n if (current.length === next.length && current.every((file, i) => file === next[i])) return;\n this.files.set(next);\n });\n });\n }\n\n // Template handlers\n\n protected openPicker(): void {\n if (this.disabled()) return;\n this.picker().nativeElement.click();\n }\n\n protected onZoneKey(event: KeyboardEvent): void {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n this.openPicker();\n }\n }\n\n protected onPickerChange(event: Event): void {\n const target = event.target as HTMLInputElement;\n if (target.files) this.acceptFiles(Array.from(target.files));\n // Reset so picking the same file twice re-fires `change`.\n target.value = '';\n }\n\n protected onDragEnter(event: DragEvent): void {\n if (this.disabled()) return;\n event.preventDefault();\n this.dragging.set(true);\n }\n\n protected onDragOver(event: DragEvent): void {\n if (this.disabled()) return;\n event.preventDefault();\n if (event.dataTransfer) event.dataTransfer.dropEffect = 'copy';\n }\n\n protected onDragLeave(event: DragEvent): void {\n // Only clear when leaving the zone itself, not internal children.\n if (event.currentTarget === event.target) this.dragging.set(false);\n }\n\n protected onDrop(event: DragEvent): void {\n event.preventDefault();\n this.dragging.set(false);\n if (this.disabled()) return;\n const dropped = event.dataTransfer?.files ? Array.from(event.dataTransfer.files) : [];\n if (dropped.length > 0) this.acceptFiles(dropped);\n }\n\n protected removeAt(index: number): void {\n if (this.disabled()) return;\n const next = this.files().filter((_, i) => i !== index);\n this.files.set(next);\n this.emit();\n }\n\n // Internals\n\n private acceptFiles(incoming: readonly File[]): void {\n const accept = this.accept();\n const maxSize = this.maxSize();\n const rejections: WrFileUploadRejection[] = [];\n const accepted: File[] = [];\n\n for (const file of incoming) {\n const reason = this.reject(file, accept, maxSize);\n if (reason) rejections.push({ file, reason });\n else accepted.push(file);\n }\n\n let next: File[];\n if (this.multiple()) {\n next = [...this.files(), ...accepted];\n const maxFiles = this.maxFiles();\n if (maxFiles > 0 && next.length > maxFiles) {\n const overflow = next.splice(maxFiles);\n for (const file of overflow) rejections.push({ file, reason: 'count' });\n }\n } else {\n // Single mode — last accepted wins, prior selection cleared.\n next = accepted.length > 0 ? [accepted[accepted.length - 1]] : [...this.files()];\n }\n\n this.files.set(next);\n this.touch.emit();\n this.emit();\n if (rejections.length > 0) this.rejected.emit(rejections);\n }\n\n private reject(file: File, accept: string, maxSize: number): WrFileUploadRejectionReason | null {\n if (accept && !matchesAccept(file, accept)) return 'type';\n if (maxSize > 0 && file.size > maxSize) return 'size';\n return null;\n }\n\n private emit(): void {\n const list = this.files();\n if (this.multiple()) {\n this.value.set(list);\n } else {\n this.value.set(list.length > 0 ? list[0] : null);\n }\n }\n}\n","<div\n class=\"wr-file-upload__zone\"\n role=\"button\"\n tabindex=\"0\"\n [attr.aria-label]=\"resolvedDropZone()\"\n [attr.aria-disabled]=\"disabled() || null\"\n (click)=\"openPicker()\"\n (keydown)=\"onZoneKey($event)\"\n (dragenter)=\"onDragEnter($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n>\n <svg class=\"wr-file-upload__icon\" width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path\n d=\"M12 16V4M12 4l-4 4M12 4l4 4M4 16v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n <div class=\"wr-file-upload__hint\">\n <strong>{{ resolvedPick() }}</strong>\n <span>{{ resolvedDrop() }}</span>\n @if (helperText()) {\n <small>{{ helperText() }}</small>\n }\n </div>\n <input\n #picker\n class=\"wr-file-upload__picker\"\n type=\"file\"\n [attr.accept]=\"accept() || null\"\n [attr.multiple]=\"multiple() ? '' : null\"\n [disabled]=\"disabled()\"\n (change)=\"onPickerChange($event)\"\n />\n</div>\n\n@if (showList() && files().length > 0) {\n <ul class=\"wr-file-upload__list\">\n @for (file of files(); track $index) {\n <li class=\"wr-file-upload__item\">\n <span class=\"wr-file-upload__name\" [title]=\"file.name\">{{ file.name }}</span>\n <span class=\"wr-file-upload__size\">{{ formatBytes(file.size) }}</span>\n <button\n type=\"button\"\n class=\"wr-file-upload__remove\"\n [attr.aria-label]=\"resolvedRemove()\"\n [disabled]=\"disabled()\"\n (click)=\"removeAt($index)\"\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" aria-hidden=\"true\">\n <path\n d=\"M2 2 L10 10 M10 2 L2 10\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n </li>\n }\n </ul>\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -24,7 +24,7 @@ import { NgControl } from '@angular/forms';
24
24
  * </wr-form-item>
25
25
  * ```
26
26
  *
27
- * @see https://ngwr.dev/components/form
27
+ * @see https://ngwr.dev/reference/components/form
28
28
  */
29
29
  class WrFormItem {
30
30
  /**
@@ -40,10 +40,10 @@ class WrFormItem {
40
40
  return parts.join(' ');
41
41
  }, /* @ts-ignore */
42
42
  ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
43
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: WrFormItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
44
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.4", type: WrFormItem, isStandalone: true, selector: "wr-form-item", inputs: { hasError: { classPropertyName: "hasError", publicName: "hasError", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: '<ng-content />', isInline: true, encapsulation: i0.ViewEncapsulation.None });
43
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrFormItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
44
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.0", type: WrFormItem, isStandalone: true, selector: "wr-form-item", inputs: { hasError: { classPropertyName: "hasError", publicName: "hasError", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: '<ng-content />', isInline: true, encapsulation: i0.ViewEncapsulation.None });
45
45
  }
46
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: WrFormItem, decorators: [{
46
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrFormItem, decorators: [{
47
47
  type: Component,
48
48
  args: [{
49
49
  selector: 'wr-form-item',
@@ -79,7 +79,7 @@ let uid = 0;
79
79
  * </wr-form-field>
80
80
  * ```
81
81
  *
82
- * @see https://ngwr.dev/components/form-field
82
+ * @see https://ngwr.dev/reference/components/form-field
83
83
  */
84
84
  class WrFormField {
85
85
  /** Label text shown above the control. */
@@ -121,10 +121,10 @@ class WrFormField {
121
121
  return parts.join(' ');
122
122
  }, /* @ts-ignore */
123
123
  ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
124
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: WrFormField, deps: [], target: i0.ɵɵFactoryTarget.Component });
125
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: WrFormField, isStandalone: true, selector: "wr-form-field", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, optional: { classPropertyName: "optional", publicName: "optional", isSignal: true, isRequired: false, transformFunction: null }, controlId: { classPropertyName: "controlId", publicName: "controlId", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, queries: [{ propertyName: "ngControl", first: true, predicate: NgControl, descendants: true, isSignal: true }], ngImport: i0, template: "@if (label()) {\n <label class=\"wr-form-field__label\" [attr.for]=\"controlId()\">\n {{ label() }}\n @if (required()) {\n <span class=\"wr-form-field__required\" aria-hidden=\"true\">*</span>\n } @else if (optional()) {\n <span class=\"wr-form-field__optional\">(optional)</span>\n }\n </label>\n}\n\n<div class=\"wr-form-field__control\"><ng-content /></div>\n\n@if (hasError()) {\n <div class=\"wr-form-field__errors\">\n <ng-content select=\"wr-form-error\" />\n </div>\n} @else if (hint()) {\n <small class=\"wr-form-field__hint\">{{ hint() }}</small>\n}\n", encapsulation: i0.ViewEncapsulation.None });
124
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrFormField, deps: [], target: i0.ɵɵFactoryTarget.Component });
125
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: WrFormField, isStandalone: true, selector: "wr-form-field", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, optional: { classPropertyName: "optional", publicName: "optional", isSignal: true, isRequired: false, transformFunction: null }, controlId: { classPropertyName: "controlId", publicName: "controlId", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, queries: [{ propertyName: "ngControl", first: true, predicate: NgControl, descendants: true, isSignal: true }], ngImport: i0, template: "@if (label()) {\n <label class=\"wr-form-field__label\" [attr.for]=\"controlId()\">\n {{ label() }}\n @if (required()) {\n <span class=\"wr-form-field__required\" aria-hidden=\"true\">*</span>\n } @else if (optional()) {\n <span class=\"wr-form-field__optional\">(optional)</span>\n }\n </label>\n}\n\n<div class=\"wr-form-field__control\"><ng-content /></div>\n\n@if (hasError()) {\n <div class=\"wr-form-field__errors\">\n <ng-content select=\"wr-form-error\" />\n </div>\n} @else if (hint()) {\n <small class=\"wr-form-field__hint\">{{ hint() }}</small>\n}\n", encapsulation: i0.ViewEncapsulation.None });
126
126
  }
127
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: WrFormField, decorators: [{
127
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrFormField, decorators: [{
128
128
  type: Component,
129
129
  args: [{ selector: 'wr-form-field', encapsulation: ViewEncapsulation.None, host: { '[class]': 'classes()' }, template: "@if (label()) {\n <label class=\"wr-form-field__label\" [attr.for]=\"controlId()\">\n {{ label() }}\n @if (required()) {\n <span class=\"wr-form-field__required\" aria-hidden=\"true\">*</span>\n } @else if (optional()) {\n <span class=\"wr-form-field__optional\">(optional)</span>\n }\n </label>\n}\n\n<div class=\"wr-form-field__control\"><ng-content /></div>\n\n@if (hasError()) {\n <div class=\"wr-form-field__errors\">\n <ng-content select=\"wr-form-error\" />\n </div>\n} @else if (hint()) {\n <small class=\"wr-form-field__hint\">{{ hint() }}</small>\n}\n" }]
130
130
  }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], optional: [{ type: i0.Input, args: [{ isSignal: true, alias: "optional", required: false }] }], controlId: [{ type: i0.Input, args: [{ isSignal: true, alias: "controlId", required: false }] }], ngControl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NgControl), { isSignal: true }] }] } });
@@ -146,10 +146,10 @@ class WrFormError {
146
146
  */
147
147
  key = input(/* @ts-ignore */
148
148
  ...(ngDevMode ? [undefined, { debugName: "key" }] : /* istanbul ignore next */ []));
149
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: WrFormError, deps: [], target: i0.ɵɵFactoryTarget.Component });
150
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.4", type: WrFormError, isStandalone: true, selector: "wr-form-error", inputs: { key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "alert" }, properties: { "attr.data-key": "key() ?? null" }, classAttribute: "wr-form-error wr-form-field__error" }, ngImport: i0, template: `<ng-content />`, isInline: true, encapsulation: i0.ViewEncapsulation.None });
149
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrFormError, deps: [], target: i0.ɵɵFactoryTarget.Component });
150
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.0", type: WrFormError, isStandalone: true, selector: "wr-form-error", inputs: { key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "alert" }, properties: { "attr.data-key": "key() ?? null" }, classAttribute: "wr-form-error wr-form-field__error" }, ngImport: i0, template: `<ng-content />`, isInline: true, encapsulation: i0.ViewEncapsulation.None });
151
151
  }
152
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: WrFormError, decorators: [{
152
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrFormError, decorators: [{
153
153
  type: Component,
154
154
  args: [{
155
155
  selector: 'wr-form-error',