ngwr 10.2.1 → 11.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (431) hide show
  1. package/README.md +39 -19
  2. package/action-sheet/styles/_index.scss +4 -1
  3. package/anchor/styles/_index.scss +6 -5
  4. package/back-top/styles/_index.scss +6 -1
  5. package/blur-text/styles/_index.scss +13 -0
  6. package/button/styles/_index.scss +11 -6
  7. package/calendar/styles/_index.scss +11 -2
  8. package/carousel/styles/_index.scss +13 -2
  9. package/cascader/styles/_index.scss +5 -3
  10. package/circular-text/styles/_index.scss +2 -0
  11. package/collapse/styles/_index.scss +1 -1
  12. package/color-picker/styles/_index.scss +6 -1
  13. package/command-palette/styles/_index.scss +2 -1
  14. package/compare/styles/_index.scss +1 -2
  15. package/context-menu/styles/_index.scss +8 -2
  16. package/descriptions/styles/_index.scss +2 -2
  17. package/dialog/styles/_index.scss +7 -0
  18. package/drawer/styles/_index.scss +20 -1
  19. package/dropdown/styles/_index.scss +19 -5
  20. package/empty/styles/_index.scss +10 -0
  21. package/falling-text/styles/_index.scss +2 -1
  22. package/fesm2022/ngwr-action-sheet.mjs +13 -3
  23. package/fesm2022/ngwr-action-sheet.mjs.map +1 -1
  24. package/fesm2022/ngwr-affix.mjs +40 -13
  25. package/fesm2022/ngwr-affix.mjs.map +1 -1
  26. package/fesm2022/ngwr-anchor.mjs +18 -6
  27. package/fesm2022/ngwr-anchor.mjs.map +1 -1
  28. package/fesm2022/ngwr-aurora.mjs +2 -2
  29. package/fesm2022/ngwr-aurora.mjs.map +1 -1
  30. package/fesm2022/ngwr-avatar.mjs +31 -7
  31. package/fesm2022/ngwr-avatar.mjs.map +1 -1
  32. package/fesm2022/ngwr-back-top.mjs +6 -2
  33. package/fesm2022/ngwr-back-top.mjs.map +1 -1
  34. package/fesm2022/ngwr-badge.mjs +1 -1
  35. package/fesm2022/ngwr-badge.mjs.map +1 -1
  36. package/fesm2022/ngwr-bar-chart.mjs +30 -9
  37. package/fesm2022/ngwr-bar-chart.mjs.map +1 -1
  38. package/fesm2022/ngwr-blur-text.mjs +2 -2
  39. package/fesm2022/ngwr-blur-text.mjs.map +1 -1
  40. package/fesm2022/ngwr-border-glow.mjs +2 -2
  41. package/fesm2022/ngwr-border-glow.mjs.map +1 -1
  42. package/fesm2022/ngwr-breadcrumbs.mjs +2 -2
  43. package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
  44. package/fesm2022/ngwr-burger.mjs +9 -4
  45. package/fesm2022/ngwr-burger.mjs.map +1 -1
  46. package/fesm2022/ngwr-button-testing.mjs +96 -0
  47. package/fesm2022/ngwr-button-testing.mjs.map +1 -0
  48. package/fesm2022/ngwr-button.mjs +31 -14
  49. package/fesm2022/ngwr-button.mjs.map +1 -1
  50. package/fesm2022/ngwr-calendar-heatmap.mjs +40 -8
  51. package/fesm2022/ngwr-calendar-heatmap.mjs.map +1 -1
  52. package/fesm2022/ngwr-calendar.mjs +20 -1
  53. package/fesm2022/ngwr-calendar.mjs.map +1 -1
  54. package/fesm2022/ngwr-card.mjs +2 -2
  55. package/fesm2022/ngwr-card.mjs.map +1 -1
  56. package/fesm2022/ngwr-carousel-testing.mjs +377 -0
  57. package/fesm2022/ngwr-carousel-testing.mjs.map +1 -0
  58. package/fesm2022/ngwr-carousel.mjs +67 -13
  59. package/fesm2022/ngwr-carousel.mjs.map +1 -1
  60. package/fesm2022/ngwr-cascader-testing.mjs +534 -0
  61. package/fesm2022/ngwr-cascader-testing.mjs.map +1 -0
  62. package/fesm2022/ngwr-cascader.mjs +2 -2
  63. package/fesm2022/ngwr-cascader.mjs.map +1 -1
  64. package/fesm2022/ngwr-checkbox-testing.mjs +90 -0
  65. package/fesm2022/ngwr-checkbox-testing.mjs.map +1 -0
  66. package/fesm2022/ngwr-checkbox.mjs +9 -3
  67. package/fesm2022/ngwr-checkbox.mjs.map +1 -1
  68. package/fesm2022/ngwr-circular-text.mjs +2 -2
  69. package/fesm2022/ngwr-circular-text.mjs.map +1 -1
  70. package/fesm2022/ngwr-click-spark.mjs +2 -2
  71. package/fesm2022/ngwr-click-spark.mjs.map +1 -1
  72. package/fesm2022/ngwr-collapse-testing.mjs +368 -0
  73. package/fesm2022/ngwr-collapse-testing.mjs.map +1 -0
  74. package/fesm2022/ngwr-color-picker.mjs +134 -14
  75. package/fesm2022/ngwr-color-picker.mjs.map +1 -1
  76. package/fesm2022/ngwr-command-palette-testing.mjs +589 -0
  77. package/fesm2022/ngwr-command-palette-testing.mjs.map +1 -0
  78. package/fesm2022/ngwr-command-palette.mjs +58 -8
  79. package/fesm2022/ngwr-command-palette.mjs.map +1 -1
  80. package/fesm2022/ngwr-compare.mjs +103 -13
  81. package/fesm2022/ngwr-compare.mjs.map +1 -1
  82. package/fesm2022/ngwr-config.mjs +106 -0
  83. package/fesm2022/ngwr-config.mjs.map +1 -0
  84. package/fesm2022/ngwr-context-menu-testing.mjs +631 -0
  85. package/fesm2022/ngwr-context-menu-testing.mjs.map +1 -0
  86. package/fesm2022/ngwr-context-menu.mjs +94 -8
  87. package/fesm2022/ngwr-context-menu.mjs.map +1 -1
  88. package/fesm2022/ngwr-cookie.mjs +5 -1
  89. package/fesm2022/ngwr-cookie.mjs.map +1 -1
  90. package/fesm2022/ngwr-counter.mjs +11 -3
  91. package/fesm2022/ngwr-counter.mjs.map +1 -1
  92. package/fesm2022/ngwr-date-adapter-luxon.mjs +52 -4
  93. package/fesm2022/ngwr-date-adapter-luxon.mjs.map +1 -1
  94. package/fesm2022/ngwr-date-adapter.mjs +54 -8
  95. package/fesm2022/ngwr-date-adapter.mjs.map +1 -1
  96. package/fesm2022/ngwr-date-picker-testing.mjs +766 -0
  97. package/fesm2022/ngwr-date-picker-testing.mjs.map +1 -0
  98. package/fesm2022/ngwr-date-picker.mjs +73 -3
  99. package/fesm2022/ngwr-date-picker.mjs.map +1 -1
  100. package/fesm2022/ngwr-decrypt-text.mjs +27 -9
  101. package/fesm2022/ngwr-decrypt-text.mjs.map +1 -1
  102. package/fesm2022/ngwr-dialog-testing.mjs +89 -0
  103. package/fesm2022/ngwr-dialog-testing.mjs.map +1 -0
  104. package/fesm2022/ngwr-directives.mjs +36 -12
  105. package/fesm2022/ngwr-directives.mjs.map +1 -1
  106. package/fesm2022/ngwr-donut-chart.mjs +22 -5
  107. package/fesm2022/ngwr-donut-chart.mjs.map +1 -1
  108. package/fesm2022/ngwr-drag-drop.mjs +2 -2
  109. package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
  110. package/fesm2022/ngwr-drawer-testing.mjs +250 -0
  111. package/fesm2022/ngwr-drawer-testing.mjs.map +1 -0
  112. package/fesm2022/ngwr-dropdown-testing.mjs +291 -0
  113. package/fesm2022/ngwr-dropdown-testing.mjs.map +1 -0
  114. package/fesm2022/ngwr-dropdown.mjs +10 -2
  115. package/fesm2022/ngwr-dropdown.mjs.map +1 -1
  116. package/fesm2022/ngwr-empty.mjs +24 -7
  117. package/fesm2022/ngwr-empty.mjs.map +1 -1
  118. package/fesm2022/ngwr-event-calendar.mjs +57 -10
  119. package/fesm2022/ngwr-event-calendar.mjs.map +1 -1
  120. package/fesm2022/ngwr-falling-text.mjs +2 -2
  121. package/fesm2022/ngwr-falling-text.mjs.map +1 -1
  122. package/fesm2022/ngwr-file-upload-testing.mjs +332 -0
  123. package/fesm2022/ngwr-file-upload-testing.mjs.map +1 -0
  124. package/fesm2022/ngwr-form-testing.mjs +451 -0
  125. package/fesm2022/ngwr-form-testing.mjs.map +1 -0
  126. package/fesm2022/ngwr-form.mjs +19 -3
  127. package/fesm2022/ngwr-form.mjs.map +1 -1
  128. package/fesm2022/ngwr-fuzzy-text.mjs +9 -2
  129. package/fesm2022/ngwr-fuzzy-text.mjs.map +1 -1
  130. package/fesm2022/ngwr-gauge.mjs +19 -5
  131. package/fesm2022/ngwr-gauge.mjs.map +1 -1
  132. package/fesm2022/ngwr-glitch-text.mjs +2 -2
  133. package/fesm2022/ngwr-glitch-text.mjs.map +1 -1
  134. package/fesm2022/ngwr-gradient-text.mjs +2 -2
  135. package/fesm2022/ngwr-gradient-text.mjs.map +1 -1
  136. package/fesm2022/ngwr-i18n-en.mjs +50 -0
  137. package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
  138. package/fesm2022/ngwr-i18n-ru.mjs +48 -0
  139. package/fesm2022/ngwr-i18n-ru.mjs.map +1 -1
  140. package/fesm2022/ngwr-image-cropper.mjs +23 -0
  141. package/fesm2022/ngwr-image-cropper.mjs.map +1 -1
  142. package/fesm2022/ngwr-input-number-testing.mjs +306 -0
  143. package/fesm2022/ngwr-input-number-testing.mjs.map +1 -0
  144. package/fesm2022/ngwr-input-number.mjs +35 -3
  145. package/fesm2022/ngwr-input-number.mjs.map +1 -1
  146. package/fesm2022/ngwr-input-otp-testing.mjs +419 -0
  147. package/fesm2022/ngwr-input-otp-testing.mjs.map +1 -0
  148. package/fesm2022/ngwr-input-otp.mjs +36 -5
  149. package/fesm2022/ngwr-input-otp.mjs.map +1 -1
  150. package/fesm2022/ngwr-input-testing.mjs +102 -0
  151. package/fesm2022/ngwr-input-testing.mjs.map +1 -0
  152. package/fesm2022/ngwr-input.mjs +47 -10
  153. package/fesm2022/ngwr-input.mjs.map +1 -1
  154. package/fesm2022/ngwr-knob.mjs +44 -8
  155. package/fesm2022/ngwr-knob.mjs.map +1 -1
  156. package/fesm2022/ngwr-layout.mjs +21 -5
  157. package/fesm2022/ngwr-layout.mjs.map +1 -1
  158. package/fesm2022/ngwr-lightbox.mjs +33 -6
  159. package/fesm2022/ngwr-lightbox.mjs.map +1 -1
  160. package/fesm2022/ngwr-line-chart.mjs +17 -4
  161. package/fesm2022/ngwr-line-chart.mjs.map +1 -1
  162. package/fesm2022/ngwr-list.mjs +2 -2
  163. package/fesm2022/ngwr-list.mjs.map +1 -1
  164. package/fesm2022/ngwr-loading-bar.mjs +2 -2
  165. package/fesm2022/ngwr-loading-bar.mjs.map +1 -1
  166. package/fesm2022/ngwr-markdown-testing.mjs +516 -0
  167. package/fesm2022/ngwr-markdown-testing.mjs.map +1 -0
  168. package/fesm2022/ngwr-markdown.mjs +1492 -0
  169. package/fesm2022/ngwr-markdown.mjs.map +1 -0
  170. package/fesm2022/ngwr-marquee.mjs +17 -6
  171. package/fesm2022/ngwr-marquee.mjs.map +1 -1
  172. package/fesm2022/ngwr-mention-testing.mjs +513 -0
  173. package/fesm2022/ngwr-mention-testing.mjs.map +1 -0
  174. package/fesm2022/ngwr-mention.mjs +10 -1
  175. package/fesm2022/ngwr-mention.mjs.map +1 -1
  176. package/fesm2022/ngwr-meta.mjs +22 -7
  177. package/fesm2022/ngwr-meta.mjs.map +1 -1
  178. package/fesm2022/ngwr-meter-group.mjs +19 -5
  179. package/fesm2022/ngwr-meter-group.mjs.map +1 -1
  180. package/fesm2022/ngwr-overlay.mjs +41 -1
  181. package/fesm2022/ngwr-overlay.mjs.map +1 -1
  182. package/fesm2022/ngwr-pagination-testing.mjs +389 -0
  183. package/fesm2022/ngwr-pagination-testing.mjs.map +1 -0
  184. package/fesm2022/ngwr-pagination.mjs +14 -2
  185. package/fesm2022/ngwr-pagination.mjs.map +1 -1
  186. package/fesm2022/ngwr-popconfirm-testing.mjs +309 -0
  187. package/fesm2022/ngwr-popconfirm-testing.mjs.map +1 -0
  188. package/fesm2022/ngwr-popconfirm.mjs +95 -17
  189. package/fesm2022/ngwr-popconfirm.mjs.map +1 -1
  190. package/fesm2022/ngwr-popover-testing.mjs +316 -0
  191. package/fesm2022/ngwr-popover-testing.mjs.map +1 -0
  192. package/fesm2022/ngwr-popover.mjs +21 -3
  193. package/fesm2022/ngwr-popover.mjs.map +1 -1
  194. package/fesm2022/ngwr-pull-to-refresh.mjs +17 -2
  195. package/fesm2022/ngwr-pull-to-refresh.mjs.map +1 -1
  196. package/fesm2022/ngwr-qr.mjs +13 -3
  197. package/fesm2022/ngwr-qr.mjs.map +1 -1
  198. package/fesm2022/ngwr-radio-testing.mjs +392 -0
  199. package/fesm2022/ngwr-radio-testing.mjs.map +1 -0
  200. package/fesm2022/ngwr-radio.mjs +10 -3
  201. package/fesm2022/ngwr-radio.mjs.map +1 -1
  202. package/fesm2022/ngwr-rating-testing.mjs +384 -0
  203. package/fesm2022/ngwr-rating-testing.mjs.map +1 -0
  204. package/fesm2022/ngwr-rating.mjs +37 -2
  205. package/fesm2022/ngwr-rating.mjs.map +1 -1
  206. package/fesm2022/ngwr-segmented-testing.mjs +512 -0
  207. package/fesm2022/ngwr-segmented-testing.mjs.map +1 -0
  208. package/fesm2022/ngwr-select-testing.mjs +268 -0
  209. package/fesm2022/ngwr-select-testing.mjs.map +1 -0
  210. package/fesm2022/ngwr-select.mjs +87 -16
  211. package/fesm2022/ngwr-select.mjs.map +1 -1
  212. package/fesm2022/ngwr-shiny-text.mjs +2 -2
  213. package/fesm2022/ngwr-shiny-text.mjs.map +1 -1
  214. package/fesm2022/ngwr-sidebar.mjs +65 -12
  215. package/fesm2022/ngwr-sidebar.mjs.map +1 -1
  216. package/fesm2022/ngwr-slider-testing.mjs +478 -0
  217. package/fesm2022/ngwr-slider-testing.mjs.map +1 -0
  218. package/fesm2022/ngwr-slider.mjs +57 -13
  219. package/fesm2022/ngwr-slider.mjs.map +1 -1
  220. package/fesm2022/ngwr-sparkline.mjs +26 -6
  221. package/fesm2022/ngwr-sparkline.mjs.map +1 -1
  222. package/fesm2022/ngwr-speed-dial.mjs +37 -4
  223. package/fesm2022/ngwr-speed-dial.mjs.map +1 -1
  224. package/fesm2022/ngwr-spinner.mjs +12 -3
  225. package/fesm2022/ngwr-spinner.mjs.map +1 -1
  226. package/fesm2022/ngwr-splash-cursor.mjs +2 -2
  227. package/fesm2022/ngwr-splash-cursor.mjs.map +1 -1
  228. package/fesm2022/ngwr-split-text.mjs +2 -2
  229. package/fesm2022/ngwr-split-text.mjs.map +1 -1
  230. package/fesm2022/ngwr-splitter.mjs +70 -9
  231. package/fesm2022/ngwr-splitter.mjs.map +1 -1
  232. package/fesm2022/ngwr-spotlight-card.mjs +2 -2
  233. package/fesm2022/ngwr-spotlight-card.mjs.map +1 -1
  234. package/fesm2022/ngwr-star-border.mjs +2 -2
  235. package/fesm2022/ngwr-star-border.mjs.map +1 -1
  236. package/fesm2022/ngwr-statistic.mjs +24 -7
  237. package/fesm2022/ngwr-statistic.mjs.map +1 -1
  238. package/fesm2022/ngwr-stepper-testing.mjs +477 -0
  239. package/fesm2022/ngwr-stepper-testing.mjs.map +1 -0
  240. package/fesm2022/ngwr-switch-testing.mjs +77 -0
  241. package/fesm2022/ngwr-switch-testing.mjs.map +1 -0
  242. package/fesm2022/ngwr-switch.mjs +9 -3
  243. package/fesm2022/ngwr-switch.mjs.map +1 -1
  244. package/fesm2022/ngwr-table-testing.mjs +580 -0
  245. package/fesm2022/ngwr-table-testing.mjs.map +1 -0
  246. package/fesm2022/ngwr-table.mjs +87 -14
  247. package/fesm2022/ngwr-table.mjs.map +1 -1
  248. package/fesm2022/ngwr-tabs-testing.mjs +617 -0
  249. package/fesm2022/ngwr-tabs-testing.mjs.map +1 -0
  250. package/fesm2022/ngwr-tabs.mjs +38 -6
  251. package/fesm2022/ngwr-tabs.mjs.map +1 -1
  252. package/fesm2022/ngwr-textarea-testing.mjs +238 -0
  253. package/fesm2022/ngwr-textarea-testing.mjs.map +1 -0
  254. package/fesm2022/ngwr-textarea.mjs +32 -4
  255. package/fesm2022/ngwr-textarea.mjs.map +1 -1
  256. package/fesm2022/ngwr-tilt-card.mjs +2 -2
  257. package/fesm2022/ngwr-tilt-card.mjs.map +1 -1
  258. package/fesm2022/ngwr-toast-testing.mjs +101 -0
  259. package/fesm2022/ngwr-toast-testing.mjs.map +1 -0
  260. package/fesm2022/ngwr-toast.mjs +2 -2
  261. package/fesm2022/ngwr-toast.mjs.map +1 -1
  262. package/fesm2022/ngwr-tour.mjs +61 -9
  263. package/fesm2022/ngwr-tour.mjs.map +1 -1
  264. package/fesm2022/ngwr-transfer-testing.mjs +538 -0
  265. package/fesm2022/ngwr-transfer-testing.mjs.map +1 -0
  266. package/fesm2022/ngwr-transfer.mjs +45 -14
  267. package/fesm2022/ngwr-transfer.mjs.map +1 -1
  268. package/fesm2022/ngwr-tree-testing.mjs +734 -0
  269. package/fesm2022/ngwr-tree-testing.mjs.map +1 -0
  270. package/fesm2022/ngwr-tree.mjs +73 -7
  271. package/fesm2022/ngwr-tree.mjs.map +1 -1
  272. package/fesm2022/ngwr-typewriter.mjs +5 -3
  273. package/fesm2022/ngwr-typewriter.mjs.map +1 -1
  274. package/fesm2022/ngwr-version.mjs +1 -1
  275. package/fesm2022/ngwr-version.mjs.map +1 -1
  276. package/fesm2022/ngwr-virtual-scroll.mjs +31 -5
  277. package/fesm2022/ngwr-virtual-scroll.mjs.map +1 -1
  278. package/fesm2022/ngwr-waves.mjs +3 -3
  279. package/fesm2022/ngwr-waves.mjs.map +1 -1
  280. package/fesm2022/ngwr-window.mjs +8 -0
  281. package/fesm2022/ngwr-window.mjs.map +1 -1
  282. package/file-upload/styles/_index.scss +7 -2
  283. package/gauge/styles/_index.scss +1 -1
  284. package/glitch-text/styles/_index.scss +4 -0
  285. package/i18n/en.json +48 -0
  286. package/i18n/ru.json +48 -0
  287. package/image-cropper/styles/_index.scss +13 -1
  288. package/input/styles/_index.scss +2 -2
  289. package/input-number/styles/_index.scss +7 -2
  290. package/knob/styles/_index.scss +8 -1
  291. package/layout/styles/_index.scss +3 -3
  292. package/lightbox/styles/_index.scss +10 -2
  293. package/line-chart/styles/_index.scss +6 -0
  294. package/llms-full.txt +151 -4
  295. package/llms.txt +57 -8
  296. package/loading-bar/styles/_index.scss +1 -2
  297. package/markdown/styles/_index.scss +296 -0
  298. package/marquee/styles/_index.scss +12 -0
  299. package/mcp/api.js +512 -0
  300. package/mcp/catalog.js +157 -0
  301. package/mcp/server.js +273 -0
  302. package/mcp/tools.js +366 -0
  303. package/meter-group/styles/_index.scss +1 -1
  304. package/package.json +186 -35
  305. package/pagination/styles/_index.scss +6 -6
  306. package/popover/styles/_index.scss +37 -5
  307. package/rating/styles/_index.scss +10 -0
  308. package/result/styles/_index.scss +3 -1
  309. package/schematics/use/symbol-map.json +2 -0
  310. package/segmented/styles/_index.scss +12 -1
  311. package/select/styles/_index.scss +32 -10
  312. package/sidebar/styles/_index.scss +30 -5
  313. package/slider/styles/_index.scss +15 -0
  314. package/speed-dial/styles/_index.scss +20 -0
  315. package/split-text/styles/_index.scss +13 -0
  316. package/star-border/styles/_index.scss +2 -0
  317. package/stepper/styles/_index.scss +19 -3
  318. package/styles/_grid.scss +4 -4
  319. package/styles.scss +1 -0
  320. package/switch/styles/_index.scss +5 -3
  321. package/table/styles/_index.scss +25 -12
  322. package/tabs/styles/_index.scss +11 -1
  323. package/textarea/styles/_index.scss +5 -0
  324. package/theme/styles/_colors.scss +44 -15
  325. package/theme/styles/_dark.scss +35 -15
  326. package/theme/styles/_mixins.scss +3 -0
  327. package/timeline/styles/_index.scss +2 -2
  328. package/toast/styles/_index.scss +17 -8
  329. package/toolbar/styles/_index.scss +3 -3
  330. package/tour/styles/_index.scss +7 -1
  331. package/tree/styles/_index.scss +9 -5
  332. package/types/ngwr-action-sheet.d.ts +9 -1
  333. package/types/ngwr-affix.d.ts +7 -1
  334. package/types/ngwr-anchor.d.ts +8 -1
  335. package/types/ngwr-avatar.d.ts +13 -3
  336. package/types/ngwr-bar-chart.d.ts +16 -0
  337. package/types/ngwr-burger.d.ts +6 -2
  338. package/types/ngwr-button-testing.d.ts +85 -0
  339. package/types/ngwr-button.d.ts +26 -10
  340. package/types/ngwr-calendar-heatmap.d.ts +16 -2
  341. package/types/ngwr-calendar.d.ts +10 -0
  342. package/types/ngwr-carousel-testing.d.ts +257 -0
  343. package/types/ngwr-carousel.d.ts +20 -4
  344. package/types/ngwr-cascader-testing.d.ts +392 -0
  345. package/types/ngwr-checkbox-testing.d.ts +77 -0
  346. package/types/ngwr-checkbox.d.ts +7 -2
  347. package/types/ngwr-collapse-testing.d.ts +290 -0
  348. package/types/ngwr-color-picker.d.ts +20 -11
  349. package/types/ngwr-command-palette-testing.d.ts +437 -0
  350. package/types/ngwr-command-palette.d.ts +25 -2
  351. package/types/ngwr-compare.d.ts +50 -2
  352. package/types/ngwr-config.d.ts +176 -0
  353. package/types/ngwr-context-menu-testing.d.ts +401 -0
  354. package/types/ngwr-context-menu.d.ts +65 -17
  355. package/types/ngwr-counter.d.ts +6 -1
  356. package/types/ngwr-date-adapter-luxon.d.ts +26 -0
  357. package/types/ngwr-date-picker-testing.d.ts +518 -0
  358. package/types/ngwr-date-picker.d.ts +4 -0
  359. package/types/ngwr-dialog-testing.d.ts +79 -0
  360. package/types/ngwr-directives.d.ts +10 -1
  361. package/types/ngwr-donut-chart.d.ts +8 -1
  362. package/types/ngwr-drawer-testing.d.ts +196 -0
  363. package/types/ngwr-dropdown-testing.d.ts +202 -0
  364. package/types/ngwr-dropdown.d.ts +7 -1
  365. package/types/ngwr-empty.d.ts +19 -4
  366. package/types/ngwr-event-calendar.d.ts +26 -1
  367. package/types/ngwr-file-upload-testing.d.ts +194 -0
  368. package/types/ngwr-form-testing.d.ts +379 -0
  369. package/types/ngwr-form.d.ts +17 -0
  370. package/types/ngwr-gauge.d.ts +13 -1
  371. package/types/ngwr-image-cropper.d.ts +10 -0
  372. package/types/ngwr-input-number-testing.d.ts +226 -0
  373. package/types/ngwr-input-number.d.ts +29 -1
  374. package/types/ngwr-input-otp-testing.d.ts +299 -0
  375. package/types/ngwr-input-otp.d.ts +23 -2
  376. package/types/ngwr-input-testing.d.ts +84 -0
  377. package/types/ngwr-input.d.ts +20 -6
  378. package/types/ngwr-knob.d.ts +18 -0
  379. package/types/ngwr-layout.d.ts +1 -0
  380. package/types/ngwr-lightbox.d.ts +17 -3
  381. package/types/ngwr-line-chart.d.ts +9 -2
  382. package/types/ngwr-markdown-testing.d.ts +462 -0
  383. package/types/ngwr-markdown.d.ts +534 -0
  384. package/types/ngwr-marquee.d.ts +12 -2
  385. package/types/ngwr-mention-testing.d.ts +359 -0
  386. package/types/ngwr-meta.d.ts +4 -2
  387. package/types/ngwr-meter-group.d.ts +11 -1
  388. package/types/ngwr-overlay.d.ts +33 -2
  389. package/types/ngwr-pagination-testing.d.ts +291 -0
  390. package/types/ngwr-pagination.d.ts +1 -0
  391. package/types/ngwr-popconfirm-testing.d.ts +235 -0
  392. package/types/ngwr-popconfirm.d.ts +31 -21
  393. package/types/ngwr-popover-testing.d.ts +221 -0
  394. package/types/ngwr-popover.d.ts +9 -0
  395. package/types/ngwr-pull-to-refresh.d.ts +7 -0
  396. package/types/ngwr-qr.d.ts +9 -1
  397. package/types/ngwr-radio-testing.d.ts +296 -0
  398. package/types/ngwr-radio.d.ts +8 -2
  399. package/types/ngwr-rating-testing.d.ts +291 -0
  400. package/types/ngwr-rating.d.ts +23 -0
  401. package/types/ngwr-segmented-testing.d.ts +401 -0
  402. package/types/ngwr-select-testing.d.ts +175 -0
  403. package/types/ngwr-select.d.ts +45 -4
  404. package/types/ngwr-sidebar.d.ts +17 -2
  405. package/types/ngwr-slider-testing.d.ts +329 -0
  406. package/types/ngwr-slider.d.ts +35 -1
  407. package/types/ngwr-sparkline.d.ts +12 -2
  408. package/types/ngwr-speed-dial.d.ts +17 -18
  409. package/types/ngwr-spinner.d.ts +8 -1
  410. package/types/ngwr-splitter.d.ts +24 -1
  411. package/types/ngwr-statistic.d.ts +12 -2
  412. package/types/ngwr-stepper-testing.d.ts +346 -0
  413. package/types/ngwr-switch-testing.d.ts +66 -0
  414. package/types/ngwr-switch.d.ts +7 -2
  415. package/types/ngwr-table-testing.d.ts +423 -0
  416. package/types/ngwr-table.d.ts +42 -0
  417. package/types/ngwr-tabs-testing.d.ts +470 -0
  418. package/types/ngwr-tabs.d.ts +9 -0
  419. package/types/ngwr-textarea-testing.d.ts +184 -0
  420. package/types/ngwr-textarea.d.ts +7 -2
  421. package/types/ngwr-toast-testing.d.ts +80 -0
  422. package/types/ngwr-tour.d.ts +27 -0
  423. package/types/ngwr-transfer-testing.d.ts +444 -0
  424. package/types/ngwr-transfer.d.ts +16 -1
  425. package/types/ngwr-tree-testing.d.ts +501 -0
  426. package/types/ngwr-tree.d.ts +33 -0
  427. package/types/ngwr-version.d.ts +1 -1
  428. package/types/ngwr-virtual-scroll.d.ts +13 -1
  429. package/typewriter/styles/_index.scss +1 -1
  430. package/typography/styles/_index.scss +1 -1
  431. package/window/styles/_index.scss +32 -9
@@ -0,0 +1,392 @@
1
+ import { ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';
2
+
3
+ /**
4
+ * @license
5
+ *
6
+ * Use of this source code is governed by an MIT-style license that can be
7
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
8
+ */
9
+ /**
10
+ * Test harness for one `<wr-radio>` — an option, not a control.
11
+ *
12
+ * The visible dot is a `<span>` the stylesheet paints; the state lives on a real
13
+ * `<input type="radio">` inside the label, and that is what this reads and clicks.
14
+ * A radio cannot exist alone — the component throws when it is constructed outside
15
+ * a `<wr-radio-group>` — so `WrRadioGroupHarness` is where the SELECTION lives and
16
+ * this answers questions about one option.
17
+ *
18
+ * There is no `aria-checked` here to prefer over the DOM, and that is right: a
19
+ * native radio carries its state in the `checked` IDL property, so the ARIA
20
+ * attribute would only be a second source of truth for a screen reader to
21
+ * disagree with. {@link isChecked} reads the property, which is the state.
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * const medium = await loader.getHarness(WrRadioHarness.with({ label: 'Medium' }));
26
+ * await medium.check();
27
+ * expect(await medium.isChecked()).toBe(true);
28
+ * ```
29
+ *
30
+ * @see https://ngwr.dev/guides/testing
31
+ */
32
+ class WrRadioHarness extends ComponentHarness {
33
+ static hostSelector = 'wr-radio';
34
+ /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */
35
+ static with(options = {}) {
36
+ return new HarnessPredicate(WrRadioHarness, options)
37
+ .addOption('label', options.label, (harness, label) => HarnessPredicate.stringMatches(harness.getLabel(), label))
38
+ .addOption('value', options.value, (harness, value) => HarnessPredicate.stringMatches(harness.getValue(), value))
39
+ .addOption('checked', options.checked, async (harness, checked) => (await harness.isChecked()) === checked)
40
+ .addOption('disabled', options.disabled, async (harness, disabled) => (await harness.isDisabled()) === disabled);
41
+ }
42
+ input = this.locatorFor('input.wr-radio__input');
43
+ label = this.locatorFor('label.wr-radio__label');
44
+ /** The projected label text, trimmed. An icon lives in the dot, so it is not part of it. */
45
+ async getLabel() {
46
+ return (await this.locatorFor('.wr-radio__text')()).text();
47
+ }
48
+ /**
49
+ * The option's value as the template WROTE it, or `null` when it was bound.
50
+ *
51
+ * The gap worth knowing about before a spec leans on this: `value` is `unknown`,
52
+ * and the component never puts it on the native input — the group holds the
53
+ * selection and a radio only says which one it is. So the only `value` in the
54
+ * DOM is the static attribute Angular leaves behind for a literal `value="sm"`;
55
+ * `[value]="size"` reaches the component without ever touching the page and
56
+ * reads `null` here whatever it holds, which for an object value it always will.
57
+ *
58
+ * Address options by their LABEL when it matters, and assert the picked value on
59
+ * the host's own model, which is the only place it exists.
60
+ */
61
+ async getValue() {
62
+ return (await this.host()).getAttribute('value');
63
+ }
64
+ /**
65
+ * The `name` the group stamps on this radio's native input.
66
+ *
67
+ * It is the whole of the group's keyboard behaviour: one shared name is what
68
+ * makes a browser treat the radios as a single tab stop, walk the arrow keys
69
+ * between them and announce "1 of 3". None of that is implemented in the
70
+ * component, so a name that stops being shared takes all of it away silently.
71
+ */
72
+ async getName() {
73
+ return (await this.input()).getProperty('name');
74
+ }
75
+ /**
76
+ * Whether this option is the group's answer.
77
+ *
78
+ * Read from the input's `checked` PROPERTY: `[checked]` is a property binding,
79
+ * so the attribute is never written and reading it would report `null` for a
80
+ * radio with a visible dot.
81
+ */
82
+ async isChecked() {
83
+ return (await this.input()).getProperty('checked');
84
+ }
85
+ /**
86
+ * Whether the option refuses selection — for either reason.
87
+ *
88
+ * The native input is disabled by this radio's own `disabled` OR by the group's,
89
+ * and from outside they are the same thing: the option cannot be picked.
90
+ */
91
+ async isDisabled() {
92
+ return (await this.input()).getProperty('disabled');
93
+ }
94
+ /**
95
+ * The control size, from the host modifier.
96
+ *
97
+ * `md` is the default and carries NO modifier class, so its absence is the
98
+ * answer rather than a missing one.
99
+ */
100
+ async getSize() {
101
+ const host = await this.host();
102
+ if (await host.hasClass('wr-radio--sm'))
103
+ return 'sm';
104
+ if (await host.hasClass('wr-radio--lg'))
105
+ return 'lg';
106
+ return 'md';
107
+ }
108
+ /** Whether the dot is filled by an icon instead of the default solid circle. */
109
+ async hasIcon() {
110
+ return (await this.host()).hasClass('wr-radio--has-icon');
111
+ }
112
+ /**
113
+ * Whether the `<label for>` really points at this radio's input.
114
+ *
115
+ * Not the option's only naming route, and worth being precise about: the input
116
+ * sits INSIDE the `<label>`, so the implicit association already names it and a
117
+ * `for` that misses does not leave the radio unnamed. What a stray `for` does
118
+ * take away is the pairing every consumer assumes — it hands label clicks, and
119
+ * anything that references the label, to whatever else on the page owns that id.
120
+ */
121
+ async isLabelBound() {
122
+ const forAttr = await (await this.label()).getAttribute('for');
123
+ return forAttr !== null && forAttr === (await (await this.input()).getProperty('id'));
124
+ }
125
+ /**
126
+ * Pick this option, the way a user does — a click on the native input.
127
+ *
128
+ * Nothing happens when it is already checked (a radio has no untick), and
129
+ * nothing happens when it is disabled, so assert the result rather than assume
130
+ * it — or reach for `WrRadioGroupHarness.select()`, which says which of the two
131
+ * it was.
132
+ *
133
+ * A click rather than a keypress, despite jsdom having no layout: the events are
134
+ * dispatched onto the input itself, so nothing is hit-tested and the zero-sized
135
+ * rect jsdom reports for every element cannot miss its target, and the
136
+ * `change` event it produces is exactly the one the component listens for. The
137
+ * arrow keys that would move a real user between options are the BROWSER's
138
+ * behaviour over a shared `name`, not the component's, and jsdom implements none
139
+ * of it — there is nothing here for a keyboard to drive.
140
+ */
141
+ async check() {
142
+ if (await this.isChecked())
143
+ return;
144
+ await (await this.input()).click();
145
+ }
146
+ /** Move keyboard focus onto the real control. */
147
+ async focus() {
148
+ return (await this.input()).focus();
149
+ }
150
+ /**
151
+ * Take focus off the radio — which is what makes the GROUP emit `touch`, since a
152
+ * blur from any child is what marks a bound field touched.
153
+ */
154
+ async blur() {
155
+ return (await this.input()).blur();
156
+ }
157
+ async isFocused() {
158
+ return (await this.input()).isFocused();
159
+ }
160
+ }
161
+
162
+ /**
163
+ * @license
164
+ *
165
+ * Use of this source code is governed by an MIT-style license that can be
166
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
167
+ */
168
+ /**
169
+ * Test harness for `<wr-radio-group>` — the control a `<wr-radio>` only means
170
+ * anything inside of, and the root of a two-part family with {@link WrRadioHarness}.
171
+ *
172
+ * Options are addressed by their LABEL rather than by their value, and there is
173
+ * deliberately no `getValue()` here. The group's value is a signal of `unknown`
174
+ * that the component never writes to the DOM: not to the group element, not to a
175
+ * radio's native input. The one thing on the page is whatever static attribute the
176
+ * template happened to leave behind, so a selection made through `[(value)]`, a
177
+ * `[formField]` or an object is not there at all, and a harness reporting it would
178
+ * be guessing. {@link getSelectedLabel} says what the page says, and a spec that
179
+ * needs the value itself asserts the host's own model — which is the assertion that
180
+ * would have caught the bug anyway.
181
+ *
182
+ * Arrow-key navigation is not this component's either: the radios share one `name`
183
+ * attribute and the browser does the rest, so jsdom — which implements none of it
184
+ * — leaves nothing for a keyboard to drive. {@link getName} is what a spec should
185
+ * pin instead, because losing the shared name is what actually takes arrow
186
+ * navigation away, and {@link getTabStopLabel} answers the other half.
187
+ *
188
+ * @example
189
+ * ```ts
190
+ * const size = await loader.getHarness(WrRadioGroupHarness.with({ name: 'size' }));
191
+ *
192
+ * expect(await size.getRadioLabels()).toEqual(['Small', 'Medium', 'Large']);
193
+ * await size.select({ label: 'Large' });
194
+ * expect(await size.getSelectedLabel()).toBe('Large');
195
+ * ```
196
+ *
197
+ * @see https://ngwr.dev/guides/testing
198
+ */
199
+ class WrRadioGroupHarness extends ComponentHarness {
200
+ static hostSelector = 'wr-radio-group';
201
+ /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */
202
+ static with(options = {}) {
203
+ return new HarnessPredicate(WrRadioGroupHarness, options)
204
+ .addOption('name', options.name, (harness, name) => HarnessPredicate.stringMatches(harness.getName(), name))
205
+ .addOption('disabled', options.disabled, async (harness, disabled) => (await harness.isDisabled()) === disabled);
206
+ }
207
+ /**
208
+ * The role the group announces — `radiogroup`, which is what tells a screen
209
+ * reader that the options belong to one question and how many of them there are.
210
+ */
211
+ async getRole() {
212
+ return (await this.host()).getAttribute('role');
213
+ }
214
+ /**
215
+ * The group's accessible name, resolved in the order a screen reader resolves it:
216
+ * the text of every element `aria-labelledby` points at, and `aria-label` only
217
+ * when that named nothing. `null` when the consumer wired neither.
218
+ *
219
+ * The order is not interchangeable — `aria-labelledby` WINS over `aria-label` in
220
+ * the accessible-name computation, so a group carrying both is announced by the
221
+ * heading it points at and reporting the `aria-label` would describe a name
222
+ * nobody hears.
223
+ *
224
+ * That `null` is a finding rather than a detail — a `radiogroup` with no name
225
+ * announces three answers and never the question. The component ships no label
226
+ * input on purpose (the question is the consumer's own heading), so this is the
227
+ * only way to check the wiring held.
228
+ */
229
+ async getAccessibleName() {
230
+ const host = await this.host();
231
+ const labelledBy = await host.getAttribute('aria-labelledby');
232
+ if (labelledBy !== null) {
233
+ // Resolved from the document root: `aria-labelledby` may point anywhere on the
234
+ // page, and the heading above a group is normally outside it.
235
+ const root = this.documentRootLocatorFactory();
236
+ const texts = [];
237
+ for (const id of labelledBy.split(/\s+/).filter(Boolean)) {
238
+ const target = await root.locatorForOptional(`#${id}`)();
239
+ if (target)
240
+ texts.push(await target.text());
241
+ }
242
+ // A reference that resolves to nothing names nothing, and the computation
243
+ // falls through to `aria-label` exactly as it does in a browser.
244
+ if (texts.length)
245
+ return texts.join(' ');
246
+ }
247
+ return host.getAttribute('aria-label');
248
+ }
249
+ /**
250
+ * The `name` every radio in the group shares.
251
+ *
252
+ * Read off the radios because they are the only place it is RELIABLY written: the
253
+ * group's `name` input reaches the page as an attribute on each native input, and
254
+ * a bound `[name]="…"` never lands on the group element at all. A literal
255
+ * `name="size"` does survive on the group element — Angular leaves a static
256
+ * attribute alone — which is exactly the trap: reading it there works for the
257
+ * literal form and quietly returns nothing for the bound one.
258
+ */
259
+ async getName() {
260
+ const [first] = await this.radiosOrThrow();
261
+ return first.getName();
262
+ }
263
+ /**
264
+ * Whether the group refuses every option.
265
+ *
266
+ * Answered from the radios, and it could not be otherwise: a bound `[disabled]`
267
+ * on the group reaches the page only by disabling each native input, so a group
268
+ * disabled as a whole and a group whose every option is individually disabled
269
+ * are the same page. They are also the same thing to the person using it, which
270
+ * is the question a harness should be answering.
271
+ */
272
+ async isDisabled() {
273
+ for (const radio of await this.radiosOrThrow()) {
274
+ if (!(await radio.isDisabled()))
275
+ return false;
276
+ }
277
+ return true;
278
+ }
279
+ /** The group's own options, in DOM order. A sibling group's radios are not here. */
280
+ async getRadios(filters = {}) {
281
+ return this.locatorForAll(WrRadioHarness.with(filters))();
282
+ }
283
+ /** The label of every option, in DOM order. */
284
+ async getRadioLabels() {
285
+ const radios = await this.getRadios();
286
+ return Promise.all(radios.map(radio => radio.getLabel()));
287
+ }
288
+ /** The checked option, or `null` while the group is unanswered. */
289
+ async getSelectedRadio() {
290
+ const [checked] = await this.getRadios({ checked: true });
291
+ return checked ?? null;
292
+ }
293
+ /**
294
+ * The label of the checked option, or `null` while the group is unanswered.
295
+ *
296
+ * Also `null` for a value that matches no radio — the group holds it, nothing is
297
+ * checked, and the page shows an unanswered question.
298
+ */
299
+ async getSelectedLabel() {
300
+ const selected = await this.getSelectedRadio();
301
+ return selected ? selected.getLabel() : null;
302
+ }
303
+ /**
304
+ * Pick the first option matching the filters — this is how the group's value
305
+ * changes.
306
+ *
307
+ * Throws when nothing matches, naming the options that do exist, and throws
308
+ * again when the option is still unchecked afterwards. That second failure has
309
+ * exactly two causes and reports both, because a click that quietly did nothing
310
+ * surfaces as an unrelated assertion three lines later.
311
+ */
312
+ async select(filters) {
313
+ const [radio] = await this.getRadios(filters);
314
+ if (!radio) {
315
+ throw new Error(`WrRadioGroupHarness.select(): no radio matched ${JSON.stringify(filters)}. This group offers: ` +
316
+ `${(await this.getRadioLabels()).join(', ')}.`);
317
+ }
318
+ await radio.check();
319
+ if (!(await radio.isChecked())) {
320
+ throw new Error(`WrRadioGroupHarness.select(): "${await radio.getLabel()}" is still unchecked after being clicked — ` +
321
+ 'either that option carries `disabled` or the whole group does.');
322
+ }
323
+ }
324
+ /**
325
+ * The label of the option a Tab press would land on, or `null` when every option
326
+ * is disabled and the group is skipped over entirely.
327
+ *
328
+ * A radio group is ONE tab stop, and which radio it is is written down nowhere:
329
+ * the component authors no roving `tabindex`, because the browser already
330
+ * applies the native rule to a shared `name` — the checked radio, or the first
331
+ * enabled one while nothing is checked. So this is DERIVED from the rendered
332
+ * state rather than read off an attribute, there being no attribute to read.
333
+ *
334
+ * Worth asking precisely because those two answers are different radios exactly
335
+ * when a form opens unanswered, which is the state most specs start in.
336
+ */
337
+ async getTabStopLabel() {
338
+ const stop = await this.tabStop();
339
+ return stop ? stop.getLabel() : null;
340
+ }
341
+ /** Put focus where a Tab press would put it. Throws when the group has no tab stop. */
342
+ async focusTabStop() {
343
+ const stop = await this.tabStop();
344
+ if (!stop) {
345
+ throw new Error('WrRadioGroupHarness.focusTabStop(): every option in this group is disabled, so the group is not a ' +
346
+ 'tab stop at all — Tab skips it rather than entering it.');
347
+ }
348
+ await stop.focus();
349
+ }
350
+ /**
351
+ * The label of the option that currently holds focus, or `null` when focus is
352
+ * elsewhere. The counterpart to {@link focusTabStop}: in a real browser the
353
+ * arrow keys move this, and moving it is also what picks a new answer.
354
+ */
355
+ async getFocusedLabel() {
356
+ for (const radio of await this.getRadios()) {
357
+ if (await radio.isFocused())
358
+ return radio.getLabel();
359
+ }
360
+ return null;
361
+ }
362
+ /** The radio Tab would enter on, applying the browser's rule to the rendered state. */
363
+ async tabStop() {
364
+ const enabled = [];
365
+ for (const radio of await this.getRadios()) {
366
+ if (!(await radio.isDisabled()))
367
+ enabled.push(radio);
368
+ }
369
+ for (const radio of enabled) {
370
+ if (await radio.isChecked())
371
+ return radio;
372
+ }
373
+ return enabled[0] ?? null;
374
+ }
375
+ /** The options, or a failure saying why an empty group has nothing to report. */
376
+ async radiosOrThrow() {
377
+ const radios = await this.getRadios();
378
+ if (!radios.length) {
379
+ throw new Error('WrRadioGroupHarness: this group has no <wr-radio> children, and every group-level fact here is read ' +
380
+ 'off them — the shared name and the disabled state reach the DOM through the radios, and a bound ' +
381
+ '[name] / [disabled] leaves nothing on the group element to read instead.');
382
+ }
383
+ return radios;
384
+ }
385
+ }
386
+
387
+ /**
388
+ * Generated bundle index. Do not edit.
389
+ */
390
+
391
+ export { WrRadioGroupHarness, WrRadioHarness };
392
+ //# sourceMappingURL=ngwr-radio-testing.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ngwr-radio-testing.mjs","sources":["../../../projects/lib/radio/testing/wr-radio-harness.ts","../../../projects/lib/radio/testing/wr-radio-group-harness.ts","../../../projects/lib/radio/testing/ngwr-radio-testing.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';\n\nimport type { WrRadioSize } from 'ngwr/radio';\n\nimport type { WrRadioHarnessFilters } from './interfaces';\n\n/**\n * Test harness for one `<wr-radio>` — an option, not a control.\n *\n * The visible dot is a `<span>` the stylesheet paints; the state lives on a real\n * `<input type=\"radio\">` inside the label, and that is what this reads and clicks.\n * A radio cannot exist alone — the component throws when it is constructed outside\n * a `<wr-radio-group>` — so `WrRadioGroupHarness` is where the SELECTION lives and\n * this answers questions about one option.\n *\n * There is no `aria-checked` here to prefer over the DOM, and that is right: a\n * native radio carries its state in the `checked` IDL property, so the ARIA\n * attribute would only be a second source of truth for a screen reader to\n * disagree with. {@link isChecked} reads the property, which is the state.\n *\n * @example\n * ```ts\n * const medium = await loader.getHarness(WrRadioHarness.with({ label: 'Medium' }));\n * await medium.check();\n * expect(await medium.isChecked()).toBe(true);\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrRadioHarness extends ComponentHarness {\n static hostSelector = 'wr-radio';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrRadioHarnessFilters = {}): HarnessPredicate<WrRadioHarness> {\n return new HarnessPredicate(WrRadioHarness, options)\n .addOption('label', options.label, (harness, label) => HarnessPredicate.stringMatches(harness.getLabel(), label))\n .addOption('value', options.value, (harness, value) => HarnessPredicate.stringMatches(harness.getValue(), value))\n .addOption('checked', options.checked, async (harness, checked) => (await harness.isChecked()) === checked)\n .addOption('disabled', options.disabled, async (harness, disabled) => (await harness.isDisabled()) === disabled);\n }\n\n private readonly input = this.locatorFor('input.wr-radio__input');\n private readonly label = this.locatorFor('label.wr-radio__label');\n\n /** The projected label text, trimmed. An icon lives in the dot, so it is not part of it. */\n async getLabel(): Promise<string> {\n return (await this.locatorFor('.wr-radio__text')()).text();\n }\n\n /**\n * The option's value as the template WROTE it, or `null` when it was bound.\n *\n * The gap worth knowing about before a spec leans on this: `value` is `unknown`,\n * and the component never puts it on the native input — the group holds the\n * selection and a radio only says which one it is. So the only `value` in the\n * DOM is the static attribute Angular leaves behind for a literal `value=\"sm\"`;\n * `[value]=\"size\"` reaches the component without ever touching the page and\n * reads `null` here whatever it holds, which for an object value it always will.\n *\n * Address options by their LABEL when it matters, and assert the picked value on\n * the host's own model, which is the only place it exists.\n */\n async getValue(): Promise<string | null> {\n return (await this.host()).getAttribute('value');\n }\n\n /**\n * The `name` the group stamps on this radio's native input.\n *\n * It is the whole of the group's keyboard behaviour: one shared name is what\n * makes a browser treat the radios as a single tab stop, walk the arrow keys\n * between them and announce \"1 of 3\". None of that is implemented in the\n * component, so a name that stops being shared takes all of it away silently.\n */\n async getName(): Promise<string> {\n return (await this.input()).getProperty<string>('name');\n }\n\n /**\n * Whether this option is the group's answer.\n *\n * Read from the input's `checked` PROPERTY: `[checked]` is a property binding,\n * so the attribute is never written and reading it would report `null` for a\n * radio with a visible dot.\n */\n async isChecked(): Promise<boolean> {\n return (await this.input()).getProperty<boolean>('checked');\n }\n\n /**\n * Whether the option refuses selection — for either reason.\n *\n * The native input is disabled by this radio's own `disabled` OR by the group's,\n * and from outside they are the same thing: the option cannot be picked.\n */\n async isDisabled(): Promise<boolean> {\n return (await this.input()).getProperty<boolean>('disabled');\n }\n\n /**\n * The control size, from the host modifier.\n *\n * `md` is the default and carries NO modifier class, so its absence is the\n * answer rather than a missing one.\n */\n async getSize(): Promise<WrRadioSize> {\n const host = await this.host();\n if (await host.hasClass('wr-radio--sm')) return 'sm';\n if (await host.hasClass('wr-radio--lg')) return 'lg';\n return 'md';\n }\n\n /** Whether the dot is filled by an icon instead of the default solid circle. */\n async hasIcon(): Promise<boolean> {\n return (await this.host()).hasClass('wr-radio--has-icon');\n }\n\n /**\n * Whether the `<label for>` really points at this radio's input.\n *\n * Not the option's only naming route, and worth being precise about: the input\n * sits INSIDE the `<label>`, so the implicit association already names it and a\n * `for` that misses does not leave the radio unnamed. What a stray `for` does\n * take away is the pairing every consumer assumes — it hands label clicks, and\n * anything that references the label, to whatever else on the page owns that id.\n */\n async isLabelBound(): Promise<boolean> {\n const forAttr = await (await this.label()).getAttribute('for');\n return forAttr !== null && forAttr === (await (await this.input()).getProperty<string>('id'));\n }\n\n /**\n * Pick this option, the way a user does — a click on the native input.\n *\n * Nothing happens when it is already checked (a radio has no untick), and\n * nothing happens when it is disabled, so assert the result rather than assume\n * it — or reach for `WrRadioGroupHarness.select()`, which says which of the two\n * it was.\n *\n * A click rather than a keypress, despite jsdom having no layout: the events are\n * dispatched onto the input itself, so nothing is hit-tested and the zero-sized\n * rect jsdom reports for every element cannot miss its target, and the\n * `change` event it produces is exactly the one the component listens for. The\n * arrow keys that would move a real user between options are the BROWSER's\n * behaviour over a shared `name`, not the component's, and jsdom implements none\n * of it — there is nothing here for a keyboard to drive.\n */\n async check(): Promise<void> {\n if (await this.isChecked()) return;\n await (await this.input()).click();\n }\n\n /** Move keyboard focus onto the real control. */\n async focus(): Promise<void> {\n return (await this.input()).focus();\n }\n\n /**\n * Take focus off the radio — which is what makes the GROUP emit `touch`, since a\n * blur from any child is what marks a bound field touched.\n */\n async blur(): Promise<void> {\n return (await this.input()).blur();\n }\n\n async isFocused(): Promise<boolean> {\n return (await this.input()).isFocused();\n }\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';\n\nimport type { WrRadioGroupHarnessFilters, WrRadioHarnessFilters } from './interfaces';\nimport { WrRadioHarness } from './wr-radio-harness';\n\n/**\n * Test harness for `<wr-radio-group>` — the control a `<wr-radio>` only means\n * anything inside of, and the root of a two-part family with {@link WrRadioHarness}.\n *\n * Options are addressed by their LABEL rather than by their value, and there is\n * deliberately no `getValue()` here. The group's value is a signal of `unknown`\n * that the component never writes to the DOM: not to the group element, not to a\n * radio's native input. The one thing on the page is whatever static attribute the\n * template happened to leave behind, so a selection made through `[(value)]`, a\n * `[formField]` or an object is not there at all, and a harness reporting it would\n * be guessing. {@link getSelectedLabel} says what the page says, and a spec that\n * needs the value itself asserts the host's own model — which is the assertion that\n * would have caught the bug anyway.\n *\n * Arrow-key navigation is not this component's either: the radios share one `name`\n * attribute and the browser does the rest, so jsdom — which implements none of it\n * — leaves nothing for a keyboard to drive. {@link getName} is what a spec should\n * pin instead, because losing the shared name is what actually takes arrow\n * navigation away, and {@link getTabStopLabel} answers the other half.\n *\n * @example\n * ```ts\n * const size = await loader.getHarness(WrRadioGroupHarness.with({ name: 'size' }));\n *\n * expect(await size.getRadioLabels()).toEqual(['Small', 'Medium', 'Large']);\n * await size.select({ label: 'Large' });\n * expect(await size.getSelectedLabel()).toBe('Large');\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrRadioGroupHarness extends ComponentHarness {\n static hostSelector = 'wr-radio-group';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrRadioGroupHarnessFilters = {}): HarnessPredicate<WrRadioGroupHarness> {\n return new HarnessPredicate(WrRadioGroupHarness, options)\n .addOption('name', options.name, (harness, name) => HarnessPredicate.stringMatches(harness.getName(), name))\n .addOption('disabled', options.disabled, async (harness, disabled) => (await harness.isDisabled()) === disabled);\n }\n\n /**\n * The role the group announces — `radiogroup`, which is what tells a screen\n * reader that the options belong to one question and how many of them there are.\n */\n async getRole(): Promise<string | null> {\n return (await this.host()).getAttribute('role');\n }\n\n /**\n * The group's accessible name, resolved in the order a screen reader resolves it:\n * the text of every element `aria-labelledby` points at, and `aria-label` only\n * when that named nothing. `null` when the consumer wired neither.\n *\n * The order is not interchangeable — `aria-labelledby` WINS over `aria-label` in\n * the accessible-name computation, so a group carrying both is announced by the\n * heading it points at and reporting the `aria-label` would describe a name\n * nobody hears.\n *\n * That `null` is a finding rather than a detail — a `radiogroup` with no name\n * announces three answers and never the question. The component ships no label\n * input on purpose (the question is the consumer's own heading), so this is the\n * only way to check the wiring held.\n */\n async getAccessibleName(): Promise<string | null> {\n const host = await this.host();\n\n const labelledBy = await host.getAttribute('aria-labelledby');\n if (labelledBy !== null) {\n // Resolved from the document root: `aria-labelledby` may point anywhere on the\n // page, and the heading above a group is normally outside it.\n const root = this.documentRootLocatorFactory();\n const texts: string[] = [];\n for (const id of labelledBy.split(/\\s+/).filter(Boolean)) {\n const target = await root.locatorForOptional(`#${id}`)();\n if (target) texts.push(await target.text());\n }\n\n // A reference that resolves to nothing names nothing, and the computation\n // falls through to `aria-label` exactly as it does in a browser.\n if (texts.length) return texts.join(' ');\n }\n\n return host.getAttribute('aria-label');\n }\n\n /**\n * The `name` every radio in the group shares.\n *\n * Read off the radios because they are the only place it is RELIABLY written: the\n * group's `name` input reaches the page as an attribute on each native input, and\n * a bound `[name]=\"…\"` never lands on the group element at all. A literal\n * `name=\"size\"` does survive on the group element — Angular leaves a static\n * attribute alone — which is exactly the trap: reading it there works for the\n * literal form and quietly returns nothing for the bound one.\n */\n async getName(): Promise<string> {\n const [first] = await this.radiosOrThrow();\n return first.getName();\n }\n\n /**\n * Whether the group refuses every option.\n *\n * Answered from the radios, and it could not be otherwise: a bound `[disabled]`\n * on the group reaches the page only by disabling each native input, so a group\n * disabled as a whole and a group whose every option is individually disabled\n * are the same page. They are also the same thing to the person using it, which\n * is the question a harness should be answering.\n */\n async isDisabled(): Promise<boolean> {\n for (const radio of await this.radiosOrThrow()) {\n if (!(await radio.isDisabled())) return false;\n }\n return true;\n }\n\n /** The group's own options, in DOM order. A sibling group's radios are not here. */\n async getRadios(filters: WrRadioHarnessFilters = {}): Promise<WrRadioHarness[]> {\n return this.locatorForAll(WrRadioHarness.with(filters))();\n }\n\n /** The label of every option, in DOM order. */\n async getRadioLabels(): Promise<string[]> {\n const radios = await this.getRadios();\n return Promise.all(radios.map(radio => radio.getLabel()));\n }\n\n /** The checked option, or `null` while the group is unanswered. */\n async getSelectedRadio(): Promise<WrRadioHarness | null> {\n const [checked] = await this.getRadios({ checked: true });\n return checked ?? null;\n }\n\n /**\n * The label of the checked option, or `null` while the group is unanswered.\n *\n * Also `null` for a value that matches no radio — the group holds it, nothing is\n * checked, and the page shows an unanswered question.\n */\n async getSelectedLabel(): Promise<string | null> {\n const selected = await this.getSelectedRadio();\n return selected ? selected.getLabel() : null;\n }\n\n /**\n * Pick the first option matching the filters — this is how the group's value\n * changes.\n *\n * Throws when nothing matches, naming the options that do exist, and throws\n * again when the option is still unchecked afterwards. That second failure has\n * exactly two causes and reports both, because a click that quietly did nothing\n * surfaces as an unrelated assertion three lines later.\n */\n async select(filters: WrRadioHarnessFilters): Promise<void> {\n const [radio] = await this.getRadios(filters);\n if (!radio) {\n throw new Error(\n `WrRadioGroupHarness.select(): no radio matched ${JSON.stringify(filters)}. This group offers: ` +\n `${(await this.getRadioLabels()).join(', ')}.`\n );\n }\n\n await radio.check();\n\n if (!(await radio.isChecked())) {\n throw new Error(\n `WrRadioGroupHarness.select(): \"${await radio.getLabel()}\" is still unchecked after being clicked — ` +\n 'either that option carries `disabled` or the whole group does.'\n );\n }\n }\n\n /**\n * The label of the option a Tab press would land on, or `null` when every option\n * is disabled and the group is skipped over entirely.\n *\n * A radio group is ONE tab stop, and which radio it is is written down nowhere:\n * the component authors no roving `tabindex`, because the browser already\n * applies the native rule to a shared `name` — the checked radio, or the first\n * enabled one while nothing is checked. So this is DERIVED from the rendered\n * state rather than read off an attribute, there being no attribute to read.\n *\n * Worth asking precisely because those two answers are different radios exactly\n * when a form opens unanswered, which is the state most specs start in.\n */\n async getTabStopLabel(): Promise<string | null> {\n const stop = await this.tabStop();\n return stop ? stop.getLabel() : null;\n }\n\n /** Put focus where a Tab press would put it. Throws when the group has no tab stop. */\n async focusTabStop(): Promise<void> {\n const stop = await this.tabStop();\n if (!stop) {\n throw new Error(\n 'WrRadioGroupHarness.focusTabStop(): every option in this group is disabled, so the group is not a ' +\n 'tab stop at all — Tab skips it rather than entering it.'\n );\n }\n await stop.focus();\n }\n\n /**\n * The label of the option that currently holds focus, or `null` when focus is\n * elsewhere. The counterpart to {@link focusTabStop}: in a real browser the\n * arrow keys move this, and moving it is also what picks a new answer.\n */\n async getFocusedLabel(): Promise<string | null> {\n for (const radio of await this.getRadios()) {\n if (await radio.isFocused()) return radio.getLabel();\n }\n return null;\n }\n\n /** The radio Tab would enter on, applying the browser's rule to the rendered state. */\n private async tabStop(): Promise<WrRadioHarness | null> {\n const enabled: WrRadioHarness[] = [];\n for (const radio of await this.getRadios()) {\n if (!(await radio.isDisabled())) enabled.push(radio);\n }\n\n for (const radio of enabled) {\n if (await radio.isChecked()) return radio;\n }\n return enabled[0] ?? null;\n }\n\n /** The options, or a failure saying why an empty group has nothing to report. */\n private async radiosOrThrow(): Promise<WrRadioHarness[]> {\n const radios = await this.getRadios();\n if (!radios.length) {\n throw new Error(\n 'WrRadioGroupHarness: this group has no <wr-radio> children, and every group-level fact here is read ' +\n 'off them — the shared name and the disabled state reach the DOM through the radios, and a bound ' +\n '[name] / [disabled] leaves nothing on the group element to read instead.'\n );\n }\n return radios;\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { coerceBooleanProperty } from '@angular/cdk/coercion';
2
2
  import * as i0 from '@angular/core';
3
3
  import { InjectionToken, input, inject, computed, ViewEncapsulation, Component, model, output, forwardRef } from '@angular/core';
4
+ import { useConfigValue } from 'ngwr/config';
4
5
  import { WrIcon } from 'ngwr/icon';
5
6
  import { randomId } from 'ngwr/utils';
6
7
 
@@ -38,9 +39,15 @@ class WrRadio {
38
39
  */
39
40
  icon = input(null, /* @ts-ignore */
40
41
  ...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
41
- /** Control size — shares the `--wr-control-*` contract. @default 'md' */
42
- size = input('md', /* @ts-ignore */
42
+ /**
43
+ * Control size — shares the `--wr-control-*` contract. Set per option (the
44
+ * group has no `size`); unset falls back to the `radio.size` app default from
45
+ * `provideWrConfig()`. @default 'md'
46
+ */
47
+ size = input(null, /* @ts-ignore */
43
48
  ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
49
+ /** `size`, then the app config, then `md`. @internal */
50
+ resolvedSize = useConfigValue(this.size, c => c.radio?.size, 'md');
44
51
  /**
45
52
  * Disable just this option. The group can also be disabled as a whole via
46
53
  * `<wr-radio-group disabled>`; either source disables this radio.
@@ -63,7 +70,7 @@ class WrRadio {
63
70
  ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
64
71
  classes = computed(() => {
65
72
  const parts = ['wr-radio'];
66
- const size = this.size();
73
+ const size = this.resolvedSize();
67
74
  if (size !== 'md')
68
75
  parts.push(`wr-radio--${size}`);
69
76
  if (this.checked())
@@ -1 +1 @@
1
- {"version":3,"file":"ngwr-radio.mjs","sources":["../../../projects/lib/radio/tokens/radio-group.token.ts","../../../projects/lib/radio/radio.ts","../../../projects/lib/radio/radio.html","../../../projects/lib/radio/radio-group.ts","../../../projects/lib/radio/ngwr-radio.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { InjectionToken, type Signal } from '@angular/core';\n\n/**\n * Contract a radio uses to talk to its parent `<wr-radio-group>`.\n *\n * @internal\n */\nexport interface WrRadioGroupContext {\n /** Shared `name` attribute applied to every native input in the group. */\n readonly name: Signal<string>;\n /** Currently selected value. */\n readonly value: Signal<unknown>;\n /** Whether the entire group is disabled. */\n readonly isDisabled: Signal<boolean>;\n /** Select the given value. */\n select(value: unknown): void;\n /**\n * Mark the group as touched (called on blur from any child). Named\n * `markTouched` rather than `touch` so it doesn't clash with the\n * `FormUiControl.touch` output the group now exposes for signal forms.\n */\n markTouched(): void;\n}\n\n/**\n * Token a `<wr-radio>` injects to participate in its parent `<wr-radio-group>`\n * — reads the selected value, shares the `name` attribute, and signals\n * selection / blur back up.\n *\n * @internal\n */\nexport const WR_RADIO_GROUP = new InjectionToken<WrRadioGroupContext>('WR_RADIO_GROUP');\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { Component, ViewEncapsulation, computed, inject, input } from '@angular/core';\n\nimport { WrIcon, type WrIconName } from 'ngwr/icon';\nimport { randomId } from 'ngwr/utils';\n\nimport { WR_RADIO_GROUP } from './tokens';\n\n/**\n * Single-choice option. Must be a child of `<wr-radio-group>`.\n *\n * @example\n * ```html\n * <wr-radio-group [(ngModel)]=\"size\">\n * <wr-radio value=\"sm\">Small</wr-radio>\n * <wr-radio value=\"md\">Medium</wr-radio>\n * <wr-radio value=\"lg\">Large</wr-radio>\n * </wr-radio-group>\n * ```\n *\n * @see https://ngwr.dev/reference/components/radio\n */\nexport type WrRadioSize = 'sm' | 'md' | 'lg';\n\n@Component({\n selector: 'wr-radio',\n templateUrl: './radio.html',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n imports: [WrIcon],\n})\nexport class WrRadio {\n /** Stable id used to associate the native input with its label. */\n readonly id = input<string>(randomId('wr-radio'));\n\n /** Value selected when this radio is checked. */\n readonly value = input.required<unknown>();\n\n /**\n * Optional icon name rendered inside the dot when checked, in place of the\n * default solid circle. Use any registered NGWR icon.\n */\n readonly icon = input<WrIconName | null>(null);\n\n /** Control size — shares the `--wr-control-*` contract. @default 'md' */\n readonly size = input<WrRadioSize>('md');\n\n /**\n * Disable just this option. The group can also be disabled as a whole via\n * `<wr-radio-group disabled>`; either source disables this radio.\n *\n * @default false\n */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n private readonly group = inject(WR_RADIO_GROUP, { optional: true });\n\n constructor() {\n if (!this.group) {\n throw new Error('[NGWR] <wr-radio> must be used inside <wr-radio-group>.');\n }\n }\n\n protected readonly name = computed(() => this.group?.name() ?? '');\n protected readonly checked = computed(() => this.group?.value() === this.value());\n /** Effective disabled — this option's own `disabled` or the group's. */\n protected readonly isDisabled = computed(() => this.disabled() || (this.group?.isDisabled() ?? false));\n\n protected readonly classes = computed(() => {\n const parts = ['wr-radio'];\n const size = this.size();\n if (size !== 'md') parts.push(`wr-radio--${size}`);\n if (this.checked()) parts.push('wr-radio--checked');\n if (this.isDisabled()) parts.push('wr-radio--disabled');\n if (this.icon()) parts.push('wr-radio--has-icon');\n return parts.join(' ');\n });\n\n protected onSelect(): void {\n if (this.isDisabled()) return;\n this.group?.select(this.value());\n }\n\n protected onBlur(): void {\n this.group?.markTouched();\n }\n}\n","<label class=\"wr-radio__label\" [for]=\"id()\">\n <input\n class=\"wr-radio__input\"\n type=\"radio\"\n [id]=\"id()\"\n [name]=\"name()\"\n [checked]=\"checked()\"\n [disabled]=\"isDisabled()\"\n (change)=\"onSelect()\"\n (blur)=\"onBlur()\"\n />\n\n <span class=\"wr-radio__dot\" aria-hidden=\"true\">\n @if (icon(); as iconName) {\n <wr-icon class=\"wr-radio__icon\" [name]=\"iconName\" />\n }\n </span>\n\n <span class=\"wr-radio__text\">\n <ng-content />\n </span>\n</label>\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { Component, ViewEncapsulation, computed, forwardRef, input, model, output } from '@angular/core';\nimport type { FormValueControl } from '@angular/forms/signals';\n\nimport { randomId } from 'ngwr/utils';\n\nimport { WR_RADIO_GROUP, type WrRadioGroupContext } from './tokens';\n\n/**\n * Hosts a group of `<wr-radio>` children as a single-value selection.\n *\n * A signal-forms native control: it implements `FormValueControl<unknown>`, so\n * `[formField]` binds to its `value` model — the currently selected radio's\n * `value`. `[(value)]` works standalone. Classic `[(ngModel)]` / reactive forms\n * keep working through Angular's bridge.\n *\n * @example\n * ```html\n * <wr-radio-group [formField]=\"form.size\">\n * <wr-radio value=\"sm\">Small</wr-radio>\n * <wr-radio value=\"md\">Medium</wr-radio>\n * <wr-radio value=\"lg\">Large</wr-radio>\n * </wr-radio-group>\n * ```\n *\n * @see https://ngwr.dev/reference/components/radio\n */\n@Component({\n selector: 'wr-radio-group',\n template: '<ng-content />',\n encapsulation: ViewEncapsulation.None,\n host: { class: 'wr-radio-group', role: 'radiogroup' },\n providers: [\n {\n provide: WR_RADIO_GROUP,\n // eslint-disable-next-line @angular-eslint/no-forward-ref\n useExisting: forwardRef(() => WrRadioGroup),\n },\n ],\n})\nexport class WrRadioGroup implements FormValueControl<unknown>, WrRadioGroupContext {\n /**\n * Shared `name` attribute. Defaults to a random id so multiple groups\n * on the same page don't collide. (Also the `FormUiControl.name` slot.)\n */\n readonly name = input<string>(randomId('wr-radio-group'));\n\n /**\n * Disable the whole group. Bound automatically from the field's disabled\n * state when used with `[formField]`.\n *\n * @default false\n */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n /** The selected radio's value. Bound by `[formField]`, or two-way via `[(value)]`. */\n readonly value = model<unknown>(null);\n\n /** Emitted on blur from any child so a bound field can mark itself touched. */\n readonly touch = output<void>();\n\n /** Effective disabled state (WrRadioGroupContext). */\n readonly isDisabled = computed(() => this.disabled());\n\n // WrRadioGroupContext\n\n select(value: unknown): void {\n if (this.isDisabled()) return;\n this.value.set(value);\n }\n\n markTouched(): void {\n this.touch.emit();\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ngwr-radio.mjs","sources":["../../../projects/lib/radio/tokens/radio-group.token.ts","../../../projects/lib/radio/radio.ts","../../../projects/lib/radio/radio.html","../../../projects/lib/radio/radio-group.ts","../../../projects/lib/radio/ngwr-radio.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { InjectionToken, type Signal } from '@angular/core';\n\n/**\n * Contract a radio uses to talk to its parent `<wr-radio-group>`.\n *\n * @internal\n */\nexport interface WrRadioGroupContext {\n /** Shared `name` attribute applied to every native input in the group. */\n readonly name: Signal<string>;\n /** Currently selected value. */\n readonly value: Signal<unknown>;\n /** Whether the entire group is disabled. */\n readonly isDisabled: Signal<boolean>;\n /** Select the given value. */\n select(value: unknown): void;\n /**\n * Mark the group as touched (called on blur from any child). Named\n * `markTouched` rather than `touch` so it doesn't clash with the\n * `FormUiControl.touch` output the group now exposes for signal forms.\n */\n markTouched(): void;\n}\n\n/**\n * Token a `<wr-radio>` injects to participate in its parent `<wr-radio-group>`\n * — reads the selected value, shares the `name` attribute, and signals\n * selection / blur back up.\n *\n * @internal\n */\nexport const WR_RADIO_GROUP = new InjectionToken<WrRadioGroupContext>('WR_RADIO_GROUP');\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { Component, ViewEncapsulation, computed, inject, input } from '@angular/core';\n\nimport { useConfigValue } from 'ngwr/config';\nimport { WrIcon, type WrIconName } from 'ngwr/icon';\nimport { randomId } from 'ngwr/utils';\n\nimport { WR_RADIO_GROUP } from './tokens';\n\n/**\n * Single-choice option. Must be a child of `<wr-radio-group>`.\n *\n * @example\n * ```html\n * <wr-radio-group [(ngModel)]=\"size\">\n * <wr-radio value=\"sm\">Small</wr-radio>\n * <wr-radio value=\"md\">Medium</wr-radio>\n * <wr-radio value=\"lg\">Large</wr-radio>\n * </wr-radio-group>\n * ```\n *\n * @see https://ngwr.dev/reference/components/radio\n */\nexport type WrRadioSize = 'sm' | 'md' | 'lg';\n\n@Component({\n selector: 'wr-radio',\n templateUrl: './radio.html',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n imports: [WrIcon],\n})\nexport class WrRadio {\n /** Stable id used to associate the native input with its label. */\n readonly id = input<string>(randomId('wr-radio'));\n\n /** Value selected when this radio is checked. */\n readonly value = input.required<unknown>();\n\n /**\n * Optional icon name rendered inside the dot when checked, in place of the\n * default solid circle. Use any registered NGWR icon.\n */\n readonly icon = input<WrIconName | null>(null);\n\n /**\n * Control size — shares the `--wr-control-*` contract. Set per option (the\n * group has no `size`); unset falls back to the `radio.size` app default from\n * `provideWrConfig()`. @default 'md'\n */\n readonly size = input<WrRadioSize | null>(null);\n\n /** `size`, then the app config, then `md`. @internal */\n protected readonly resolvedSize = useConfigValue(this.size, c => c.radio?.size, 'md');\n\n /**\n * Disable just this option. The group can also be disabled as a whole via\n * `<wr-radio-group disabled>`; either source disables this radio.\n *\n * @default false\n */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n private readonly group = inject(WR_RADIO_GROUP, { optional: true });\n\n constructor() {\n if (!this.group) {\n throw new Error('[NGWR] <wr-radio> must be used inside <wr-radio-group>.');\n }\n }\n\n protected readonly name = computed(() => this.group?.name() ?? '');\n protected readonly checked = computed(() => this.group?.value() === this.value());\n /** Effective disabled — this option's own `disabled` or the group's. */\n protected readonly isDisabled = computed(() => this.disabled() || (this.group?.isDisabled() ?? false));\n\n protected readonly classes = computed(() => {\n const parts = ['wr-radio'];\n const size = this.resolvedSize();\n if (size !== 'md') parts.push(`wr-radio--${size}`);\n if (this.checked()) parts.push('wr-radio--checked');\n if (this.isDisabled()) parts.push('wr-radio--disabled');\n if (this.icon()) parts.push('wr-radio--has-icon');\n return parts.join(' ');\n });\n\n protected onSelect(): void {\n if (this.isDisabled()) return;\n this.group?.select(this.value());\n }\n\n protected onBlur(): void {\n this.group?.markTouched();\n }\n}\n","<label class=\"wr-radio__label\" [for]=\"id()\">\n <input\n class=\"wr-radio__input\"\n type=\"radio\"\n [id]=\"id()\"\n [name]=\"name()\"\n [checked]=\"checked()\"\n [disabled]=\"isDisabled()\"\n (change)=\"onSelect()\"\n (blur)=\"onBlur()\"\n />\n\n <span class=\"wr-radio__dot\" aria-hidden=\"true\">\n @if (icon(); as iconName) {\n <wr-icon class=\"wr-radio__icon\" [name]=\"iconName\" />\n }\n </span>\n\n <span class=\"wr-radio__text\">\n <ng-content />\n </span>\n</label>\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { Component, ViewEncapsulation, computed, forwardRef, input, model, output } from '@angular/core';\nimport type { FormValueControl } from '@angular/forms/signals';\n\nimport { randomId } from 'ngwr/utils';\n\nimport { WR_RADIO_GROUP, type WrRadioGroupContext } from './tokens';\n\n/**\n * Hosts a group of `<wr-radio>` children as a single-value selection.\n *\n * A signal-forms native control: it implements `FormValueControl<unknown>`, so\n * `[formField]` binds to its `value` model — the currently selected radio's\n * `value`. `[(value)]` works standalone. Classic `[(ngModel)]` / reactive forms\n * keep working through Angular's bridge.\n *\n * @example\n * ```html\n * <wr-radio-group [formField]=\"form.size\">\n * <wr-radio value=\"sm\">Small</wr-radio>\n * <wr-radio value=\"md\">Medium</wr-radio>\n * <wr-radio value=\"lg\">Large</wr-radio>\n * </wr-radio-group>\n * ```\n *\n * @see https://ngwr.dev/reference/components/radio\n */\n@Component({\n selector: 'wr-radio-group',\n template: '<ng-content />',\n encapsulation: ViewEncapsulation.None,\n host: { class: 'wr-radio-group', role: 'radiogroup' },\n providers: [\n {\n provide: WR_RADIO_GROUP,\n // eslint-disable-next-line @angular-eslint/no-forward-ref\n useExisting: forwardRef(() => WrRadioGroup),\n },\n ],\n})\nexport class WrRadioGroup implements FormValueControl<unknown>, WrRadioGroupContext {\n /**\n * Shared `name` attribute. Defaults to a random id so multiple groups\n * on the same page don't collide. (Also the `FormUiControl.name` slot.)\n */\n readonly name = input<string>(randomId('wr-radio-group'));\n\n /**\n * Disable the whole group. Bound automatically from the field's disabled\n * state when used with `[formField]`.\n *\n * @default false\n */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n /** The selected radio's value. Bound by `[formField]`, or two-way via `[(value)]`. */\n readonly value = model<unknown>(null);\n\n /** Emitted on blur from any child so a bound field can mark itself touched. */\n readonly touch = output<void>();\n\n /** Effective disabled state (WrRadioGroupContext). */\n readonly isDisabled = computed(() => this.disabled());\n\n // WrRadioGroupContext\n\n select(value: unknown): void {\n if (this.isDisabled()) return;\n this.value.set(value);\n }\n\n markTouched(): void {\n this.touch.emit();\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}