ngwr 14.8.0 → 14.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (447) hide show
  1. package/README.md +66 -332
  2. package/alert/styles/_index.scss +10 -0
  3. package/avatar/styles/_index.scss +18 -7
  4. package/badge/styles/_index.scss +7 -0
  5. package/badge/styles/_tag.scss +7 -1
  6. package/button/styles/_index.scss +6 -0
  7. package/cascader/styles/_rules.scss +1 -1
  8. package/checkbox/styles/_index.scss +4 -0
  9. package/command-palette/styles/_index.scss +1 -1
  10. package/divider/styles/_index.scss +2 -0
  11. package/editor/styles/_index.scss +441 -0
  12. package/fesm2022/ngwr-action-sheet-testing.mjs.map +1 -1
  13. package/fesm2022/ngwr-action-sheet.mjs +3 -3
  14. package/fesm2022/ngwr-action-sheet.mjs.map +1 -1
  15. package/fesm2022/ngwr-affix.mjs +3 -3
  16. package/fesm2022/ngwr-affix.mjs.map +1 -1
  17. package/fesm2022/ngwr-alert.mjs +3 -3
  18. package/fesm2022/ngwr-alert.mjs.map +1 -1
  19. package/fesm2022/ngwr-anchor.mjs +3 -3
  20. package/fesm2022/ngwr-anchor.mjs.map +1 -1
  21. package/fesm2022/ngwr-aurora.mjs +3 -3
  22. package/fesm2022/ngwr-aurora.mjs.map +1 -1
  23. package/fesm2022/ngwr-avatar.mjs +3 -3
  24. package/fesm2022/ngwr-avatar.mjs.map +1 -1
  25. package/fesm2022/ngwr-back-top.mjs +3 -3
  26. package/fesm2022/ngwr-back-top.mjs.map +1 -1
  27. package/fesm2022/ngwr-badge.mjs +28 -13
  28. package/fesm2022/ngwr-badge.mjs.map +1 -1
  29. package/fesm2022/ngwr-bar-chart-testing.mjs.map +1 -1
  30. package/fesm2022/ngwr-bar-chart.mjs +3 -3
  31. package/fesm2022/ngwr-bar-chart.mjs.map +1 -1
  32. package/fesm2022/ngwr-blur-text-testing.mjs.map +1 -1
  33. package/fesm2022/ngwr-blur-text.mjs +3 -3
  34. package/fesm2022/ngwr-blur-text.mjs.map +1 -1
  35. package/fesm2022/ngwr-border-glow-testing.mjs.map +1 -1
  36. package/fesm2022/ngwr-border-glow.mjs +3 -3
  37. package/fesm2022/ngwr-border-glow.mjs.map +1 -1
  38. package/fesm2022/ngwr-breadcrumbs.mjs +6 -6
  39. package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
  40. package/fesm2022/ngwr-burger.mjs +3 -3
  41. package/fesm2022/ngwr-burger.mjs.map +1 -1
  42. package/fesm2022/ngwr-button-testing.mjs.map +1 -1
  43. package/fesm2022/ngwr-button.mjs +6 -6
  44. package/fesm2022/ngwr-button.mjs.map +1 -1
  45. package/fesm2022/ngwr-calendar-heatmap-testing.mjs.map +1 -1
  46. package/fesm2022/ngwr-calendar-heatmap.mjs +3 -3
  47. package/fesm2022/ngwr-calendar-heatmap.mjs.map +1 -1
  48. package/fesm2022/ngwr-calendar-testing.mjs.map +1 -1
  49. package/fesm2022/ngwr-calendar.mjs +3 -3
  50. package/fesm2022/ngwr-calendar.mjs.map +1 -1
  51. package/fesm2022/ngwr-card.mjs +9 -9
  52. package/fesm2022/ngwr-card.mjs.map +1 -1
  53. package/fesm2022/ngwr-carousel-testing.mjs.map +1 -1
  54. package/fesm2022/ngwr-carousel.mjs +6 -6
  55. package/fesm2022/ngwr-carousel.mjs.map +1 -1
  56. package/fesm2022/ngwr-cascader-testing.mjs.map +1 -1
  57. package/fesm2022/ngwr-cascader.mjs +4 -4
  58. package/fesm2022/ngwr-cascader.mjs.map +1 -1
  59. package/fesm2022/ngwr-checkbox-testing.mjs.map +1 -1
  60. package/fesm2022/ngwr-checkbox.mjs +6 -6
  61. package/fesm2022/ngwr-checkbox.mjs.map +1 -1
  62. package/fesm2022/ngwr-circular-text-testing.mjs.map +1 -1
  63. package/fesm2022/ngwr-circular-text.mjs +3 -3
  64. package/fesm2022/ngwr-circular-text.mjs.map +1 -1
  65. package/fesm2022/ngwr-click-spark.mjs +3 -3
  66. package/fesm2022/ngwr-click-spark.mjs.map +1 -1
  67. package/fesm2022/ngwr-clipboard.mjs +3 -3
  68. package/fesm2022/ngwr-clipboard.mjs.map +1 -1
  69. package/fesm2022/ngwr-collapse-testing.mjs.map +1 -1
  70. package/fesm2022/ngwr-collapse.mjs +9 -9
  71. package/fesm2022/ngwr-collapse.mjs.map +1 -1
  72. package/fesm2022/ngwr-color-picker-testing.mjs.map +1 -1
  73. package/fesm2022/ngwr-color-picker.mjs +6 -6
  74. package/fesm2022/ngwr-color-picker.mjs.map +1 -1
  75. package/fesm2022/ngwr-command-palette-testing.mjs.map +1 -1
  76. package/fesm2022/ngwr-command-palette.mjs +3 -3
  77. package/fesm2022/ngwr-command-palette.mjs.map +1 -1
  78. package/fesm2022/ngwr-compare.mjs +3 -3
  79. package/fesm2022/ngwr-compare.mjs.map +1 -1
  80. package/fesm2022/ngwr-confetti.mjs +3 -3
  81. package/fesm2022/ngwr-confetti.mjs.map +1 -1
  82. package/fesm2022/ngwr-config.mjs.map +1 -1
  83. package/fesm2022/ngwr-context-menu-testing.mjs.map +1 -1
  84. package/fesm2022/ngwr-context-menu.mjs +12 -12
  85. package/fesm2022/ngwr-context-menu.mjs.map +1 -1
  86. package/fesm2022/ngwr-cookie.mjs +3 -3
  87. package/fesm2022/ngwr-cookie.mjs.map +1 -1
  88. package/fesm2022/ngwr-counter.mjs +6 -6
  89. package/fesm2022/ngwr-counter.mjs.map +1 -1
  90. package/fesm2022/ngwr-date-adapters-fns.mjs +3 -3
  91. package/fesm2022/ngwr-date-adapters-fns.mjs.map +1 -1
  92. package/fesm2022/ngwr-date-adapters-luxon.mjs +3 -3
  93. package/fesm2022/ngwr-date-adapters-luxon.mjs.map +1 -1
  94. package/fesm2022/ngwr-date-picker-testing.mjs.map +1 -1
  95. package/fesm2022/ngwr-date-picker.mjs +21 -21
  96. package/fesm2022/ngwr-date-picker.mjs.map +1 -1
  97. package/fesm2022/ngwr-date.mjs +3 -3
  98. package/fesm2022/ngwr-date.mjs.map +1 -1
  99. package/fesm2022/ngwr-decrypt-text-testing.mjs.map +1 -1
  100. package/fesm2022/ngwr-decrypt-text.mjs +3 -3
  101. package/fesm2022/ngwr-decrypt-text.mjs.map +1 -1
  102. package/fesm2022/ngwr-density.mjs +6 -6
  103. package/fesm2022/ngwr-density.mjs.map +1 -1
  104. package/fesm2022/ngwr-descriptions.mjs +6 -6
  105. package/fesm2022/ngwr-descriptions.mjs.map +1 -1
  106. package/fesm2022/ngwr-dialog-testing.mjs.map +1 -1
  107. package/fesm2022/ngwr-dialog.mjs +15 -15
  108. package/fesm2022/ngwr-dialog.mjs.map +1 -1
  109. package/fesm2022/ngwr-directives.mjs +12 -12
  110. package/fesm2022/ngwr-directives.mjs.map +1 -1
  111. package/fesm2022/ngwr-divider.mjs +3 -3
  112. package/fesm2022/ngwr-divider.mjs.map +1 -1
  113. package/fesm2022/ngwr-donut-chart-testing.mjs.map +1 -1
  114. package/fesm2022/ngwr-donut-chart.mjs +3 -3
  115. package/fesm2022/ngwr-donut-chart.mjs.map +1 -1
  116. package/fesm2022/ngwr-drag-drop.mjs +6 -6
  117. package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
  118. package/fesm2022/ngwr-drawer-testing.mjs.map +1 -1
  119. package/fesm2022/ngwr-drawer.mjs +18 -18
  120. package/fesm2022/ngwr-drawer.mjs.map +1 -1
  121. package/fesm2022/ngwr-dropdown-testing.mjs.map +1 -1
  122. package/fesm2022/ngwr-dropdown.mjs +9 -9
  123. package/fesm2022/ngwr-dropdown.mjs.map +1 -1
  124. package/fesm2022/ngwr-editor-testing.mjs +568 -0
  125. package/fesm2022/ngwr-editor-testing.mjs.map +1 -0
  126. package/fesm2022/ngwr-editor.mjs +2601 -0
  127. package/fesm2022/ngwr-editor.mjs.map +1 -0
  128. package/fesm2022/ngwr-empty.mjs +3 -3
  129. package/fesm2022/ngwr-empty.mjs.map +1 -1
  130. package/fesm2022/ngwr-event-calendar-testing.mjs.map +1 -1
  131. package/fesm2022/ngwr-event-calendar.mjs +6 -6
  132. package/fesm2022/ngwr-event-calendar.mjs.map +1 -1
  133. package/fesm2022/ngwr-falling-text-testing.mjs.map +1 -1
  134. package/fesm2022/ngwr-falling-text.mjs +3 -3
  135. package/fesm2022/ngwr-falling-text.mjs.map +1 -1
  136. package/fesm2022/ngwr-file-upload-testing.mjs.map +1 -1
  137. package/fesm2022/ngwr-file-upload.mjs +3 -3
  138. package/fesm2022/ngwr-file-upload.mjs.map +1 -1
  139. package/fesm2022/ngwr-form-testing.mjs.map +1 -1
  140. package/fesm2022/ngwr-form.mjs +9 -9
  141. package/fesm2022/ngwr-form.mjs.map +1 -1
  142. package/fesm2022/ngwr-fuzzy-text-testing.mjs.map +1 -1
  143. package/fesm2022/ngwr-fuzzy-text.mjs +3 -3
  144. package/fesm2022/ngwr-fuzzy-text.mjs.map +1 -1
  145. package/fesm2022/ngwr-gauge-testing.mjs.map +1 -1
  146. package/fesm2022/ngwr-gauge.mjs +3 -3
  147. package/fesm2022/ngwr-gauge.mjs.map +1 -1
  148. package/fesm2022/ngwr-glitch-text-testing.mjs.map +1 -1
  149. package/fesm2022/ngwr-glitch-text.mjs +3 -3
  150. package/fesm2022/ngwr-glitch-text.mjs.map +1 -1
  151. package/fesm2022/ngwr-gradient-text-testing.mjs.map +1 -1
  152. package/fesm2022/ngwr-gradient-text.mjs +3 -3
  153. package/fesm2022/ngwr-gradient-text.mjs.map +1 -1
  154. package/fesm2022/ngwr-graph-testing.mjs.map +1 -1
  155. package/fesm2022/ngwr-graph.mjs +6 -6
  156. package/fesm2022/ngwr-graph.mjs.map +1 -1
  157. package/fesm2022/ngwr-hotkey.mjs +6 -6
  158. package/fesm2022/ngwr-hotkey.mjs.map +1 -1
  159. package/fesm2022/ngwr-i18n-ar.mjs +29 -0
  160. package/fesm2022/ngwr-i18n-ar.mjs.map +1 -1
  161. package/fesm2022/ngwr-i18n-cs.mjs +29 -0
  162. package/fesm2022/ngwr-i18n-cs.mjs.map +1 -1
  163. package/fesm2022/ngwr-i18n-de.mjs +29 -0
  164. package/fesm2022/ngwr-i18n-de.mjs.map +1 -1
  165. package/fesm2022/ngwr-i18n-en.mjs +34 -0
  166. package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
  167. package/fesm2022/ngwr-i18n-es.mjs +29 -0
  168. package/fesm2022/ngwr-i18n-es.mjs.map +1 -1
  169. package/fesm2022/ngwr-i18n-fr.mjs +29 -0
  170. package/fesm2022/ngwr-i18n-fr.mjs.map +1 -1
  171. package/fesm2022/ngwr-i18n-he.mjs +29 -0
  172. package/fesm2022/ngwr-i18n-he.mjs.map +1 -1
  173. package/fesm2022/ngwr-i18n-hi.mjs +29 -0
  174. package/fesm2022/ngwr-i18n-hi.mjs.map +1 -1
  175. package/fesm2022/ngwr-i18n-id.mjs +29 -0
  176. package/fesm2022/ngwr-i18n-id.mjs.map +1 -1
  177. package/fesm2022/ngwr-i18n-it.mjs +29 -0
  178. package/fesm2022/ngwr-i18n-it.mjs.map +1 -1
  179. package/fesm2022/ngwr-i18n-ja.mjs +29 -0
  180. package/fesm2022/ngwr-i18n-ja.mjs.map +1 -1
  181. package/fesm2022/ngwr-i18n-ko.mjs +29 -0
  182. package/fesm2022/ngwr-i18n-ko.mjs.map +1 -1
  183. package/fesm2022/ngwr-i18n-nl.mjs +29 -0
  184. package/fesm2022/ngwr-i18n-nl.mjs.map +1 -1
  185. package/fesm2022/ngwr-i18n-pl.mjs +29 -0
  186. package/fesm2022/ngwr-i18n-pl.mjs.map +1 -1
  187. package/fesm2022/ngwr-i18n-pt.mjs +29 -0
  188. package/fesm2022/ngwr-i18n-pt.mjs.map +1 -1
  189. package/fesm2022/ngwr-i18n-ru.mjs +29 -0
  190. package/fesm2022/ngwr-i18n-ru.mjs.map +1 -1
  191. package/fesm2022/ngwr-i18n-sv.mjs +29 -0
  192. package/fesm2022/ngwr-i18n-sv.mjs.map +1 -1
  193. package/fesm2022/ngwr-i18n-tr.mjs +29 -0
  194. package/fesm2022/ngwr-i18n-tr.mjs.map +1 -1
  195. package/fesm2022/ngwr-i18n-uk.mjs +29 -0
  196. package/fesm2022/ngwr-i18n-uk.mjs.map +1 -1
  197. package/fesm2022/ngwr-i18n-vi.mjs +29 -0
  198. package/fesm2022/ngwr-i18n-vi.mjs.map +1 -1
  199. package/fesm2022/ngwr-i18n-zh-TW.mjs +29 -0
  200. package/fesm2022/ngwr-i18n-zh-TW.mjs.map +1 -1
  201. package/fesm2022/ngwr-i18n-zh.mjs +29 -0
  202. package/fesm2022/ngwr-i18n-zh.mjs.map +1 -1
  203. package/fesm2022/ngwr-i18n.mjs +9 -9
  204. package/fesm2022/ngwr-i18n.mjs.map +1 -1
  205. package/fesm2022/ngwr-icon-adapters-feather.mjs.map +1 -1
  206. package/fesm2022/ngwr-icon-adapters-lucide.mjs.map +1 -1
  207. package/fesm2022/ngwr-icon.mjs +6 -6
  208. package/fesm2022/ngwr-icon.mjs.map +1 -1
  209. package/fesm2022/ngwr-image-cropper-testing.mjs.map +1 -1
  210. package/fesm2022/ngwr-image-cropper.mjs +3 -3
  211. package/fesm2022/ngwr-image-cropper.mjs.map +1 -1
  212. package/fesm2022/ngwr-input-number-testing.mjs.map +1 -1
  213. package/fesm2022/ngwr-input-number.mjs +3 -3
  214. package/fesm2022/ngwr-input-number.mjs.map +1 -1
  215. package/fesm2022/ngwr-input-otp-testing.mjs.map +1 -1
  216. package/fesm2022/ngwr-input-otp.mjs +3 -3
  217. package/fesm2022/ngwr-input-otp.mjs.map +1 -1
  218. package/fesm2022/ngwr-input-testing.mjs.map +1 -1
  219. package/fesm2022/ngwr-input.mjs +15 -15
  220. package/fesm2022/ngwr-input.mjs.map +1 -1
  221. package/fesm2022/ngwr-keyboard.mjs +3 -3
  222. package/fesm2022/ngwr-keyboard.mjs.map +1 -1
  223. package/fesm2022/ngwr-knob-testing.mjs.map +1 -1
  224. package/fesm2022/ngwr-knob.mjs +3 -3
  225. package/fesm2022/ngwr-knob.mjs.map +1 -1
  226. package/fesm2022/ngwr-layout.mjs +15 -15
  227. package/fesm2022/ngwr-layout.mjs.map +1 -1
  228. package/fesm2022/ngwr-lightbox-testing.mjs.map +1 -1
  229. package/fesm2022/ngwr-lightbox.mjs +3 -3
  230. package/fesm2022/ngwr-lightbox.mjs.map +1 -1
  231. package/fesm2022/ngwr-line-chart-testing.mjs.map +1 -1
  232. package/fesm2022/ngwr-line-chart.mjs +3 -3
  233. package/fesm2022/ngwr-line-chart.mjs.map +1 -1
  234. package/fesm2022/ngwr-list.mjs +6 -6
  235. package/fesm2022/ngwr-list.mjs.map +1 -1
  236. package/fesm2022/ngwr-loading-bar-router.mjs.map +1 -1
  237. package/fesm2022/ngwr-loading-bar.mjs +6 -6
  238. package/fesm2022/ngwr-loading-bar.mjs.map +1 -1
  239. package/fesm2022/ngwr-markdown-testing.mjs.map +1 -1
  240. package/fesm2022/ngwr-markdown.mjs +798 -17
  241. package/fesm2022/ngwr-markdown.mjs.map +1 -1
  242. package/fesm2022/ngwr-marquee-testing.mjs.map +1 -1
  243. package/fesm2022/ngwr-marquee.mjs +3 -3
  244. package/fesm2022/ngwr-marquee.mjs.map +1 -1
  245. package/fesm2022/ngwr-media.mjs +3 -3
  246. package/fesm2022/ngwr-media.mjs.map +1 -1
  247. package/fesm2022/ngwr-mention-testing.mjs.map +1 -1
  248. package/fesm2022/ngwr-mention.mjs +6 -6
  249. package/fesm2022/ngwr-mention.mjs.map +1 -1
  250. package/fesm2022/ngwr-meta.mjs +6 -6
  251. package/fesm2022/ngwr-meta.mjs.map +1 -1
  252. package/fesm2022/ngwr-meter-group-testing.mjs.map +1 -1
  253. package/fesm2022/ngwr-meter-group.mjs +3 -3
  254. package/fesm2022/ngwr-meter-group.mjs.map +1 -1
  255. package/fesm2022/ngwr-overlay.mjs +6 -6
  256. package/fesm2022/ngwr-overlay.mjs.map +1 -1
  257. package/fesm2022/ngwr-page-header.mjs +3 -3
  258. package/fesm2022/ngwr-page-header.mjs.map +1 -1
  259. package/fesm2022/ngwr-pagination-testing.mjs.map +1 -1
  260. package/fesm2022/ngwr-pagination.mjs +3 -3
  261. package/fesm2022/ngwr-pagination.mjs.map +1 -1
  262. package/fesm2022/ngwr-pipes.mjs +21 -21
  263. package/fesm2022/ngwr-pipes.mjs.map +1 -1
  264. package/fesm2022/ngwr-platform.mjs +9 -9
  265. package/fesm2022/ngwr-platform.mjs.map +1 -1
  266. package/fesm2022/ngwr-popconfirm-testing.mjs.map +1 -1
  267. package/fesm2022/ngwr-popconfirm.mjs +6 -6
  268. package/fesm2022/ngwr-popconfirm.mjs.map +1 -1
  269. package/fesm2022/ngwr-popover-testing.mjs.map +1 -1
  270. package/fesm2022/ngwr-popover.mjs +12 -12
  271. package/fesm2022/ngwr-popover.mjs.map +1 -1
  272. package/fesm2022/ngwr-progress.mjs +3 -3
  273. package/fesm2022/ngwr-progress.mjs.map +1 -1
  274. package/fesm2022/ngwr-pull-to-refresh.mjs +3 -3
  275. package/fesm2022/ngwr-pull-to-refresh.mjs.map +1 -1
  276. package/fesm2022/ngwr-qr.mjs +3 -3
  277. package/fesm2022/ngwr-qr.mjs.map +1 -1
  278. package/fesm2022/ngwr-radio-testing.mjs.map +1 -1
  279. package/fesm2022/ngwr-radio.mjs +6 -6
  280. package/fesm2022/ngwr-radio.mjs.map +1 -1
  281. package/fesm2022/ngwr-rating-testing.mjs.map +1 -1
  282. package/fesm2022/ngwr-rating.mjs +3 -3
  283. package/fesm2022/ngwr-rating.mjs.map +1 -1
  284. package/fesm2022/ngwr-result.mjs +12 -12
  285. package/fesm2022/ngwr-result.mjs.map +1 -1
  286. package/fesm2022/ngwr-rotating-text-testing.mjs.map +1 -1
  287. package/fesm2022/ngwr-rotating-text.mjs +3 -3
  288. package/fesm2022/ngwr-rotating-text.mjs.map +1 -1
  289. package/fesm2022/ngwr-schema-form.mjs +3 -3
  290. package/fesm2022/ngwr-schema-form.mjs.map +1 -1
  291. package/fesm2022/ngwr-scroll.mjs +3 -3
  292. package/fesm2022/ngwr-scroll.mjs.map +1 -1
  293. package/fesm2022/ngwr-segmented-testing.mjs.map +1 -1
  294. package/fesm2022/ngwr-segmented.mjs +3 -3
  295. package/fesm2022/ngwr-segmented.mjs.map +1 -1
  296. package/fesm2022/ngwr-select-testing.mjs.map +1 -1
  297. package/fesm2022/ngwr-select.mjs +12 -12
  298. package/fesm2022/ngwr-select.mjs.map +1 -1
  299. package/fesm2022/ngwr-shiny-text-testing.mjs.map +1 -1
  300. package/fesm2022/ngwr-shiny-text.mjs +6 -6
  301. package/fesm2022/ngwr-shiny-text.mjs.map +1 -1
  302. package/fesm2022/ngwr-sidebar.mjs +3 -3
  303. package/fesm2022/ngwr-sidebar.mjs.map +1 -1
  304. package/fesm2022/ngwr-skeleton.mjs +3 -3
  305. package/fesm2022/ngwr-skeleton.mjs.map +1 -1
  306. package/fesm2022/ngwr-slider-testing.mjs.map +1 -1
  307. package/fesm2022/ngwr-slider.mjs +3 -3
  308. package/fesm2022/ngwr-slider.mjs.map +1 -1
  309. package/fesm2022/ngwr-sparkline-testing.mjs.map +1 -1
  310. package/fesm2022/ngwr-sparkline.mjs +3 -3
  311. package/fesm2022/ngwr-sparkline.mjs.map +1 -1
  312. package/fesm2022/ngwr-speed-dial-testing.mjs.map +1 -1
  313. package/fesm2022/ngwr-speed-dial.mjs +3 -3
  314. package/fesm2022/ngwr-speed-dial.mjs.map +1 -1
  315. package/fesm2022/ngwr-spinner.mjs +3 -3
  316. package/fesm2022/ngwr-spinner.mjs.map +1 -1
  317. package/fesm2022/ngwr-splash-cursor-testing.mjs.map +1 -1
  318. package/fesm2022/ngwr-splash-cursor.mjs +3 -3
  319. package/fesm2022/ngwr-splash-cursor.mjs.map +1 -1
  320. package/fesm2022/ngwr-split-text-testing.mjs.map +1 -1
  321. package/fesm2022/ngwr-split-text.mjs +3 -3
  322. package/fesm2022/ngwr-split-text.mjs.map +1 -1
  323. package/fesm2022/ngwr-splitter-testing.mjs.map +1 -1
  324. package/fesm2022/ngwr-splitter.mjs +3 -3
  325. package/fesm2022/ngwr-splitter.mjs.map +1 -1
  326. package/fesm2022/ngwr-spotlight-card-testing.mjs.map +1 -1
  327. package/fesm2022/ngwr-spotlight-card.mjs +6 -6
  328. package/fesm2022/ngwr-spotlight-card.mjs.map +1 -1
  329. package/fesm2022/ngwr-squircle.mjs +6 -6
  330. package/fesm2022/ngwr-squircle.mjs.map +1 -1
  331. package/fesm2022/ngwr-star-border-testing.mjs.map +1 -1
  332. package/fesm2022/ngwr-star-border.mjs +3 -3
  333. package/fesm2022/ngwr-star-border.mjs.map +1 -1
  334. package/fesm2022/ngwr-statistic.mjs +9 -9
  335. package/fesm2022/ngwr-statistic.mjs.map +1 -1
  336. package/fesm2022/ngwr-stepper-testing.mjs.map +1 -1
  337. package/fesm2022/ngwr-stepper.mjs +6 -6
  338. package/fesm2022/ngwr-stepper.mjs.map +1 -1
  339. package/fesm2022/ngwr-storage.mjs +3 -3
  340. package/fesm2022/ngwr-storage.mjs.map +1 -1
  341. package/fesm2022/ngwr-switch-testing.mjs.map +1 -1
  342. package/fesm2022/ngwr-switch.mjs +3 -3
  343. package/fesm2022/ngwr-switch.mjs.map +1 -1
  344. package/fesm2022/ngwr-table-testing.mjs.map +1 -1
  345. package/fesm2022/ngwr-table.mjs +18 -18
  346. package/fesm2022/ngwr-table.mjs.map +1 -1
  347. package/fesm2022/ngwr-tabs-router.mjs +3 -3
  348. package/fesm2022/ngwr-tabs-router.mjs.map +1 -1
  349. package/fesm2022/ngwr-tabs-testing.mjs.map +1 -1
  350. package/fesm2022/ngwr-tabs.mjs +6 -6
  351. package/fesm2022/ngwr-tabs.mjs.map +1 -1
  352. package/fesm2022/ngwr-textarea-testing.mjs.map +1 -1
  353. package/fesm2022/ngwr-textarea.mjs +3 -3
  354. package/fesm2022/ngwr-textarea.mjs.map +1 -1
  355. package/fesm2022/ngwr-theme.mjs +3 -3
  356. package/fesm2022/ngwr-theme.mjs.map +1 -1
  357. package/fesm2022/ngwr-tilt-card-testing.mjs.map +1 -1
  358. package/fesm2022/ngwr-tilt-card.mjs +6 -6
  359. package/fesm2022/ngwr-tilt-card.mjs.map +1 -1
  360. package/fesm2022/ngwr-timeline.mjs +6 -6
  361. package/fesm2022/ngwr-timeline.mjs.map +1 -1
  362. package/fesm2022/ngwr-toast-testing.mjs.map +1 -1
  363. package/fesm2022/ngwr-toast.mjs +9 -9
  364. package/fesm2022/ngwr-toast.mjs.map +1 -1
  365. package/fesm2022/ngwr-toolbar.mjs +3 -3
  366. package/fesm2022/ngwr-toolbar.mjs.map +1 -1
  367. package/fesm2022/ngwr-tour-testing.mjs.map +1 -1
  368. package/fesm2022/ngwr-tour.mjs +6 -6
  369. package/fesm2022/ngwr-tour.mjs.map +1 -1
  370. package/fesm2022/ngwr-transfer-testing.mjs.map +1 -1
  371. package/fesm2022/ngwr-transfer.mjs +3 -3
  372. package/fesm2022/ngwr-transfer.mjs.map +1 -1
  373. package/fesm2022/ngwr-tree-testing.mjs.map +1 -1
  374. package/fesm2022/ngwr-tree.mjs +3 -3
  375. package/fesm2022/ngwr-tree.mjs.map +1 -1
  376. package/fesm2022/ngwr-typewriter-testing.mjs.map +1 -1
  377. package/fesm2022/ngwr-typewriter.mjs +3 -3
  378. package/fesm2022/ngwr-typewriter.mjs.map +1 -1
  379. package/fesm2022/ngwr-typography.mjs +7 -3
  380. package/fesm2022/ngwr-typography.mjs.map +1 -1
  381. package/fesm2022/ngwr-utils.mjs.map +1 -1
  382. package/fesm2022/ngwr-validators.mjs.map +1 -1
  383. package/fesm2022/ngwr-version.mjs +1 -1
  384. package/fesm2022/ngwr-version.mjs.map +1 -1
  385. package/fesm2022/ngwr-virtual-scroll.mjs +3 -3
  386. package/fesm2022/ngwr-virtual-scroll.mjs.map +1 -1
  387. package/fesm2022/ngwr-waves-testing.mjs.map +1 -1
  388. package/fesm2022/ngwr-waves.mjs +3 -3
  389. package/fesm2022/ngwr-waves.mjs.map +1 -1
  390. package/fesm2022/ngwr-window-testing.mjs.map +1 -1
  391. package/fesm2022/ngwr-window.mjs +12 -12
  392. package/fesm2022/ngwr-window.mjs.map +1 -1
  393. package/form/styles/_index.scss +5 -0
  394. package/i18n/ar.json +29 -0
  395. package/i18n/cs.json +29 -0
  396. package/i18n/de.json +29 -0
  397. package/i18n/en.json +29 -0
  398. package/i18n/es.json +29 -0
  399. package/i18n/fr.json +29 -0
  400. package/i18n/he.json +29 -0
  401. package/i18n/hi.json +29 -0
  402. package/i18n/id.json +29 -0
  403. package/i18n/it.json +29 -0
  404. package/i18n/ja.json +29 -0
  405. package/i18n/ko.json +29 -0
  406. package/i18n/nl.json +29 -0
  407. package/i18n/pl.json +29 -0
  408. package/i18n/pt.json +29 -0
  409. package/i18n/ru.json +29 -0
  410. package/i18n/sv.json +29 -0
  411. package/i18n/tr.json +29 -0
  412. package/i18n/uk.json +29 -0
  413. package/i18n/vi.json +29 -0
  414. package/i18n/zh-TW.json +29 -0
  415. package/i18n/zh.json +29 -0
  416. package/input/styles/_index.scss +5 -1
  417. package/input-otp/styles/_index.scss +5 -5
  418. package/llms-full.txt +11 -1
  419. package/llms.txt +188 -132
  420. package/mcp/providers.js +2 -2
  421. package/mcp/server.js +1 -1
  422. package/overlay/styles/_arrow.scss +3 -0
  423. package/package.json +43 -2
  424. package/progress/styles/_index.scss +4 -0
  425. package/radio/styles/_index.scss +4 -1
  426. package/schematics/use/symbol-map.json +1 -0
  427. package/select/styles/_index.scss +3 -3
  428. package/sidebar/styles/_index.scss +10 -0
  429. package/skeleton/styles/_index.scss +3 -0
  430. package/skills/ngwr/SKILL.md +5 -5
  431. package/skills/ngwr/references/catalog.md +2 -0
  432. package/skills/ngwr/references/setup.md +3 -3
  433. package/styles.scss +1 -0
  434. package/table/styles/_index.scss +7 -0
  435. package/textarea/styles/_index.scss +12 -3
  436. package/theme/styles/_colors.scss +39 -13
  437. package/theme/styles/_contrast.scss +9 -7
  438. package/toast/styles/_index.scss +4 -0
  439. package/tree/styles/_index.scss +1 -1
  440. package/types/ngwr-badge.d.ts +22 -7
  441. package/types/ngwr-config.d.ts +12 -0
  442. package/types/ngwr-editor-testing.d.ts +378 -0
  443. package/types/ngwr-editor.d.ts +449 -0
  444. package/types/ngwr-markdown.d.ts +61 -2
  445. package/types/ngwr-typography.d.ts +4 -0
  446. package/types/ngwr-version.d.ts +1 -1
  447. package/typography/styles/_index.scss +16 -0
@@ -1 +1 @@
1
- {"version":3,"file":"ngwr-tour.mjs","sources":["../../../projects/lib/tour/tour-popup.ts","../../../projects/lib/tour/tour-popup.html","../../../projects/lib/tour/tour.ts","../../../projects/lib/tour/ngwr-tour.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Component, InjectionToken, ViewEncapsulation, computed, inject } from '@angular/core';\n\nimport { WrButton } from 'ngwr/button';\nimport { readI18nText, useI18nFormatter } from 'ngwr/i18n';\n\nimport type { WrTourStep } from './interfaces';\n\n/** What the popup needs from the running tour, without importing the service (cycle). */\nexport interface WrTourController {\n readonly index: () => number;\n readonly total: () => number;\n readonly step: () => WrTourStep | null;\n /**\n * Whether this is the last step the user will actually see — the service looks\n * ahead for a reachable one, because a trailing step whose target is missing gets\n * skipped and the raw count would call the final card \"Next\".\n */\n readonly isLast: () => boolean;\n /**\n * Whether this is the first step the user will actually see — the service looks\n * BEHIND for a reachable one, for the mirror reason: a leading step whose target\n * is missing gets skipped, so the tour opens on a later index and the raw one\n * would put a Back button on the very first card.\n */\n readonly isFirst: () => boolean;\n next(): void;\n prev(): void;\n stop(): void;\n}\n\n/** Provided by `WrTour` when it attaches the popup portal. */\nexport const WR_TOUR_STEP = new InjectionToken<WrTourController>('WR_TOUR_STEP');\n\n/**\n * The card a tour shows next to the spotlit element. Rendered by `WrTour` into\n * a CDK overlay — not something you place yourself.\n *\n * @see https://ngwr.dev/reference/services/tour\n */\n@Component({\n selector: 'wr-tour-popup',\n templateUrl: './tour-popup.html',\n encapsulation: ViewEncapsulation.None,\n host: { class: 'wr-tour-popup', role: 'dialog', 'aria-modal': 'true', '[attr.aria-label]': 'ariaLabel()' },\n imports: [WrButton],\n})\nexport class WrTourPopup {\n protected readonly tour = inject(WR_TOUR_STEP);\n\n // `readI18nText`, not `useI18nText`: these have no consumer-facing input to\n // forward. Both helpers are reactive.\n protected readonly nextLabel = readI18nText('tour.next', 'Next');\n protected readonly backLabel = readI18nText('tour.back', 'Back');\n protected readonly doneLabel = readI18nText('tour.done', 'Done');\n protected readonly skipLabel = readI18nText('tour.skip', 'Skip tour');\n\n /** `Step {{current}} of {{total}}` — also the dialog's accessible name. */\n protected readonly progress = useI18nFormatter('tour.progress', 'Step {{current}} of {{total}}');\n\n // From the service, not `index() >= total() - 1`: a trailing step whose target is\n // missing gets skipped, so the raw count called the final card \"Next\" and then\n // ended the tour when it was pressed.\n protected readonly isLast = computed(() => this.tour.isLast());\n // Same story at the other end, and the same fix: `index() <= 0` rendered a Back\n // button on the first card of a tour whose leading step had been skipped, and\n // `prev()` walks off the start and returns — so the button did nothing at all.\n protected readonly isFirst = computed(() => this.tour.isFirst());\n\n protected readonly progressText = computed(() =>\n this.progress({ current: this.tour.index() + 1, total: this.tour.total() })\n );\n\n protected readonly ariaLabel = computed(() => {\n const title = this.tour.step()?.title;\n return title ? `${title} — ${this.progressText()}` : this.progressText();\n });\n}\n","@let step = tour.step();\n\n<p class=\"wr-tour-popup__progress\">{{ progressText() }}</p>\n\n@if (step?.title; as title) {\n <h2 class=\"wr-tour-popup__title\">{{ title }}</h2>\n}\n\n<p class=\"wr-tour-popup__content\">{{ step?.content }}</p>\n\n<div class=\"wr-tour-popup__actions\">\n <!-- The three buttons are told apart by a class rather than by their position in\n the row: the back button is conditional, so an index means one thing on the\n first step and another everywhere else — and the labels are translated. -->\n <button\n wr-btn\n type=\"button\"\n size=\"sm\"\n color=\"medium\"\n outlined\n class=\"wr-tour-popup__action wr-tour-popup__action--skip\"\n (click)=\"tour.stop()\"\n >\n {{ skipLabel() }}\n </button>\n\n <span class=\"wr-tour-popup__spacer\"></span>\n\n @if (!isFirst()) {\n <button\n wr-btn\n type=\"button\"\n size=\"sm\"\n outlined\n class=\"wr-tour-popup__action wr-tour-popup__action--back\"\n (click)=\"tour.prev()\"\n >\n {{ backLabel() }}\n </button>\n }\n <button\n wr-btn\n type=\"button\"\n size=\"sm\"\n color=\"primary\"\n class=\"wr-tour-popup__action wr-tour-popup__action--next\"\n (click)=\"tour.next()\"\n >\n {{ isLast() ? doneLabel() : nextLabel() }}\n </button>\n</div>\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { type ConfigurableFocusTrap, ConfigurableFocusTrapFactory } from '@angular/cdk/a11y';\nimport { Directionality } from '@angular/cdk/bidi';\nimport { type ConnectedPosition, type OverlayRef, ScrollStrategyOptions } from '@angular/cdk/overlay';\nimport { ComponentPortal } from '@angular/cdk/portal';\nimport { isPlatformBrowser } from '@angular/common';\nimport {\n DOCUMENT,\n DestroyRef,\n EnvironmentInjector,\n Injector,\n PLATFORM_ID,\n Service,\n computed,\n inject,\n signal,\n} from '@angular/core';\n\nimport { WR_OVERLAY, wrFollowDirection, wrMirrorOffsets } from 'ngwr/overlay';\n\nimport type { WrTourPlacement, WrTourStep } from './interfaces';\nimport { WR_TOUR_STEP, WrTourPopup } from './tour-popup';\n\n/** Fallback order per preferred side — the opposite side first, then the sides. */\nconst FALLBACKS: Record<WrTourPlacement, readonly WrTourPlacement[]> = {\n bottom: ['bottom', 'top', 'right', 'left'],\n top: ['top', 'bottom', 'right', 'left'],\n left: ['left', 'right', 'bottom', 'top'],\n right: ['right', 'left', 'bottom', 'top'],\n};\n\nconst CONNECTED: Record<\n WrTourPlacement,\n {\n originX: 'start' | 'center' | 'end';\n originY: 'top' | 'center' | 'bottom';\n overlayX: 'start' | 'center' | 'end';\n overlayY: 'top' | 'center' | 'bottom';\n }\n> = {\n bottom: { originX: 'center', originY: 'bottom', overlayX: 'center', overlayY: 'top' },\n top: { originX: 'center', originY: 'top', overlayX: 'center', overlayY: 'bottom' },\n left: { originX: 'start', originY: 'center', overlayX: 'end', overlayY: 'center' },\n right: { originX: 'end', originY: 'center', overlayX: 'start', overlayY: 'center' },\n};\n\n/**\n * Guided product tour: a spotlight over one element at a time plus a popup\n * explaining it.\n *\n * Steps are data, not markup — call `start()` with an array and the service owns\n * the overlay, the cut-out, focus and the keyboard. A step whose target is not\n * on the page is skipped rather than shown floating, so a tour survives a\n * feature being hidden behind a flag or a permission.\n *\n * @example\n * ```ts\n * private readonly tour = inject(WrTour);\n *\n * showMeAround(): void {\n * this.tour.start([\n * { target: '[data-tour=\"search\"]', title: 'Search', content: 'Find anything by name.' },\n * { target: '[data-tour=\"filters\"]', content: 'Narrow the list down.', placement: 'right' },\n * ]);\n * }\n * ```\n *\n * @see https://ngwr.dev/reference/services/tour\n */\n@Service()\nexport class WrTour {\n private readonly overlay = inject(WR_OVERLAY);\n private readonly dir = inject(Directionality, { optional: true });\n private readonly scrollStrategies = inject(ScrollStrategyOptions);\n private readonly injector = inject(EnvironmentInjector);\n private readonly focusTrapFactory = inject(ConfigurableFocusTrapFactory);\n private readonly document = inject(DOCUMENT);\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n private readonly steps = signal<readonly WrTourStep[]>([]);\n private readonly cursor = signal(-1);\n\n private overlayRef: OverlayRef | null = null;\n private focusTrap: ConfigurableFocusTrap | null = null;\n private spotlight: HTMLElement | null = null;\n private detachKeydown: (() => void) | null = null;\n private detachReposition: (() => void) | null = null;\n private restoreFocus: HTMLElement | null = null;\n\n /** Whether a tour is running. */\n readonly active = computed(() => this.cursor() >= 0);\n\n /** Zero-based index of the current step, `-1` when idle. */\n readonly index = computed(() => this.cursor());\n\n /** How many steps this tour has. */\n readonly total = computed(() => this.steps().length);\n\n /** The step being shown, or `null` when idle. */\n readonly step = computed<WrTourStep | null>(() => this.steps()[this.cursor()] ?? null);\n\n // Whether any step AFTER the current one can actually be shown. Settled once per\n // move, in `goTo`, because reachability is a DOM question and not a signal.\n private readonly noStepAfter = signal(false);\n\n // The same question looking the other way. Settled in `goTo` for the same reason.\n private readonly noStepBefore = signal(true);\n\n /**\n * Whether this is the last step the user will see. Not `index() === total() - 1`:\n * a trailing step whose target is missing is skipped, so comparing against the\n * raw count left the primary button reading \"Next\" on the final card and then\n * ending the tour when it was pressed.\n */\n readonly isLast = computed(() => this.noStepAfter());\n\n /**\n * Whether this is the first step the user will see. Not `index() === 0`, for the\n * mirror of the reason above: a LEADING step whose target is missing is skipped,\n * so the tour opens on a later index and the raw one put a Back button on the\n * first card — one that did nothing at all, because `prev()` walks off the start\n * and returns without moving.\n */\n readonly isFirst = computed(() => this.noStepBefore());\n\n constructor() {\n // Everything this service owns lives OUTSIDE its own injector: a CDK overlay, a\n // div appended to `document.body`, a document keydown listener and two window\n // listeners. Nothing removes them when the injector goes, so a tour running at\n // teardown left its cut-out on the page.\n inject(DestroyRef).onDestroy(() => this.stop());\n }\n\n /**\n * Begin a tour. Restarts if one is already running. A no-op under SSR — a\n * tour is a client-side affordance and there is nothing to spotlight on the\n * server.\n */\n start(steps: readonly WrTourStep[]): void {\n if (!this.isBrowser || steps.length === 0) return;\n this.stop();\n this.steps.set(steps);\n this.restoreFocus = this.document.activeElement as HTMLElement | null;\n this.goTo(0, 1);\n }\n\n /** Advance; finishes the tour past the last step. */\n next(): void {\n this.goTo(this.cursor() + 1, 1);\n }\n\n /** Go back; stays put on the first step. */\n prev(): void {\n this.goTo(this.cursor() - 1, -1);\n }\n\n /** End the tour and return focus where it was. */\n stop(): void {\n this.teardownStep();\n this.steps.set([]);\n this.cursor.set(-1);\n this.restoreFocus?.focus?.();\n this.restoreFocus = null;\n }\n\n /**\n * Move to `index`, skipping steps whose target is not in the DOM. `direction`\n * says which way to keep skipping, so a missing step never traps the tour\n * between two dead ends.\n */\n private goTo(index: number, direction: 1 | -1): void {\n const steps = this.steps();\n let i = index;\n while (i >= 0 && i < steps.length && this.resolve(steps[i]) === null) i += direction;\n\n if (i < 0) {\n // Ran off the start while going back — stay where we were.\n return;\n }\n if (i >= steps.length) {\n this.stop();\n return;\n }\n\n this.teardownStep();\n this.cursor.set(i);\n this.noStepAfter.set(!this.anyResolvableAfter(i));\n this.noStepBefore.set(!this.anyResolvableBefore(i));\n this.openStep(steps[i]);\n }\n\n /** Whether the tour has a step past `index` that can actually be shown. */\n private anyResolvableAfter(index: number): boolean {\n const steps = this.steps();\n for (let i = index + 1; i < steps.length; i += 1) {\n if (this.resolve(steps[i]) !== null) return true;\n }\n return false;\n }\n\n /** Whether the tour has a step before `index` that can actually be shown. */\n private anyResolvableBefore(index: number): boolean {\n const steps = this.steps();\n for (let i = index - 1; i >= 0; i -= 1) {\n if (this.resolve(steps[i]) !== null) return true;\n }\n return false;\n }\n\n private resolve(step: WrTourStep): HTMLElement | null {\n if (typeof step.target !== 'string') return step.target.isConnected ? step.target : null;\n return this.document.querySelector<HTMLElement>(step.target);\n }\n\n private openStep(step: WrTourStep): void {\n const target = this.resolve(step);\n if (!target) return;\n\n target.scrollIntoView({ block: 'center', inline: 'nearest', behavior: 'smooth' });\n\n // The cut-out is a bare element sized to the target with an enormous spread\n // shadow: everything outside it dims, the target itself stays untouched.\n // Cheaper and far more robust than a clip-path polygon, and it needs no\n // recompute when the page reflows beyond moving the box.\n const spotlight = this.document.createElement('div');\n spotlight.className = 'wr-tour__spotlight';\n spotlight.setAttribute('aria-hidden', 'true');\n this.document.body.appendChild(spotlight);\n this.spotlight = spotlight;\n this.placeSpotlight(target);\n\n const placement = step.placement ?? 'bottom';\n const positionStrategy = this.overlay\n .position()\n .flexibleConnectedTo(target)\n .withPositions(this.stepPositions(placement, this.isRtl()))\n .withPush(true);\n\n this.overlayRef = this.overlay.create({\n positionStrategy,\n scrollStrategy: this.scrollStrategies.reposition(),\n panelClass: 'wr-tour-overlay',\n });\n\n // The CDK read the direction once, just now. A tour is long-lived by nature\n // — a step can sit on screen while the user changes a language setting — and\n // without this the card keeps the direction the step opened in, with the\n // 12px gap that held it clear of the spotlight now pointing into it.\n // Per step, because every move disposes this ref and builds the next.\n wrFollowDirection(this.overlayRef, this.dir, this.injector, direction =>\n positionStrategy.withPositions(this.stepPositions(placement, direction === 'rtl'))\n );\n\n const portal = new ComponentPortal(\n WrTourPopup,\n null,\n Injector.create({ parent: this.injector, providers: [{ provide: WR_TOUR_STEP, useValue: this }] })\n );\n const ref = this.overlayRef.attach(portal);\n\n // Kept on the instance, not in a local: a trap registers with CDK's\n // `FocusTrapManager` and installs a capture-phase document focus listener, so an\n // undestroyed one leaks per STEP and every tour left a stack of them behind.\n this.focusTrap = this.focusTrapFactory.create(ref.location.nativeElement as HTMLElement);\n void this.focusTrap.focusInitialElementWhenReady();\n\n const onKey = (event: KeyboardEvent): void => {\n // The listener is on the document, so a step shown over a dialog would see the\n // Escape that dialog just handled and close the tour too.\n if (event.key === 'Escape' && !event.defaultPrevented) {\n event.preventDefault();\n this.stop();\n }\n };\n this.document.addEventListener('keydown', onKey);\n this.detachKeydown = () => this.document.removeEventListener('keydown', onKey);\n\n const reposition = (): void => this.placeSpotlight(target);\n window.addEventListener('scroll', reposition, true);\n window.addEventListener('resize', reposition);\n this.detachReposition = () => {\n window.removeEventListener('scroll', reposition, true);\n window.removeEventListener('resize', reposition);\n };\n }\n\n /**\n * The card's fallback table for one placement, with its inline offsets already\n * mirrored. Built per call rather than per step: the direction can change while\n * the step is on screen, and a table is what has to be rebuilt when it does.\n */\n private stepPositions(placement: WrTourPlacement, isRtl: boolean): ConnectedPosition[] {\n return wrMirrorOffsets(\n FALLBACKS[placement].map(side => ({\n ...CONNECTED[side],\n offsetY: side === 'bottom' ? 12 : side === 'top' ? -12 : 0,\n offsetX: side === 'right' ? 12 : side === 'left' ? -12 : 0,\n })),\n isRtl\n );\n }\n\n private placeSpotlight(target: HTMLElement): void {\n const el = this.spotlight;\n if (!el) return;\n const r = target.getBoundingClientRect();\n const pad = 6;\n el.style.top = `${r.top - pad}px`;\n el.style.left = `${r.left - pad}px`;\n el.style.width = `${r.width + pad * 2}px`;\n el.style.height = `${r.height + pad * 2}px`;\n }\n\n private teardownStep(): void {\n this.focusTrap?.destroy();\n this.focusTrap = null;\n this.detachKeydown?.();\n this.detachKeydown = null;\n this.detachReposition?.();\n this.detachReposition = null;\n this.overlayRef?.dispose();\n this.overlayRef = null;\n this.spotlight?.remove();\n this.spotlight = null;\n }\n\n /**\n * Whether the app reads right-to-left.\n *\n * Optional inject: `Directionality` is root-provided, so this is never null in\n * an app — but a bare `TestBed` that provides nothing should still get a\n * component that works, and defaulting to LTR is the honest fallback.\n */\n private isRtl(): boolean {\n return this.dir?.value === 'rtl';\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-tour.mjs","sources":["../../../projects/lib/tour/tour-popup.ts","../../../projects/lib/tour/tour-popup.html","../../../projects/lib/tour/tour.ts","../../../projects/lib/tour/ngwr-tour.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Component, InjectionToken, ViewEncapsulation, computed, inject } from '@angular/core';\n\nimport { WrButton } from 'ngwr/button';\nimport { readI18nText, useI18nFormatter } from 'ngwr/i18n';\n\nimport type { WrTourStep } from './interfaces';\n\n/** What the popup needs from the running tour, without importing the service (cycle). */\nexport interface WrTourController {\n readonly index: () => number;\n readonly total: () => number;\n readonly step: () => WrTourStep | null;\n /**\n * Whether this is the last step the user will actually see — the service looks\n * ahead for a reachable one, because a trailing step whose target is missing gets\n * skipped and the raw count would call the final card \"Next\".\n */\n readonly isLast: () => boolean;\n /**\n * Whether this is the first step the user will actually see — the service looks\n * BEHIND for a reachable one, for the mirror reason: a leading step whose target\n * is missing gets skipped, so the tour opens on a later index and the raw one\n * would put a Back button on the very first card.\n */\n readonly isFirst: () => boolean;\n next(): void;\n prev(): void;\n stop(): void;\n}\n\n/** Provided by `WrTour` when it attaches the popup portal. */\nexport const WR_TOUR_STEP = new InjectionToken<WrTourController>('WR_TOUR_STEP');\n\n/**\n * The card a tour shows next to the spotlit element. Rendered by `WrTour` into\n * a CDK overlay — not something you place yourself.\n *\n * @see https://ngwr.dev/reference/services/tour\n */\n@Component({\n selector: 'wr-tour-popup',\n templateUrl: './tour-popup.html',\n encapsulation: ViewEncapsulation.None,\n host: { class: 'wr-tour-popup', role: 'dialog', 'aria-modal': 'true', '[attr.aria-label]': 'ariaLabel()' },\n imports: [WrButton],\n})\nexport class WrTourPopup {\n protected readonly tour = inject(WR_TOUR_STEP);\n\n // `readI18nText`, not `useI18nText`: these have no consumer-facing input to\n // forward. Both helpers are reactive.\n protected readonly nextLabel = readI18nText('tour.next', 'Next');\n protected readonly backLabel = readI18nText('tour.back', 'Back');\n protected readonly doneLabel = readI18nText('tour.done', 'Done');\n protected readonly skipLabel = readI18nText('tour.skip', 'Skip tour');\n\n /** `Step {{current}} of {{total}}` — also the dialog's accessible name. */\n protected readonly progress = useI18nFormatter('tour.progress', 'Step {{current}} of {{total}}');\n\n // From the service, not `index() >= total() - 1`: a trailing step whose target is\n // missing gets skipped, so the raw count called the final card \"Next\" and then\n // ended the tour when it was pressed.\n protected readonly isLast = computed(() => this.tour.isLast());\n // Same story at the other end, and the same fix: `index() <= 0` rendered a Back\n // button on the first card of a tour whose leading step had been skipped, and\n // `prev()` walks off the start and returns — so the button did nothing at all.\n protected readonly isFirst = computed(() => this.tour.isFirst());\n\n protected readonly progressText = computed(() =>\n this.progress({ current: this.tour.index() + 1, total: this.tour.total() })\n );\n\n protected readonly ariaLabel = computed(() => {\n const title = this.tour.step()?.title;\n return title ? `${title} — ${this.progressText()}` : this.progressText();\n });\n}\n","@let step = tour.step();\n\n<p class=\"wr-tour-popup__progress\">{{ progressText() }}</p>\n\n@if (step?.title; as title) {\n <h2 class=\"wr-tour-popup__title\">{{ title }}</h2>\n}\n\n<p class=\"wr-tour-popup__content\">{{ step?.content }}</p>\n\n<div class=\"wr-tour-popup__actions\">\n <!-- The three buttons are told apart by a class rather than by their position in\n the row: the back button is conditional, so an index means one thing on the\n first step and another everywhere else — and the labels are translated. -->\n <button\n wr-btn\n type=\"button\"\n size=\"sm\"\n color=\"medium\"\n outlined\n class=\"wr-tour-popup__action wr-tour-popup__action--skip\"\n (click)=\"tour.stop()\"\n >\n {{ skipLabel() }}\n </button>\n\n <span class=\"wr-tour-popup__spacer\"></span>\n\n @if (!isFirst()) {\n <button\n wr-btn\n type=\"button\"\n size=\"sm\"\n outlined\n class=\"wr-tour-popup__action wr-tour-popup__action--back\"\n (click)=\"tour.prev()\"\n >\n {{ backLabel() }}\n </button>\n }\n <button\n wr-btn\n type=\"button\"\n size=\"sm\"\n color=\"primary\"\n class=\"wr-tour-popup__action wr-tour-popup__action--next\"\n (click)=\"tour.next()\"\n >\n {{ isLast() ? doneLabel() : nextLabel() }}\n </button>\n</div>\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { type ConfigurableFocusTrap, ConfigurableFocusTrapFactory } from '@angular/cdk/a11y';\nimport { Directionality } from '@angular/cdk/bidi';\nimport { type ConnectedPosition, type OverlayRef, ScrollStrategyOptions } from '@angular/cdk/overlay';\nimport { ComponentPortal } from '@angular/cdk/portal';\nimport { isPlatformBrowser } from '@angular/common';\nimport {\n DOCUMENT,\n DestroyRef,\n EnvironmentInjector,\n Injector,\n PLATFORM_ID,\n Service,\n computed,\n inject,\n signal,\n} from '@angular/core';\n\nimport { WR_OVERLAY, wrFollowDirection, wrMirrorOffsets } from 'ngwr/overlay';\n\nimport type { WrTourPlacement, WrTourStep } from './interfaces';\nimport { WR_TOUR_STEP, WrTourPopup } from './tour-popup';\n\n/** Fallback order per preferred side — the opposite side first, then the sides. */\nconst FALLBACKS: Record<WrTourPlacement, readonly WrTourPlacement[]> = {\n bottom: ['bottom', 'top', 'right', 'left'],\n top: ['top', 'bottom', 'right', 'left'],\n left: ['left', 'right', 'bottom', 'top'],\n right: ['right', 'left', 'bottom', 'top'],\n};\n\nconst CONNECTED: Record<\n WrTourPlacement,\n {\n originX: 'start' | 'center' | 'end';\n originY: 'top' | 'center' | 'bottom';\n overlayX: 'start' | 'center' | 'end';\n overlayY: 'top' | 'center' | 'bottom';\n }\n> = {\n bottom: { originX: 'center', originY: 'bottom', overlayX: 'center', overlayY: 'top' },\n top: { originX: 'center', originY: 'top', overlayX: 'center', overlayY: 'bottom' },\n left: { originX: 'start', originY: 'center', overlayX: 'end', overlayY: 'center' },\n right: { originX: 'end', originY: 'center', overlayX: 'start', overlayY: 'center' },\n};\n\n/**\n * Guided product tour: a spotlight over one element at a time plus a popup\n * explaining it.\n *\n * Steps are data, not markup — call `start()` with an array and the service owns\n * the overlay, the cut-out, focus and the keyboard. A step whose target is not\n * on the page is skipped rather than shown floating, so a tour survives a\n * feature being hidden behind a flag or a permission.\n *\n * @example\n * ```ts\n * private readonly tour = inject(WrTour);\n *\n * showMeAround(): void {\n * this.tour.start([\n * { target: '[data-tour=\"search\"]', title: 'Search', content: 'Find anything by name.' },\n * { target: '[data-tour=\"filters\"]', content: 'Narrow the list down.', placement: 'right' },\n * ]);\n * }\n * ```\n *\n * @see https://ngwr.dev/reference/services/tour\n */\n@Service()\nexport class WrTour {\n private readonly overlay = inject(WR_OVERLAY);\n private readonly dir = inject(Directionality, { optional: true });\n private readonly scrollStrategies = inject(ScrollStrategyOptions);\n private readonly injector = inject(EnvironmentInjector);\n private readonly focusTrapFactory = inject(ConfigurableFocusTrapFactory);\n private readonly document = inject(DOCUMENT);\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n private readonly steps = signal<readonly WrTourStep[]>([]);\n private readonly cursor = signal(-1);\n\n private overlayRef: OverlayRef | null = null;\n private focusTrap: ConfigurableFocusTrap | null = null;\n private spotlight: HTMLElement | null = null;\n private detachKeydown: (() => void) | null = null;\n private detachReposition: (() => void) | null = null;\n private restoreFocus: HTMLElement | null = null;\n\n /** Whether a tour is running. */\n readonly active = computed(() => this.cursor() >= 0);\n\n /** Zero-based index of the current step, `-1` when idle. */\n readonly index = computed(() => this.cursor());\n\n /** How many steps this tour has. */\n readonly total = computed(() => this.steps().length);\n\n /** The step being shown, or `null` when idle. */\n readonly step = computed<WrTourStep | null>(() => this.steps()[this.cursor()] ?? null);\n\n // Whether any step AFTER the current one can actually be shown. Settled once per\n // move, in `goTo`, because reachability is a DOM question and not a signal.\n private readonly noStepAfter = signal(false);\n\n // The same question looking the other way. Settled in `goTo` for the same reason.\n private readonly noStepBefore = signal(true);\n\n /**\n * Whether this is the last step the user will see. Not `index() === total() - 1`:\n * a trailing step whose target is missing is skipped, so comparing against the\n * raw count left the primary button reading \"Next\" on the final card and then\n * ending the tour when it was pressed.\n */\n readonly isLast = computed(() => this.noStepAfter());\n\n /**\n * Whether this is the first step the user will see. Not `index() === 0`, for the\n * mirror of the reason above: a LEADING step whose target is missing is skipped,\n * so the tour opens on a later index and the raw one put a Back button on the\n * first card — one that did nothing at all, because `prev()` walks off the start\n * and returns without moving.\n */\n readonly isFirst = computed(() => this.noStepBefore());\n\n constructor() {\n // Everything this service owns lives OUTSIDE its own injector: a CDK overlay, a\n // div appended to `document.body`, a document keydown listener and two window\n // listeners. Nothing removes them when the injector goes, so a tour running at\n // teardown left its cut-out on the page.\n inject(DestroyRef).onDestroy(() => this.stop());\n }\n\n /**\n * Begin a tour. Restarts if one is already running. A no-op under SSR — a\n * tour is a client-side affordance and there is nothing to spotlight on the\n * server.\n */\n start(steps: readonly WrTourStep[]): void {\n if (!this.isBrowser || steps.length === 0) return;\n this.stop();\n this.steps.set(steps);\n this.restoreFocus = this.document.activeElement as HTMLElement | null;\n this.goTo(0, 1);\n }\n\n /** Advance; finishes the tour past the last step. */\n next(): void {\n this.goTo(this.cursor() + 1, 1);\n }\n\n /** Go back; stays put on the first step. */\n prev(): void {\n this.goTo(this.cursor() - 1, -1);\n }\n\n /** End the tour and return focus where it was. */\n stop(): void {\n this.teardownStep();\n this.steps.set([]);\n this.cursor.set(-1);\n this.restoreFocus?.focus?.();\n this.restoreFocus = null;\n }\n\n /**\n * Move to `index`, skipping steps whose target is not in the DOM. `direction`\n * says which way to keep skipping, so a missing step never traps the tour\n * between two dead ends.\n */\n private goTo(index: number, direction: 1 | -1): void {\n const steps = this.steps();\n let i = index;\n while (i >= 0 && i < steps.length && this.resolve(steps[i]) === null) i += direction;\n\n if (i < 0) {\n // Ran off the start while going back — stay where we were.\n return;\n }\n if (i >= steps.length) {\n this.stop();\n return;\n }\n\n this.teardownStep();\n this.cursor.set(i);\n this.noStepAfter.set(!this.anyResolvableAfter(i));\n this.noStepBefore.set(!this.anyResolvableBefore(i));\n this.openStep(steps[i]);\n }\n\n /** Whether the tour has a step past `index` that can actually be shown. */\n private anyResolvableAfter(index: number): boolean {\n const steps = this.steps();\n for (let i = index + 1; i < steps.length; i += 1) {\n if (this.resolve(steps[i]) !== null) return true;\n }\n return false;\n }\n\n /** Whether the tour has a step before `index` that can actually be shown. */\n private anyResolvableBefore(index: number): boolean {\n const steps = this.steps();\n for (let i = index - 1; i >= 0; i -= 1) {\n if (this.resolve(steps[i]) !== null) return true;\n }\n return false;\n }\n\n private resolve(step: WrTourStep): HTMLElement | null {\n if (typeof step.target !== 'string') return step.target.isConnected ? step.target : null;\n return this.document.querySelector<HTMLElement>(step.target);\n }\n\n private openStep(step: WrTourStep): void {\n const target = this.resolve(step);\n if (!target) return;\n\n target.scrollIntoView({ block: 'center', inline: 'nearest', behavior: 'smooth' });\n\n // The cut-out is a bare element sized to the target with an enormous spread\n // shadow: everything outside it dims, the target itself stays untouched.\n // Cheaper and far more robust than a clip-path polygon, and it needs no\n // recompute when the page reflows beyond moving the box.\n const spotlight = this.document.createElement('div');\n spotlight.className = 'wr-tour__spotlight';\n spotlight.setAttribute('aria-hidden', 'true');\n this.document.body.appendChild(spotlight);\n this.spotlight = spotlight;\n this.placeSpotlight(target);\n\n const placement = step.placement ?? 'bottom';\n const positionStrategy = this.overlay\n .position()\n .flexibleConnectedTo(target)\n .withPositions(this.stepPositions(placement, this.isRtl()))\n .withPush(true);\n\n this.overlayRef = this.overlay.create({\n positionStrategy,\n scrollStrategy: this.scrollStrategies.reposition(),\n panelClass: 'wr-tour-overlay',\n });\n\n // The CDK read the direction once, just now. A tour is long-lived by nature\n // — a step can sit on screen while the user changes a language setting — and\n // without this the card keeps the direction the step opened in, with the\n // 12px gap that held it clear of the spotlight now pointing into it.\n // Per step, because every move disposes this ref and builds the next.\n wrFollowDirection(this.overlayRef, this.dir, this.injector, direction =>\n positionStrategy.withPositions(this.stepPositions(placement, direction === 'rtl'))\n );\n\n const portal = new ComponentPortal(\n WrTourPopup,\n null,\n Injector.create({ parent: this.injector, providers: [{ provide: WR_TOUR_STEP, useValue: this }] })\n );\n const ref = this.overlayRef.attach(portal);\n\n // Kept on the instance, not in a local: a trap registers with CDK's\n // `FocusTrapManager` and installs a capture-phase document focus listener, so an\n // undestroyed one leaks per STEP and every tour left a stack of them behind.\n this.focusTrap = this.focusTrapFactory.create(ref.location.nativeElement as HTMLElement);\n void this.focusTrap.focusInitialElementWhenReady();\n\n const onKey = (event: KeyboardEvent): void => {\n // The listener is on the document, so a step shown over a dialog would see the\n // Escape that dialog just handled and close the tour too.\n if (event.key === 'Escape' && !event.defaultPrevented) {\n event.preventDefault();\n this.stop();\n }\n };\n this.document.addEventListener('keydown', onKey);\n this.detachKeydown = () => this.document.removeEventListener('keydown', onKey);\n\n const reposition = (): void => this.placeSpotlight(target);\n window.addEventListener('scroll', reposition, true);\n window.addEventListener('resize', reposition);\n this.detachReposition = () => {\n window.removeEventListener('scroll', reposition, true);\n window.removeEventListener('resize', reposition);\n };\n }\n\n /**\n * The card's fallback table for one placement, with its inline offsets already\n * mirrored. Built per call rather than per step: the direction can change while\n * the step is on screen, and a table is what has to be rebuilt when it does.\n */\n private stepPositions(placement: WrTourPlacement, isRtl: boolean): ConnectedPosition[] {\n return wrMirrorOffsets(\n FALLBACKS[placement].map(side => ({\n ...CONNECTED[side],\n offsetY: side === 'bottom' ? 12 : side === 'top' ? -12 : 0,\n offsetX: side === 'right' ? 12 : side === 'left' ? -12 : 0,\n })),\n isRtl\n );\n }\n\n private placeSpotlight(target: HTMLElement): void {\n const el = this.spotlight;\n if (!el) return;\n const r = target.getBoundingClientRect();\n const pad = 6;\n el.style.top = `${r.top - pad}px`;\n el.style.left = `${r.left - pad}px`;\n el.style.width = `${r.width + pad * 2}px`;\n el.style.height = `${r.height + pad * 2}px`;\n }\n\n private teardownStep(): void {\n this.focusTrap?.destroy();\n this.focusTrap = null;\n this.detachKeydown?.();\n this.detachKeydown = null;\n this.detachReposition?.();\n this.detachReposition = null;\n this.overlayRef?.dispose();\n this.overlayRef = null;\n this.spotlight?.remove();\n this.spotlight = null;\n }\n\n /**\n * Whether the app reads right-to-left.\n *\n * Optional inject: `Directionality` is root-provided, so this is never null in\n * an app — but a bare `TestBed` that provides nothing should still get a\n * component that works, and defaulting to LTR is the honest fallback.\n */\n private isRtl(): boolean {\n return this.dir?.value === 'rtl';\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ngwr-transfer-testing.mjs","sources":["../../../projects/lib/transfer/testing/wr-transfer-item-harness.ts","../../../projects/lib/transfer/testing/wr-transfer-pane-harness.ts","../../../projects/lib/transfer/testing/wr-transfer-harness.ts","../../../projects/lib/transfer/testing/ngwr-transfer-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 { WrTransferItemHarnessFilters } from './interfaces';\n\n/**\n * Test harness for one row of a `<wr-transfer>` pane.\n *\n * A row is a `<li>` holding a `<wr-checkbox>`, and the checkbox is the thing the\n * user operates — so the state is read from the native `<input type=\"checkbox\">`\n * inside it, and {@link toggle} clicks that. The pane is deliberately NOT a\n * `role=\"listbox\"` of `role=\"option\"` rows (an option may not contain an\n * interactive control, and the axe gate says so), which is why there is no\n * `aria-selected` here to read: the checkbox's own state IS the announcement.\n *\n * **Checked is not the value.** A tick stages the row for the next move and\n * nothing more; which pane the row sits in is what `[(value)]` carries. Staging is\n * spent — and cleared — by the move that commits it.\n *\n * @example\n * ```ts\n * const source = await transfer.getPane('source');\n * await (await source.getItem({ label: 'Read' })).check();\n *\n * await transfer.moveTo('target');\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrTransferItemHarness extends ComponentHarness {\n /**\n * `.wr-transfer__item` is a DATA row and nothing else.\n *\n * An empty pane renders an `<li class=\"wr-transfer__empty\">` for its placeholder,\n * so querying `li` would hand that back as a row with no checkbox to read.\n */\n static hostSelector = '.wr-transfer__item';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrTransferItemHarnessFilters = {}): HarnessPredicate<WrTransferItemHarness> {\n return new HarnessPredicate(WrTransferItemHarness, options)\n .addOption('label', options.label, (harness, label) => HarnessPredicate.stringMatches(harness.getLabel(), label))\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-checkbox__input');\n\n /** The row's label, trimmed — the `WrTransferItem.label` the pane shows and the search matches. */\n async getLabel(): Promise<string> {\n return (await this.locatorFor('.wr-checkbox__text')()).text();\n }\n\n /**\n * Whether the row is STAGED for the next move.\n *\n * Not \"selected\": a row's pane is what the value says, and the tick is transient\n * staging the move spends. `WrTransferPaneHarness.getCheckedLabels()` reads the\n * whole staged set of a pane.\n */\n async isChecked(): Promise<boolean> {\n return (await this.input()).getProperty<boolean>('checked');\n }\n\n /**\n * Whether the row refuses staging.\n *\n * The native input's `disabled` — the state a screen reader is given and the one\n * that decides whether a click does anything. It answers `true` for BOTH reasons a\n * row can be inert: the item's own `disabled` flag, and a disabled transfer, which\n * disables every row. The `wr-transfer__item--disabled` modifier only marks the\n * first of those, so it is the narrower question and not the one that predicts\n * behaviour.\n */\n async isDisabled(): Promise<boolean> {\n return (await this.input()).getProperty<boolean>('disabled');\n }\n\n /**\n * Flip the row's staging.\n *\n * Refuses a disabled row rather than clicking into the void: the component drops\n * the toggle outright, so the click would resolve having changed nothing and the\n * failure would surface as an unexplained empty move two assertions later.\n */\n async toggle(): Promise<void> {\n if (await this.isDisabled()) {\n const label = await this.getLabel();\n throw new Error(\n `WrTransferItemHarness.toggle(): \"${label}\" is disabled and the component refuses to stage it. ` +\n 'Either the item carries `disabled`, or the whole transfer does — check isDisabled() on the transfer too.'\n );\n }\n await (await this.input()).click();\n }\n\n /** Stage the row if it is not already staged. */\n async check(): Promise<void> {\n if (!(await this.isChecked())) await this.toggle();\n }\n\n /** Unstage the row if it is staged. */\n async uncheck(): Promise<void> {\n if (await this.isChecked()) await this.toggle();\n }\n\n /** Move keyboard focus onto the row's checkbox — the row's only tab stop. */\n async focus(): Promise<void> {\n return (await this.input()).focus();\n }\n\n /** Whether the row's checkbox has focus. */\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, type TestElement } from '@angular/cdk/testing';\n\nimport type { WrTransferItemHarnessFilters, WrTransferPaneHarnessFilters, WrTransferSide } from './interfaces';\nimport { WrTransferItemHarness } from './wr-transfer-item-harness';\n\n/**\n * Test harness for ONE pane of a `<wr-transfer>` — reached with\n * `WrTransferHarness.getPane('source' | 'target')`.\n *\n * The two panes are the same block rendered twice (the component's template\n * iterates them), so they are one harness class keyed by side rather than two sets\n * of `…Source` / `…Target` methods: the side is named once, at `getPane()`, and\n * every question after that is asked of a pane without repeating which one. It also\n * means the symmetry cannot rot — a method that only works on the left is\n * impossible to write here.\n *\n * What a pane SHOWS is the honest scope of everything below. `[items]` minus the\n * value on the left, the value on the right, and then the pane's own filter on top:\n * rows a filter has hidden are not rendered at all, are not counted by the header,\n * and — the component's own rule — are not moved either, however they were staged.\n *\n * @example\n * ```ts\n * const source = await transfer.getPane('source');\n *\n * await source.search('adm');\n * await source.checkAll();\n * expect(await source.getCheckedLabels()).toEqual(['Admin']);\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrTransferPaneHarness extends ComponentHarness {\n /**\n * The pane is a plain `<div>` with no role of its own — the heading names the\n * list, and the checkbox in each row carries the semantics — so its BEM class is\n * the only handle, and being `ViewEncapsulation.None` that class is public API.\n */\n static hostSelector = '.wr-transfer__pane';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrTransferPaneHarnessFilters = {}): HarnessPredicate<WrTransferPaneHarness> {\n return new HarnessPredicate(WrTransferPaneHarness, options)\n .addOption('side', options.side, async (harness, side) => (await harness.getSide()) === side)\n .addOption('title', options.title, (harness, title) => HarnessPredicate.stringMatches(harness.getTitle(), title));\n }\n\n private readonly list = this.locatorFor('ul.wr-transfer__list');\n private readonly selectAllBox = this.locatorFor('.wr-transfer__head input.wr-checkbox__input');\n private readonly searchBox = this.locatorForOptional('.wr-transfer__search input');\n\n /**\n * Which side this pane is.\n *\n * From the `--target` modifier rather than from DOM order: order is a layout fact\n * that `dir=\"rtl\"` and any future reflow are free to change, while the modifier is\n * what the component says the pane MEANS.\n */\n async getSide(): Promise<WrTransferSide> {\n return (await (await this.host()).hasClass('wr-transfer__pane--target')) ? 'target' : 'source';\n }\n\n /** The pane's heading — `[sourceTitle]` / `[targetTitle]`, or the i18n fallback. */\n async getTitle(): Promise<string> {\n return (await this.locatorFor('.wr-transfer__title')()).text();\n }\n\n /**\n * The count beside the heading, verbatim — `'1 / 4'` with the built-in copy.\n *\n * Deliberately not parsed into numbers: it is an i18n FORMAT\n * (`transfer.count`) a consuming app can replace wholesale, so a harness that\n * split it on `/` would answer for the default catalog and break on a translated\n * one. Its two numbers are `(await getCheckedLabels()).length` and\n * `(await getItems()).length` — both of which this harness reads from the rendered\n * rows, so a spec can assert the header agrees with them.\n */\n async getCountText(): Promise<string> {\n return (await this.locatorFor('.wr-transfer__count')()).text();\n }\n\n /**\n * The list's accessible name — the `aria-label` on the `<ul>`, which repeats the\n * heading so that a row announced in isolation still says which pane it is in.\n */\n async getListLabel(): Promise<string | null> {\n return (await this.list()).getAttribute('aria-label');\n }\n\n /**\n * The explicit `role` on the pane's list, which is `null` — and that `null` is the\n * ANSWER, not a gap worth fixing.\n *\n * The pane is a plain `<ul>` of checkboxes on purpose. Dressing it as a\n * `role=\"listbox\"` of `role=\"option\"` rows reads better in the abstract but is\n * invalid: an option may not contain an interactive control, and the axe gate\n * rejects it. Pinning this is what keeps that \"improvement\" from looking like a\n * win.\n */\n async getListRole(): Promise<string | null> {\n return (await this.list()).getAttribute('role');\n }\n\n /** The rows the pane is showing, in render order. */\n async getItems(filters: WrTransferItemHarnessFilters = {}): Promise<WrTransferItemHarness[]> {\n return this.locatorForAll(WrTransferItemHarness.with(filters))();\n }\n\n /**\n * The labels the pane is showing, in render order.\n *\n * On the right that is the value, in the order the user built it — not `[items]`\n * order, which the component deliberately does not impose.\n */\n async getItemLabels(): Promise<string[]> {\n const items = await this.getItems();\n return Promise.all(items.map(item => item.getLabel()));\n }\n\n /** The first row matching the filters, or a failure that says what the pane is showing. */\n async getItem(filters: WrTransferItemHarnessFilters): Promise<WrTransferItemHarness> {\n const [item] = await this.getItems(filters);\n if (!item) {\n const showing = await this.getItemLabels();\n const side = await this.getSide();\n throw new Error(\n `WrTransferPaneHarness.getItem(): no row matched ${JSON.stringify(filters)} in the ${side} pane, ` +\n `which is showing [${showing.join(', ')}]. A row in the other pane, or one this pane's search has ` +\n 'filtered out, is not here.'\n );\n }\n return item;\n }\n\n /**\n * The labels of the rows STAGED for the next move, in render order.\n *\n * The staged set and the value are different things, and this is the one the pane\n * shows: read from the rendered rows, so a row staged before a search hid it is\n * absent — exactly as the header count and the move itself treat it.\n */\n async getCheckedLabels(): Promise<string[]> {\n const items = await this.getItems({ checked: true });\n return Promise.all(items.map(item => item.getLabel()));\n }\n\n /** The placeholder shown in a pane with no rows, or `null` while it has some. */\n async getEmptyText(): Promise<string | null> {\n const empty = await this.locatorForOptional('.wr-transfer__empty')();\n return empty ? empty.text() : null;\n }\n\n /** Whether this pane has a filter box — `[searchable]` puts one above both panes. */\n async hasSearch(): Promise<boolean> {\n return (await this.searchBox()) !== null;\n }\n\n /**\n * Type into the pane's filter box, narrowing it to the rows whose label contains\n * the query (case-insensitively).\n *\n * Pass `''` to clear it. No `change` is dispatched — `input` is the event the\n * component listens for, and the one a real keystroke carries; a browser defers\n * `change` on a text field to the commit, so nothing here depends on it. (The\n * keystrokes themselves come with the `keydown` / `keypress` / `keyup` the CDK\n * sends alongside, which this component ignores.)\n */\n async search(query: string): Promise<void> {\n const box = await this.searchBox();\n if (!box) {\n throw new Error(\n `WrTransferPaneHarness.search(): the ${await this.getSide()} pane has no filter box — ` +\n '`searchable` is off on the transfer, and it turns them on for both panes at once.'\n );\n }\n\n // `clear()` dispatches `input` on its own, and `sendKeys('')` throws, so an empty\n // query is the clear and nothing else.\n await box.clear();\n if (query.length > 0) await box.sendKeys(query);\n }\n\n /** What is currently typed in the pane's filter box, or `''`. Throws when there is none. */\n async getSearchValue(): Promise<string> {\n return (await this.searchOrThrow('getSearchValue')).getProperty<string>('value');\n }\n\n /** The filter box's placeholder — `[searchPlaceholder]`, or the i18n fallback. */\n async getSearchPlaceholder(): Promise<string> {\n return (await this.searchOrThrow('getSearchPlaceholder')).getProperty<string>('placeholder');\n }\n\n /**\n * The filter box's accessible name.\n *\n * Composed with the pane heading by the component, and it has to be: both panes\n * carry the same placeholder, so an unnamed pair announces as two identical\n * \"Search\" fields with no way to tell which list either one filters.\n */\n async getSearchLabel(): Promise<string | null> {\n return (await this.searchOrThrow('getSearchLabel')).getAttribute('aria-label');\n }\n\n /**\n * The select-all box's accessible name.\n *\n * It has one of its own — the heading names the LIST, so reusing it here would\n * leave a screen reader announcing two different controls identically.\n */\n async getSelectAllLabel(): Promise<string | null> {\n return (await this.selectAllBox()).getAttribute('aria-label');\n }\n\n /** Whether every row the pane is showing that CAN be staged is staged. */\n async isAllChecked(): Promise<boolean> {\n return (await this.selectAllBox()).getProperty<boolean>('checked');\n }\n\n /**\n * Whether some of the pane's stageable rows are staged and others are not.\n *\n * `indeterminate` is a DOM PROPERTY, not an attribute — reading the attribute\n * would report `null` for a box that is visibly dashed.\n */\n async isPartiallyChecked(): Promise<boolean> {\n return (await this.selectAllBox()).getProperty<boolean>('indeterminate');\n }\n\n /**\n * Whether the select-all box refuses interaction — a disabled transfer, or a pane\n * with nothing stageable in it (empty, filtered to nothing, or showing only\n * disabled rows).\n */\n async isSelectAllDisabled(): Promise<boolean> {\n return (await this.selectAllBox()).getProperty<boolean>('disabled');\n }\n\n /**\n * Click the select-all box once.\n *\n * Its scope is the rows the pane is SHOWING and can stage: a filtered-out row and\n * a disabled row are both outside it. Worth knowing before asserting on a partial\n * pane — the box reads UNchecked while the staging is partial, so one click there\n * stages everything rather than clearing it. {@link uncheckAll} handles that.\n */\n async toggleSelectAll(): Promise<void> {\n if (await this.isSelectAllDisabled()) {\n throw new Error(\n `WrTransferPaneHarness.toggleSelectAll(): the ${await this.getSide()} pane's select-all is disabled, ` +\n 'so the click would change nothing — the transfer is disabled, or this pane shows no row that can be ' +\n 'staged (empty, filtered to nothing, or every row disabled).'\n );\n }\n await (await this.selectAllBox()).click();\n }\n\n /** Stage every row the pane shows that can be staged. A pane already fully staged is left alone. */\n async checkAll(): Promise<void> {\n if (!(await this.isAllChecked())) await this.toggleSelectAll();\n }\n\n /** Clear the pane's staging. */\n async uncheckAll(): Promise<void> {\n if (await this.isAllChecked()) {\n await this.toggleSelectAll();\n return;\n }\n // Two clicks from a partial pane, and there is no shortcut: the box is UNchecked\n // there, so the first click stages the rest and only the second clears the lot.\n if (await this.isPartiallyChecked()) {\n await this.toggleSelectAll();\n await this.toggleSelectAll();\n }\n }\n\n /** The filter box, or a failure naming the input that turns it on. */\n private async searchOrThrow(method: string): Promise<TestElement> {\n const box = await this.searchBox();\n if (!box) {\n throw new Error(\n `WrTransferPaneHarness.${method}(): the ${await this.getSide()} pane has no filter box — ` +\n '`searchable` is off on the transfer.'\n );\n }\n return box;\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, type TestElement } from '@angular/cdk/testing';\n\nimport type { WrTransferHarnessFilters, WrTransferSide } from './interfaces';\nimport { WrTransferItemHarness } from './wr-transfer-item-harness';\nimport { WrTransferPaneHarness } from './wr-transfer-pane-harness';\n\n/**\n * Test harness for `<wr-transfer>` — the root of a small family, since a dual\n * listbox is three things and not one control: {@link WrTransferPaneHarness} for one\n * pane and {@link WrTransferItemHarness} for one row inside it.\n *\n * **Everything is keyed by SIDE, never duplicated per pane.** The two panes are the\n * same block rendered twice, so a `…Source` / `…Target` method pair for each\n * question would double the surface and let the halves drift; instead\n * {@link getPane} takes the side once and the pane answers, and the two whole-\n * control operations that are inherently directional — the move buttons — take the\n * side they move rows INTO. `moveTo('target')` is the right-facing button in an LTR\n * layout, and stays the correct one under `dir=\"rtl\"`, where \"right\" is not.\n *\n * **The staged ticks are not the value.** `[(value)]` is the RIGHT pane's\n * membership; a tick inside either pane is transient staging that the next move\n * spends and clears. Conflating them is the failure this component invites, so the\n * two are separate questions here: {@link WrTransferPaneHarness.getItemLabels} is\n * what a pane HOLDS (the value, on the right) and\n * {@link WrTransferPaneHarness.getCheckedLabels} is what it has STAGED.\n *\n * Both are scoped to what a pane is showing, which is also the component's own rule\n * for a move: a row staged before a search hid it is no longer counted, no longer\n * ticked, and does not travel.\n *\n * @example\n * ```ts\n * const transfer = await loader.getHarness(WrTransferHarness);\n * const source = await transfer.getPane('source');\n *\n * await (await source.getItem({ label: 'Read' })).check();\n * await transfer.moveTo('target');\n *\n * expect(await (await transfer.getPane('target')).getItemLabels()).toEqual(['Read']);\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrTransferHarness extends ComponentHarness {\n static hostSelector = 'wr-transfer';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrTransferHarnessFilters = {}): HarnessPredicate<WrTransferHarness> {\n return new HarnessPredicate(WrTransferHarness, options)\n .addOption('sourceTitle', options.sourceTitle, (harness, title) =>\n HarnessPredicate.stringMatches(harness.paneTitle('source'), title)\n )\n .addOption('targetTitle', options.targetTitle, (harness, title) =>\n HarnessPredicate.stringMatches(harness.paneTitle('target'), title)\n )\n .addOption('itemLabel', options.itemLabel, async (harness, label) => {\n for (const shown of await harness.shownLabels()) {\n if (await HarnessPredicate.stringMatches(shown, label)) return true;\n }\n return false;\n })\n .addOption(\n 'searchable',\n options.searchable,\n async (harness, searchable) => (await harness.isSearchable()) === searchable\n )\n .addOption('disabled', options.disabled, async (harness, disabled) => (await harness.isDisabled()) === disabled);\n }\n\n /**\n * One of the two panes — `'source'` is the left one (the rows outside the value),\n * `'target'` the right one (the value).\n *\n * The side is named here and nowhere else; see the class note.\n */\n async getPane(side: WrTransferSide): Promise<WrTransferPaneHarness> {\n return this.locatorFor(WrTransferPaneHarness.with({ side }))();\n }\n\n /**\n * Whether the whole control refuses interaction.\n *\n * From the host modifier, which is the only signal the host itself carries: a\n * `<wr-transfer>` element is not a control and publishes no `aria-disabled` of its\n * own — the state reaches assistive tech through the checkboxes, the buttons and\n * the filter boxes it disables, which is where\n * {@link WrTransferItemHarness.isDisabled} and {@link canMoveTo} read it.\n */\n async isDisabled(): Promise<boolean> {\n return (await this.host()).hasClass('wr-transfer--disabled');\n }\n\n /** Whether the panes have filter boxes — `[searchable]` gives both one or neither. */\n async isSearchable(): Promise<boolean> {\n return (await this.host()).hasClass('wr-transfer--searchable');\n }\n\n /**\n * Whether the button that moves rows INTO `side` is offering itself.\n *\n * It is enabled only while the OTHER pane has something staged and showing, so\n * this is also the readable way to assert that staging landed — and that a search\n * which hid a staged row took the move away again.\n *\n * Read from the native `disabled` attribute: these are `button[wr-btn]`, the\n * native shape, where that attribute is the state. (`wr-btn` adds `aria-disabled`\n * only for its custom-element shape, on which `disabled` is inert.)\n */\n async canMoveTo(side: WrTransferSide): Promise<boolean> {\n return (await (await this.moveButton(side)).getAttribute('disabled')) === null;\n }\n\n /**\n * The accessible name of the button that moves rows INTO `side` —\n * `[toTargetLabel]` / `[toSourceLabel]`, or the i18n fallback.\n *\n * Worth pinning: the button's only content is an `aria-hidden` chevron, so this\n * `aria-label` is the entire announcement. Lose it and the pair becomes two\n * unnamed buttons.\n */\n async getMoveLabel(side: WrTransferSide): Promise<string | null> {\n return (await this.moveButton(side)).getAttribute('aria-label');\n }\n\n /**\n * Press the button that moves the staged rows INTO `side`, committing them to the\n * value.\n *\n * Only the rows the other pane is SHOWING as staged travel, and the staging is\n * cleared afterwards — the component's rule, not this harness's.\n *\n * Refuses a disabled button rather than pressing it: a native disabled `<button>`\n * swallows the click before Angular's listener sees it, so the call would resolve\n * having moved nothing at all.\n */\n async moveTo(side: WrTransferSide): Promise<void> {\n if (!(await this.canMoveTo(side))) {\n const from: WrTransferSide = side === 'target' ? 'source' : 'target';\n throw new Error(\n `WrTransferHarness.moveTo('${side}'): the button is disabled, so nothing would move. The ${from} pane ` +\n 'has nothing staged and showing — a row staged before a search hid it no longer counts — or the whole ' +\n 'transfer is disabled.'\n );\n }\n await (await this.moveButton(side)).click();\n }\n\n /**\n * Stage everything the other pane can stage, then move it INTO `side`.\n *\n * \"Everything\" is the pane's own scope: the rows it is SHOWING, disabled ones\n * excluded. A search narrows it, and with a filter typed this moves what is\n * visible rather than the whole pane.\n */\n async moveAllTo(side: WrTransferSide): Promise<void> {\n const from = await this.getPane(side === 'target' ? 'source' : 'target');\n await from.checkAll();\n await this.moveTo(side);\n }\n\n /** The heading of one pane — the `sourceTitle` / `targetTitle` filters run through this. */\n private async paneTitle(side: WrTransferSide): Promise<string> {\n return (await this.getPane(side)).getTitle();\n }\n\n /** Every label rendered in either pane, for the `itemLabel` filter. */\n private async shownLabels(): Promise<string[]> {\n const items = await this.locatorForAll(WrTransferItemHarness)();\n return Promise.all(items.map(item => item.getLabel()));\n }\n\n /**\n * The move button for a direction, addressed by its `--to-source` / `--to-target`\n * modifier.\n *\n * Not by DOM order, and that is the point: two identically classed buttons whose\n * only difference was their position would let a template reshuffle silently\n * reverse every `moveTo()` in every consumer's suite, with both directions still\n * green. Not by the `aria-label` either — that string is localizable.\n */\n private async moveButton(side: WrTransferSide): Promise<TestElement> {\n return this.locatorFor(`.wr-transfer__move--to-${side}`)();\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-transfer-testing.mjs","sources":["../../../projects/lib/transfer/testing/wr-transfer-item-harness.ts","../../../projects/lib/transfer/testing/wr-transfer-pane-harness.ts","../../../projects/lib/transfer/testing/wr-transfer-harness.ts","../../../projects/lib/transfer/testing/ngwr-transfer-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 { WrTransferItemHarnessFilters } from './interfaces';\n\n/**\n * Test harness for one row of a `<wr-transfer>` pane.\n *\n * A row is a `<li>` holding a `<wr-checkbox>`, and the checkbox is the thing the\n * user operates — so the state is read from the native `<input type=\"checkbox\">`\n * inside it, and {@link toggle} clicks that. The pane is deliberately NOT a\n * `role=\"listbox\"` of `role=\"option\"` rows (an option may not contain an\n * interactive control, and the axe gate says so), which is why there is no\n * `aria-selected` here to read: the checkbox's own state IS the announcement.\n *\n * **Checked is not the value.** A tick stages the row for the next move and\n * nothing more; which pane the row sits in is what `[(value)]` carries. Staging is\n * spent — and cleared — by the move that commits it.\n *\n * @example\n * ```ts\n * const source = await transfer.getPane('source');\n * await (await source.getItem({ label: 'Read' })).check();\n *\n * await transfer.moveTo('target');\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrTransferItemHarness extends ComponentHarness {\n /**\n * `.wr-transfer__item` is a DATA row and nothing else.\n *\n * An empty pane renders an `<li class=\"wr-transfer__empty\">` for its placeholder,\n * so querying `li` would hand that back as a row with no checkbox to read.\n */\n static hostSelector = '.wr-transfer__item';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrTransferItemHarnessFilters = {}): HarnessPredicate<WrTransferItemHarness> {\n return new HarnessPredicate(WrTransferItemHarness, options)\n .addOption('label', options.label, (harness, label) => HarnessPredicate.stringMatches(harness.getLabel(), label))\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-checkbox__input');\n\n /** The row's label, trimmed — the `WrTransferItem.label` the pane shows and the search matches. */\n async getLabel(): Promise<string> {\n return (await this.locatorFor('.wr-checkbox__text')()).text();\n }\n\n /**\n * Whether the row is STAGED for the next move.\n *\n * Not \"selected\": a row's pane is what the value says, and the tick is transient\n * staging the move spends. `WrTransferPaneHarness.getCheckedLabels()` reads the\n * whole staged set of a pane.\n */\n async isChecked(): Promise<boolean> {\n return (await this.input()).getProperty<boolean>('checked');\n }\n\n /**\n * Whether the row refuses staging.\n *\n * The native input's `disabled` — the state a screen reader is given and the one\n * that decides whether a click does anything. It answers `true` for BOTH reasons a\n * row can be inert: the item's own `disabled` flag, and a disabled transfer, which\n * disables every row. The `wr-transfer__item--disabled` modifier only marks the\n * first of those, so it is the narrower question and not the one that predicts\n * behaviour.\n */\n async isDisabled(): Promise<boolean> {\n return (await this.input()).getProperty<boolean>('disabled');\n }\n\n /**\n * Flip the row's staging.\n *\n * Refuses a disabled row rather than clicking into the void: the component drops\n * the toggle outright, so the click would resolve having changed nothing and the\n * failure would surface as an unexplained empty move two assertions later.\n */\n async toggle(): Promise<void> {\n if (await this.isDisabled()) {\n const label = await this.getLabel();\n throw new Error(\n `WrTransferItemHarness.toggle(): \"${label}\" is disabled and the component refuses to stage it. ` +\n 'Either the item carries `disabled`, or the whole transfer does — check isDisabled() on the transfer too.'\n );\n }\n await (await this.input()).click();\n }\n\n /** Stage the row if it is not already staged. */\n async check(): Promise<void> {\n if (!(await this.isChecked())) await this.toggle();\n }\n\n /** Unstage the row if it is staged. */\n async uncheck(): Promise<void> {\n if (await this.isChecked()) await this.toggle();\n }\n\n /** Move keyboard focus onto the row's checkbox — the row's only tab stop. */\n async focus(): Promise<void> {\n return (await this.input()).focus();\n }\n\n /** Whether the row's checkbox has focus. */\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, type TestElement } from '@angular/cdk/testing';\n\nimport type { WrTransferItemHarnessFilters, WrTransferPaneHarnessFilters, WrTransferSide } from './interfaces';\nimport { WrTransferItemHarness } from './wr-transfer-item-harness';\n\n/**\n * Test harness for ONE pane of a `<wr-transfer>` — reached with\n * `WrTransferHarness.getPane('source' | 'target')`.\n *\n * The two panes are the same block rendered twice (the component's template\n * iterates them), so they are one harness class keyed by side rather than two sets\n * of `…Source` / `…Target` methods: the side is named once, at `getPane()`, and\n * every question after that is asked of a pane without repeating which one. It also\n * means the symmetry cannot rot — a method that only works on the left is\n * impossible to write here.\n *\n * What a pane SHOWS is the honest scope of everything below. `[items]` minus the\n * value on the left, the value on the right, and then the pane's own filter on top:\n * rows a filter has hidden are not rendered at all, are not counted by the header,\n * and — the component's own rule — are not moved either, however they were staged.\n *\n * @example\n * ```ts\n * const source = await transfer.getPane('source');\n *\n * await source.search('adm');\n * await source.checkAll();\n * expect(await source.getCheckedLabels()).toEqual(['Admin']);\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrTransferPaneHarness extends ComponentHarness {\n /**\n * The pane is a plain `<div>` with no role of its own — the heading names the\n * list, and the checkbox in each row carries the semantics — so its BEM class is\n * the only handle, and being `ViewEncapsulation.None` that class is public API.\n */\n static hostSelector = '.wr-transfer__pane';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrTransferPaneHarnessFilters = {}): HarnessPredicate<WrTransferPaneHarness> {\n return new HarnessPredicate(WrTransferPaneHarness, options)\n .addOption('side', options.side, async (harness, side) => (await harness.getSide()) === side)\n .addOption('title', options.title, (harness, title) => HarnessPredicate.stringMatches(harness.getTitle(), title));\n }\n\n private readonly list = this.locatorFor('ul.wr-transfer__list');\n private readonly selectAllBox = this.locatorFor('.wr-transfer__head input.wr-checkbox__input');\n private readonly searchBox = this.locatorForOptional('.wr-transfer__search input');\n\n /**\n * Which side this pane is.\n *\n * From the `--target` modifier rather than from DOM order: order is a layout fact\n * that `dir=\"rtl\"` and any future reflow are free to change, while the modifier is\n * what the component says the pane MEANS.\n */\n async getSide(): Promise<WrTransferSide> {\n return (await (await this.host()).hasClass('wr-transfer__pane--target')) ? 'target' : 'source';\n }\n\n /** The pane's heading — `[sourceTitle]` / `[targetTitle]`, or the i18n fallback. */\n async getTitle(): Promise<string> {\n return (await this.locatorFor('.wr-transfer__title')()).text();\n }\n\n /**\n * The count beside the heading, verbatim — `'1 / 4'` with the built-in copy.\n *\n * Deliberately not parsed into numbers: it is an i18n FORMAT\n * (`transfer.count`) a consuming app can replace wholesale, so a harness that\n * split it on `/` would answer for the default catalog and break on a translated\n * one. Its two numbers are `(await getCheckedLabels()).length` and\n * `(await getItems()).length` — both of which this harness reads from the rendered\n * rows, so a spec can assert the header agrees with them.\n */\n async getCountText(): Promise<string> {\n return (await this.locatorFor('.wr-transfer__count')()).text();\n }\n\n /**\n * The list's accessible name — the `aria-label` on the `<ul>`, which repeats the\n * heading so that a row announced in isolation still says which pane it is in.\n */\n async getListLabel(): Promise<string | null> {\n return (await this.list()).getAttribute('aria-label');\n }\n\n /**\n * The explicit `role` on the pane's list, which is `null` — and that `null` is the\n * ANSWER, not a gap worth fixing.\n *\n * The pane is a plain `<ul>` of checkboxes on purpose. Dressing it as a\n * `role=\"listbox\"` of `role=\"option\"` rows reads better in the abstract but is\n * invalid: an option may not contain an interactive control, and the axe gate\n * rejects it. Pinning this is what keeps that \"improvement\" from looking like a\n * win.\n */\n async getListRole(): Promise<string | null> {\n return (await this.list()).getAttribute('role');\n }\n\n /** The rows the pane is showing, in render order. */\n async getItems(filters: WrTransferItemHarnessFilters = {}): Promise<WrTransferItemHarness[]> {\n return this.locatorForAll(WrTransferItemHarness.with(filters))();\n }\n\n /**\n * The labels the pane is showing, in render order.\n *\n * On the right that is the value, in the order the user built it — not `[items]`\n * order, which the component deliberately does not impose.\n */\n async getItemLabels(): Promise<string[]> {\n const items = await this.getItems();\n return Promise.all(items.map(item => item.getLabel()));\n }\n\n /** The first row matching the filters, or a failure that says what the pane is showing. */\n async getItem(filters: WrTransferItemHarnessFilters): Promise<WrTransferItemHarness> {\n const [item] = await this.getItems(filters);\n if (!item) {\n const showing = await this.getItemLabels();\n const side = await this.getSide();\n throw new Error(\n `WrTransferPaneHarness.getItem(): no row matched ${JSON.stringify(filters)} in the ${side} pane, ` +\n `which is showing [${showing.join(', ')}]. A row in the other pane, or one this pane's search has ` +\n 'filtered out, is not here.'\n );\n }\n return item;\n }\n\n /**\n * The labels of the rows STAGED for the next move, in render order.\n *\n * The staged set and the value are different things, and this is the one the pane\n * shows: read from the rendered rows, so a row staged before a search hid it is\n * absent — exactly as the header count and the move itself treat it.\n */\n async getCheckedLabels(): Promise<string[]> {\n const items = await this.getItems({ checked: true });\n return Promise.all(items.map(item => item.getLabel()));\n }\n\n /** The placeholder shown in a pane with no rows, or `null` while it has some. */\n async getEmptyText(): Promise<string | null> {\n const empty = await this.locatorForOptional('.wr-transfer__empty')();\n return empty ? empty.text() : null;\n }\n\n /** Whether this pane has a filter box — `[searchable]` puts one above both panes. */\n async hasSearch(): Promise<boolean> {\n return (await this.searchBox()) !== null;\n }\n\n /**\n * Type into the pane's filter box, narrowing it to the rows whose label contains\n * the query (case-insensitively).\n *\n * Pass `''` to clear it. No `change` is dispatched — `input` is the event the\n * component listens for, and the one a real keystroke carries; a browser defers\n * `change` on a text field to the commit, so nothing here depends on it. (The\n * keystrokes themselves come with the `keydown` / `keypress` / `keyup` the CDK\n * sends alongside, which this component ignores.)\n */\n async search(query: string): Promise<void> {\n const box = await this.searchBox();\n if (!box) {\n throw new Error(\n `WrTransferPaneHarness.search(): the ${await this.getSide()} pane has no filter box — ` +\n '`searchable` is off on the transfer, and it turns them on for both panes at once.'\n );\n }\n\n // `clear()` dispatches `input` on its own, and `sendKeys('')` throws, so an empty\n // query is the clear and nothing else.\n await box.clear();\n if (query.length > 0) await box.sendKeys(query);\n }\n\n /** What is currently typed in the pane's filter box, or `''`. Throws when there is none. */\n async getSearchValue(): Promise<string> {\n return (await this.searchOrThrow('getSearchValue')).getProperty<string>('value');\n }\n\n /** The filter box's placeholder — `[searchPlaceholder]`, or the i18n fallback. */\n async getSearchPlaceholder(): Promise<string> {\n return (await this.searchOrThrow('getSearchPlaceholder')).getProperty<string>('placeholder');\n }\n\n /**\n * The filter box's accessible name.\n *\n * Composed with the pane heading by the component, and it has to be: both panes\n * carry the same placeholder, so an unnamed pair announces as two identical\n * \"Search\" fields with no way to tell which list either one filters.\n */\n async getSearchLabel(): Promise<string | null> {\n return (await this.searchOrThrow('getSearchLabel')).getAttribute('aria-label');\n }\n\n /**\n * The select-all box's accessible name.\n *\n * It has one of its own — the heading names the LIST, so reusing it here would\n * leave a screen reader announcing two different controls identically.\n */\n async getSelectAllLabel(): Promise<string | null> {\n return (await this.selectAllBox()).getAttribute('aria-label');\n }\n\n /** Whether every row the pane is showing that CAN be staged is staged. */\n async isAllChecked(): Promise<boolean> {\n return (await this.selectAllBox()).getProperty<boolean>('checked');\n }\n\n /**\n * Whether some of the pane's stageable rows are staged and others are not.\n *\n * `indeterminate` is a DOM PROPERTY, not an attribute — reading the attribute\n * would report `null` for a box that is visibly dashed.\n */\n async isPartiallyChecked(): Promise<boolean> {\n return (await this.selectAllBox()).getProperty<boolean>('indeterminate');\n }\n\n /**\n * Whether the select-all box refuses interaction — a disabled transfer, or a pane\n * with nothing stageable in it (empty, filtered to nothing, or showing only\n * disabled rows).\n */\n async isSelectAllDisabled(): Promise<boolean> {\n return (await this.selectAllBox()).getProperty<boolean>('disabled');\n }\n\n /**\n * Click the select-all box once.\n *\n * Its scope is the rows the pane is SHOWING and can stage: a filtered-out row and\n * a disabled row are both outside it. Worth knowing before asserting on a partial\n * pane — the box reads UNchecked while the staging is partial, so one click there\n * stages everything rather than clearing it. {@link uncheckAll} handles that.\n */\n async toggleSelectAll(): Promise<void> {\n if (await this.isSelectAllDisabled()) {\n throw new Error(\n `WrTransferPaneHarness.toggleSelectAll(): the ${await this.getSide()} pane's select-all is disabled, ` +\n 'so the click would change nothing — the transfer is disabled, or this pane shows no row that can be ' +\n 'staged (empty, filtered to nothing, or every row disabled).'\n );\n }\n await (await this.selectAllBox()).click();\n }\n\n /** Stage every row the pane shows that can be staged. A pane already fully staged is left alone. */\n async checkAll(): Promise<void> {\n if (!(await this.isAllChecked())) await this.toggleSelectAll();\n }\n\n /** Clear the pane's staging. */\n async uncheckAll(): Promise<void> {\n if (await this.isAllChecked()) {\n await this.toggleSelectAll();\n return;\n }\n // Two clicks from a partial pane, and there is no shortcut: the box is UNchecked\n // there, so the first click stages the rest and only the second clears the lot.\n if (await this.isPartiallyChecked()) {\n await this.toggleSelectAll();\n await this.toggleSelectAll();\n }\n }\n\n /** The filter box, or a failure naming the input that turns it on. */\n private async searchOrThrow(method: string): Promise<TestElement> {\n const box = await this.searchBox();\n if (!box) {\n throw new Error(\n `WrTransferPaneHarness.${method}(): the ${await this.getSide()} pane has no filter box — ` +\n '`searchable` is off on the transfer.'\n );\n }\n return box;\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, type TestElement } from '@angular/cdk/testing';\n\nimport type { WrTransferHarnessFilters, WrTransferSide } from './interfaces';\nimport { WrTransferItemHarness } from './wr-transfer-item-harness';\nimport { WrTransferPaneHarness } from './wr-transfer-pane-harness';\n\n/**\n * Test harness for `<wr-transfer>` — the root of a small family, since a dual\n * listbox is three things and not one control: {@link WrTransferPaneHarness} for one\n * pane and {@link WrTransferItemHarness} for one row inside it.\n *\n * **Everything is keyed by SIDE, never duplicated per pane.** The two panes are the\n * same block rendered twice, so a `…Source` / `…Target` method pair for each\n * question would double the surface and let the halves drift; instead\n * {@link getPane} takes the side once and the pane answers, and the two whole-\n * control operations that are inherently directional — the move buttons — take the\n * side they move rows INTO. `moveTo('target')` is the right-facing button in an LTR\n * layout, and stays the correct one under `dir=\"rtl\"`, where \"right\" is not.\n *\n * **The staged ticks are not the value.** `[(value)]` is the RIGHT pane's\n * membership; a tick inside either pane is transient staging that the next move\n * spends and clears. Conflating them is the failure this component invites, so the\n * two are separate questions here: {@link WrTransferPaneHarness.getItemLabels} is\n * what a pane HOLDS (the value, on the right) and\n * {@link WrTransferPaneHarness.getCheckedLabels} is what it has STAGED.\n *\n * Both are scoped to what a pane is showing, which is also the component's own rule\n * for a move: a row staged before a search hid it is no longer counted, no longer\n * ticked, and does not travel.\n *\n * @example\n * ```ts\n * const transfer = await loader.getHarness(WrTransferHarness);\n * const source = await transfer.getPane('source');\n *\n * await (await source.getItem({ label: 'Read' })).check();\n * await transfer.moveTo('target');\n *\n * expect(await (await transfer.getPane('target')).getItemLabels()).toEqual(['Read']);\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrTransferHarness extends ComponentHarness {\n static hostSelector = 'wr-transfer';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrTransferHarnessFilters = {}): HarnessPredicate<WrTransferHarness> {\n return new HarnessPredicate(WrTransferHarness, options)\n .addOption('sourceTitle', options.sourceTitle, (harness, title) =>\n HarnessPredicate.stringMatches(harness.paneTitle('source'), title)\n )\n .addOption('targetTitle', options.targetTitle, (harness, title) =>\n HarnessPredicate.stringMatches(harness.paneTitle('target'), title)\n )\n .addOption('itemLabel', options.itemLabel, async (harness, label) => {\n for (const shown of await harness.shownLabels()) {\n if (await HarnessPredicate.stringMatches(shown, label)) return true;\n }\n return false;\n })\n .addOption(\n 'searchable',\n options.searchable,\n async (harness, searchable) => (await harness.isSearchable()) === searchable\n )\n .addOption('disabled', options.disabled, async (harness, disabled) => (await harness.isDisabled()) === disabled);\n }\n\n /**\n * One of the two panes — `'source'` is the left one (the rows outside the value),\n * `'target'` the right one (the value).\n *\n * The side is named here and nowhere else; see the class note.\n */\n async getPane(side: WrTransferSide): Promise<WrTransferPaneHarness> {\n return this.locatorFor(WrTransferPaneHarness.with({ side }))();\n }\n\n /**\n * Whether the whole control refuses interaction.\n *\n * From the host modifier, which is the only signal the host itself carries: a\n * `<wr-transfer>` element is not a control and publishes no `aria-disabled` of its\n * own — the state reaches assistive tech through the checkboxes, the buttons and\n * the filter boxes it disables, which is where\n * {@link WrTransferItemHarness.isDisabled} and {@link canMoveTo} read it.\n */\n async isDisabled(): Promise<boolean> {\n return (await this.host()).hasClass('wr-transfer--disabled');\n }\n\n /** Whether the panes have filter boxes — `[searchable]` gives both one or neither. */\n async isSearchable(): Promise<boolean> {\n return (await this.host()).hasClass('wr-transfer--searchable');\n }\n\n /**\n * Whether the button that moves rows INTO `side` is offering itself.\n *\n * It is enabled only while the OTHER pane has something staged and showing, so\n * this is also the readable way to assert that staging landed — and that a search\n * which hid a staged row took the move away again.\n *\n * Read from the native `disabled` attribute: these are `button[wr-btn]`, the\n * native shape, where that attribute is the state. (`wr-btn` adds `aria-disabled`\n * only for its custom-element shape, on which `disabled` is inert.)\n */\n async canMoveTo(side: WrTransferSide): Promise<boolean> {\n return (await (await this.moveButton(side)).getAttribute('disabled')) === null;\n }\n\n /**\n * The accessible name of the button that moves rows INTO `side` —\n * `[toTargetLabel]` / `[toSourceLabel]`, or the i18n fallback.\n *\n * Worth pinning: the button's only content is an `aria-hidden` chevron, so this\n * `aria-label` is the entire announcement. Lose it and the pair becomes two\n * unnamed buttons.\n */\n async getMoveLabel(side: WrTransferSide): Promise<string | null> {\n return (await this.moveButton(side)).getAttribute('aria-label');\n }\n\n /**\n * Press the button that moves the staged rows INTO `side`, committing them to the\n * value.\n *\n * Only the rows the other pane is SHOWING as staged travel, and the staging is\n * cleared afterwards — the component's rule, not this harness's.\n *\n * Refuses a disabled button rather than pressing it: a native disabled `<button>`\n * swallows the click before Angular's listener sees it, so the call would resolve\n * having moved nothing at all.\n */\n async moveTo(side: WrTransferSide): Promise<void> {\n if (!(await this.canMoveTo(side))) {\n const from: WrTransferSide = side === 'target' ? 'source' : 'target';\n throw new Error(\n `WrTransferHarness.moveTo('${side}'): the button is disabled, so nothing would move. The ${from} pane ` +\n 'has nothing staged and showing — a row staged before a search hid it no longer counts — or the whole ' +\n 'transfer is disabled.'\n );\n }\n await (await this.moveButton(side)).click();\n }\n\n /**\n * Stage everything the other pane can stage, then move it INTO `side`.\n *\n * \"Everything\" is the pane's own scope: the rows it is SHOWING, disabled ones\n * excluded. A search narrows it, and with a filter typed this moves what is\n * visible rather than the whole pane.\n */\n async moveAllTo(side: WrTransferSide): Promise<void> {\n const from = await this.getPane(side === 'target' ? 'source' : 'target');\n await from.checkAll();\n await this.moveTo(side);\n }\n\n /** The heading of one pane — the `sourceTitle` / `targetTitle` filters run through this. */\n private async paneTitle(side: WrTransferSide): Promise<string> {\n return (await this.getPane(side)).getTitle();\n }\n\n /** Every label rendered in either pane, for the `itemLabel` filter. */\n private async shownLabels(): Promise<string[]> {\n const items = await this.locatorForAll(WrTransferItemHarness)();\n return Promise.all(items.map(item => item.getLabel()));\n }\n\n /**\n * The move button for a direction, addressed by its `--to-source` / `--to-target`\n * modifier.\n *\n * Not by DOM order, and that is the point: two identically classed buttons whose\n * only difference was their position would let a template reshuffle silently\n * reverse every `moveTo()` in every consumer's suite, with both directions still\n * green. Not by the `aria-label` either — that string is localizable.\n */\n private async moveButton(side: WrTransferSide): Promise<TestElement> {\n return this.locatorFor(`.wr-transfer__move--to-${side}`)();\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -300,10 +300,10 @@ class WrTransfer {
300
300
  someChecked: shown.length > 0 && shown.length < enabled.length,
301
301
  };
302
302
  }
303
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrTransfer, deps: [], target: i0.ɵɵFactoryTarget.Component });
304
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: WrTransfer, isStandalone: true, selector: "wr-transfer", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, sourceTitle: { classPropertyName: "sourceTitle", publicName: "sourceTitle", isSignal: true, isRequired: false, transformFunction: null }, targetTitle: { classPropertyName: "targetTitle", publicName: "targetTitle", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, emptyText: { classPropertyName: "emptyText", publicName: "emptyText", isSignal: true, isRequired: false, transformFunction: null }, selectAllLabel: { classPropertyName: "selectAllLabel", publicName: "selectAllLabel", isSignal: true, isRequired: false, transformFunction: null }, toTargetLabel: { classPropertyName: "toTargetLabel", publicName: "toTargetLabel", isSignal: true, isRequired: false, transformFunction: null }, toSourceLabel: { classPropertyName: "toSourceLabel", publicName: "toSourceLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { attributes: { "role": "group" }, properties: { "class": "classes()", "attr.aria-invalid": "fieldAria.ariaInvalid()", "attr.aria-describedby": "fieldAria.describedBy()" } }, providers: [{ provide: WR_FORM_FIELD, useValue: null }], ngImport: i0, template: "<!--\n Two panes and the buttons between them. Each pane is a PLAIN `<ul>` of\n checkboxes, deliberately: dressing it as a `role=\"listbox\"` of `role=\"option\"`\n rows reads better in the abstract but is invalid \u2014 an option may not contain an\n interactive control, and the axe gate says so. The checkbox is the thing the\n user operates, so it is the thing the semantics should describe; the pane\n heading names the group.\n-->\n@for (pane of panes; track pane) {\n @let state = pane === 'source' ? source() : target();\n @let title = pane === 'source' ? resolvedSourceTitle() : resolvedTargetTitle();\n\n <div class=\"wr-transfer__pane\" [class.wr-transfer__pane--target]=\"pane === 'target'\">\n <div class=\"wr-transfer__head\">\n <wr-checkbox\n size=\"sm\"\n [checked]=\"state.allChecked\"\n [indeterminate]=\"state.someChecked\"\n [disabled]=\"disabled() || state.enabledCount === 0\"\n [readonly]=\"readonly()\"\n [ariaLabel]=\"selectAllAria({ action: resolvedSelectAll(), pane: title })\"\n (checkedChange)=\"toggleAll(pane, $event)\"\n />\n <span class=\"wr-transfer__title\">{{ title }}</span>\n <span class=\"wr-transfer__count\">{{\n countLabel({ checked: state.checkedCount, total: state.rows.length })\n }}</span>\n </div>\n\n @if (searchable()) {\n <div class=\"wr-transfer__search\">\n <input\n wrInput\n size=\"sm\"\n type=\"search\"\n [placeholder]=\"resolvedSearch()\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"`${title} \u2014 ${resolvedSearch()}`\"\n (input)=\"onSearch(pane, $event)\"\n />\n </div>\n }\n\n <ul class=\"wr-transfer__list\" [attr.aria-label]=\"title\">\n @for (item of state.rows; track item.value) {\n <li class=\"wr-transfer__item\" [class.wr-transfer__item--disabled]=\"item.disabled\">\n <wr-checkbox\n size=\"sm\"\n [checked]=\"isChecked(pane, item)\"\n [disabled]=\"disabled() || !!item.disabled\"\n [readonly]=\"readonly()\"\n (checkedChange)=\"toggle(pane, item, $event)\"\n (touch)=\"touch.emit()\"\n >\n {{ item.label }}\n </wr-checkbox>\n </li>\n } @empty {\n <li class=\"wr-transfer__empty\">{{ resolvedEmpty() }}</li>\n }\n </ul>\n </div>\n\n <!-- The buttons live between the panes, so they are emitted after the first. -->\n @if (pane === 'source') {\n <div class=\"wr-transfer__actions\">\n <button\n wr-btn\n type=\"button\"\n size=\"sm\"\n color=\"primary\"\n outlined\n class=\"wr-transfer__move wr-transfer__move--to-target\"\n [disabled]=\"!canMoveRight()\"\n [attr.aria-label]=\"resolvedToTarget()\"\n (click)=\"moveRight()\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n </button>\n <button\n wr-btn\n type=\"button\"\n size=\"sm\"\n color=\"primary\"\n outlined\n class=\"wr-transfer__move wr-transfer__move--to-source\"\n [disabled]=\"!canMoveLeft()\"\n [attr.aria-label]=\"resolvedToSource()\"\n (click)=\"moveLeft()\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m15 18-6-6 6-6\" />\n </svg>\n </button>\n </div>\n }\n}\n", dependencies: [{ kind: "component", type: WrButton, selector: "wr-btn, button[wr-btn], a[wr-btn]", inputs: ["color", "size", "shape", "icon", "iconPosition", "disabled", "outlined", "block", "loading", "disabledWhenLoading"] }, { kind: "component", type: WrCheckbox, selector: "wr-checkbox", inputs: ["id", "checkboxValue", "ariaLabel", "checked", "disabled", "readonly", "size", "icon", "indeterminate"], outputs: ["checkedChange", "touch"] }, { kind: "directive", type: WrInput, selector: "input[wrInput], textarea[wrInput]", inputs: ["size", "rounded"] }], encapsulation: i0.ViewEncapsulation.None });
303
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrTransfer, deps: [], target: i0.ɵɵFactoryTarget.Component });
304
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: WrTransfer, isStandalone: true, selector: "wr-transfer", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, sourceTitle: { classPropertyName: "sourceTitle", publicName: "sourceTitle", isSignal: true, isRequired: false, transformFunction: null }, targetTitle: { classPropertyName: "targetTitle", publicName: "targetTitle", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, emptyText: { classPropertyName: "emptyText", publicName: "emptyText", isSignal: true, isRequired: false, transformFunction: null }, selectAllLabel: { classPropertyName: "selectAllLabel", publicName: "selectAllLabel", isSignal: true, isRequired: false, transformFunction: null }, toTargetLabel: { classPropertyName: "toTargetLabel", publicName: "toTargetLabel", isSignal: true, isRequired: false, transformFunction: null }, toSourceLabel: { classPropertyName: "toSourceLabel", publicName: "toSourceLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { attributes: { "role": "group" }, properties: { "class": "classes()", "attr.aria-invalid": "fieldAria.ariaInvalid()", "attr.aria-describedby": "fieldAria.describedBy()" } }, providers: [{ provide: WR_FORM_FIELD, useValue: null }], ngImport: i0, template: "<!--\n Two panes and the buttons between them. Each pane is a PLAIN `<ul>` of\n checkboxes, deliberately: dressing it as a `role=\"listbox\"` of `role=\"option\"`\n rows reads better in the abstract but is invalid \u2014 an option may not contain an\n interactive control, and the axe gate says so. The checkbox is the thing the\n user operates, so it is the thing the semantics should describe; the pane\n heading names the group.\n-->\n@for (pane of panes; track pane) {\n @let state = pane === 'source' ? source() : target();\n @let title = pane === 'source' ? resolvedSourceTitle() : resolvedTargetTitle();\n\n <div class=\"wr-transfer__pane\" [class.wr-transfer__pane--target]=\"pane === 'target'\">\n <div class=\"wr-transfer__head\">\n <wr-checkbox\n size=\"sm\"\n [checked]=\"state.allChecked\"\n [indeterminate]=\"state.someChecked\"\n [disabled]=\"disabled() || state.enabledCount === 0\"\n [readonly]=\"readonly()\"\n [ariaLabel]=\"selectAllAria({ action: resolvedSelectAll(), pane: title })\"\n (checkedChange)=\"toggleAll(pane, $event)\"\n />\n <span class=\"wr-transfer__title\">{{ title }}</span>\n <span class=\"wr-transfer__count\">{{\n countLabel({ checked: state.checkedCount, total: state.rows.length })\n }}</span>\n </div>\n\n @if (searchable()) {\n <div class=\"wr-transfer__search\">\n <input\n wrInput\n size=\"sm\"\n type=\"search\"\n [placeholder]=\"resolvedSearch()\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"`${title} \u2014 ${resolvedSearch()}`\"\n (input)=\"onSearch(pane, $event)\"\n />\n </div>\n }\n\n <ul class=\"wr-transfer__list\" [attr.aria-label]=\"title\">\n @for (item of state.rows; track item.value) {\n <li class=\"wr-transfer__item\" [class.wr-transfer__item--disabled]=\"item.disabled\">\n <wr-checkbox\n size=\"sm\"\n [checked]=\"isChecked(pane, item)\"\n [disabled]=\"disabled() || !!item.disabled\"\n [readonly]=\"readonly()\"\n (checkedChange)=\"toggle(pane, item, $event)\"\n (touch)=\"touch.emit()\"\n >\n {{ item.label }}\n </wr-checkbox>\n </li>\n } @empty {\n <li class=\"wr-transfer__empty\">{{ resolvedEmpty() }}</li>\n }\n </ul>\n </div>\n\n <!-- The buttons live between the panes, so they are emitted after the first. -->\n @if (pane === 'source') {\n <div class=\"wr-transfer__actions\">\n <button\n wr-btn\n type=\"button\"\n size=\"sm\"\n color=\"primary\"\n outlined\n class=\"wr-transfer__move wr-transfer__move--to-target\"\n [disabled]=\"!canMoveRight()\"\n [attr.aria-label]=\"resolvedToTarget()\"\n (click)=\"moveRight()\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n </button>\n <button\n wr-btn\n type=\"button\"\n size=\"sm\"\n color=\"primary\"\n outlined\n class=\"wr-transfer__move wr-transfer__move--to-source\"\n [disabled]=\"!canMoveLeft()\"\n [attr.aria-label]=\"resolvedToSource()\"\n (click)=\"moveLeft()\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m15 18-6-6 6-6\" />\n </svg>\n </button>\n </div>\n }\n}\n", dependencies: [{ kind: "component", type: WrButton, selector: "wr-btn, button[wr-btn], a[wr-btn]", inputs: ["color", "size", "shape", "icon", "iconPosition", "disabled", "outlined", "block", "loading", "disabledWhenLoading"] }, { kind: "component", type: WrCheckbox, selector: "wr-checkbox", inputs: ["id", "checkboxValue", "ariaLabel", "checked", "disabled", "readonly", "size", "icon", "indeterminate"], outputs: ["checkedChange", "touch"] }, { kind: "directive", type: WrInput, selector: "input[wrInput], textarea[wrInput]", inputs: ["size", "rounded"] }], encapsulation: i0.ViewEncapsulation.None });
305
305
  }
306
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrTransfer, decorators: [{
306
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrTransfer, decorators: [{
307
307
  type: Component,
308
308
  args: [{ selector: 'wr-transfer', encapsulation: ViewEncapsulation.None, host: {
309
309
  '[class]': 'classes()',
@@ -1 +1 @@
1
- {"version":3,"file":"ngwr-transfer.mjs","sources":["../../../projects/lib/transfer/transfer.ts","../../../projects/lib/transfer/transfer.html","../../../projects/lib/transfer/ngwr-transfer.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 } from '@angular/cdk/coercion';\nimport {\n Component,\n ElementRef,\n Injector,\n ViewEncapsulation,\n afterNextRender,\n computed,\n inject,\n input,\n isDevMode,\n model,\n output,\n signal,\n} from '@angular/core';\nimport type { FormValueControl } from '@angular/forms/signals';\n\nimport { WrButton } from 'ngwr/button';\nimport { WrCheckbox } from 'ngwr/checkbox';\nimport { WR_FORM_FIELD, useFormFieldAria } from 'ngwr/form';\nimport { useI18nFormatter, useI18nText } from 'ngwr/i18n';\nimport { WrInput } from 'ngwr/input';\n\nimport type { WrTransferItem } from './interfaces';\n\n/** A pane's rows plus the header state derived from them. */\ninterface PaneState {\n readonly rows: readonly WrTransferItem[];\n /**\n * The staged values this pane is actually SHOWING — visible and enabled. The\n * staging signals can hold more than that (a filter change hides rows without\n * unstaging them), and every consumer of the staged set has to agree on which\n * one it means: the count, the header checkbox and the move all read this.\n */\n readonly checked: readonly unknown[];\n readonly checkedCount: number;\n readonly enabledCount: number;\n readonly allChecked: boolean;\n readonly someChecked: boolean;\n}\n\n/**\n * Dual-listbox picker: two panes and the buttons that move rows between them.\n *\n * The full item set is `[items]` and the RIGHT pane is the value — `[(value)]`\n * holds the chosen `WrTransferItem['value']`s, everything else stays left. The\n * checked state inside each pane is transient staging, deliberately not part of\n * the value: what a form cares about is which rows ended up on the right.\n *\n * A signal-forms native control (`FormValueControl<readonly unknown[]>`), so\n * `[formField]` binds straight to `value`; `[(ngModel)]` and reactive forms keep\n * working through Angular's bridge, and `[(value)]` is the standalone shape.\n *\n * @example\n * ```html\n * <!-- Standalone -->\n * <wr-transfer [items]=\"permissions\" [(value)]=\"granted\" />\n *\n * <!-- Searchable, with pane titles -->\n * <wr-transfer\n * searchable\n * sourceTitle=\"Available\"\n * targetTitle=\"Granted\"\n * [items]=\"permissions\"\n * [formField]=\"form.granted\"\n * />\n * ```\n *\n * @see https://ngwr.dev/reference/components/transfer\n */\n@Component({\n selector: 'wr-transfer',\n templateUrl: './transfer.html',\n encapsulation: ViewEncapsulation.None,\n host: {\n '[class]': 'classes()',\n // `role=\"group\"` so the error state below has somewhere legible to live: the\n // control is a composite with no single element carrying its semantics, and\n // `aria-invalid` on a bare `generic` host is announced by nothing.\n role: 'group',\n '[attr.aria-invalid]': 'fieldAria.ariaInvalid()',\n '[attr.aria-describedby]': 'fieldAria.describedBy()',\n },\n // The transfer is the control a `<wr-form-field>` wraps; the checkboxes and\n // the search inputs in its own template are parts, not controls. Without this\n // shield each of them found the field's token and announced the one error as\n // its own — which is why `fieldAria` below reads the field with `skipSelf`.\n providers: [{ provide: WR_FORM_FIELD, useValue: null }],\n imports: [WrButton, WrCheckbox, WrInput],\n})\nexport class WrTransfer implements FormValueControl<readonly unknown[]> {\n /** Every row, in either pane. Membership of the right pane is `value`. */\n readonly items = input<readonly WrTransferItem[]>([]);\n\n /**\n * Values currently in the RIGHT pane. Two-way bindable; bound automatically\n * by `[formField]` / `[(ngModel)]`.\n */\n readonly value = model<readonly unknown[]>([]);\n\n /** Emitted on blur / commit so a bound field marks itself touched. */\n readonly touch = output<void>();\n\n /** Disable the whole control. @default false */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n /**\n * Refuse changes to the value while both panes stay focusable and readable.\n * Bound automatically from the field's readonly state when used with\n * `[formField]`.\n *\n * The move buttons go inert and the row checkboxes go read-only; SEARCH keeps\n * working, because filtering a pane changes what is shown and not what is\n * chosen. No `aria-readonly` on the host: role `group` does not support the\n * state, so each row's checkbox mirrors its own instead.\n *\n * @default false\n */\n readonly readonly = input(false, { transform: coerceBooleanProperty });\n\n /** The surrounding `<wr-form-field>`'s error state. @internal */\n protected readonly fieldAria = useFormFieldAria({ skipSelf: true });\n\n /** Show a filter box above each pane. @default false */\n readonly searchable = input(false, { transform: coerceBooleanProperty });\n\n /** Heading above the left pane. Falls back to `transfer.source`. */\n readonly sourceTitle = input<string | null>(null);\n\n /** Heading above the right pane. Falls back to `transfer.target`. */\n readonly targetTitle = input<string | null>(null);\n\n /** Placeholder in both filter boxes. Falls back to `transfer.search`. */\n readonly searchPlaceholder = input<string | null>(null);\n\n /** Shown in a pane with no rows. Falls back to `transfer.empty`. */\n readonly emptyText = input<string | null>(null);\n\n /**\n * Accessible name of each pane's select-all checkbox, composed with the pane\n * heading. Falls back to `transfer.selectAll`.\n */\n readonly selectAllLabel = input<string | null>(null);\n\n /** Accessible name of the move-right button. Falls back to `transfer.toTarget`. */\n readonly toTargetLabel = input<string | null>(null);\n\n /** Accessible name of the move-left button. Falls back to `transfer.toSource`. */\n readonly toSourceLabel = input<string | null>(null);\n\n protected readonly resolvedSourceTitle = useI18nText(this.sourceTitle, 'transfer.source', 'Available');\n protected readonly resolvedTargetTitle = useI18nText(this.targetTitle, 'transfer.target', 'Selected');\n protected readonly resolvedSearch = useI18nText(this.searchPlaceholder, 'transfer.search', 'Search');\n protected readonly resolvedEmpty = useI18nText(this.emptyText, 'transfer.empty', 'Nothing here');\n protected readonly resolvedSelectAll = useI18nText(this.selectAllLabel, 'transfer.selectAll', 'Select all');\n\n /**\n * The select-all checkbox's accessible name, composed IN THE CATALOG.\n *\n * It used to be a template literal — `` `${title} — ${selectAll}` `` — which\n * froze both the separator and the operand order into English. A translator\n * could change each half and not the sentence they make, which is the exact\n * defect the calendar and event-calendar catalogs were rewritten to remove.\n * The key ships as `{{pane}} — {{action}}` in every locale, so nothing reads\n * differently today and every locale can now reorder it without a code change.\n */\n protected readonly selectAllAria = useI18nFormatter('transfer.selectAllAria', '{{pane}} — {{action}}');\n protected readonly resolvedToTarget = useI18nText(this.toTargetLabel, 'transfer.toTarget', 'Move to selected');\n protected readonly resolvedToSource = useI18nText(this.toSourceLabel, 'transfer.toSource', 'Move to available');\n\n /** `{{checked}} / {{total}}` under each heading. @internal */\n protected readonly countLabel = useI18nFormatter('transfer.count', '{{checked}} / {{total}}');\n\n /** Pane order — the template iterates it so both panes share one block. */\n protected readonly panes = ['source', 'target'] as const;\n\n private readonly sourceQuery = signal('');\n private readonly targetQuery = signal('');\n\n /** Staged rows, per pane. Cleared as soon as a move commits them. */\n private readonly sourceChecked = signal<readonly unknown[]>([]);\n private readonly targetChecked = signal<readonly unknown[]>([]);\n\n // The value as a guaranteed array — a classic-forms binding can write null even\n // though the type is `readonly unknown[]`, so normalise every read. Same hazard\n // `wr-checkbox-group` guards; here an unguarded `.map` threw outright.\n private readonly selected = computed<readonly unknown[]>(() => {\n const v = this.value();\n return Array.isArray(v) ? v : [];\n });\n\n private readonly valueSet = computed(() => new Set(this.selected()));\n\n protected readonly source = computed<PaneState>(() =>\n this.pane(\n this.items().filter(item => !this.valueSet().has(item.value)),\n this.sourceQuery(),\n this.sourceChecked()\n )\n );\n\n protected readonly target = computed<PaneState>(() => {\n // Right-pane order follows `value`, not `items`: the order a user built is\n // the one they expect to read back.\n const rows = this.selected()\n .map(v => this.items().find(item => item.value === v))\n .filter((item): item is WrTransferItem => item !== undefined);\n\n if (isDevMode() && rows.length !== this.selected().length) this.warnAboutOrphans();\n\n return this.pane(rows, this.targetQuery(), this.targetChecked());\n });\n\n /**\n * Say something when `value` holds a value no `items` entry matches.\n *\n * Such a value is in NEITHER pane — the left one filters out anything already\n * selected and the right one can only render rows it found — and the header\n * counts the rows it shows, so nothing on screen contradicts anything. The\n * result is a value the user can neither see nor remove, and no sign that it\n * is there.\n *\n * A warning rather than an invented row, which matches how the library treats\n * the same question elsewhere: `wr-select` renders a value outside its option\n * list only under an explicit `freeText`, so an unmatched value is a mode a\n * consumer opts into, not a shape a component guesses at. It also stays quiet\n * about the common transient case — `items` arriving after `value` — because\n * the message names the values and a developer can see them settle.\n */\n private warnAboutOrphans(): void {\n const known = new Set(this.items().map(item => item.value));\n const orphans = this.selected().filter(v => !known.has(v));\n if (orphans.length === 0) return;\n\n // eslint-disable-next-line no-console -- dev-mode validation\n console.warn(\n `[NGWR] <wr-transfer>: ${orphans.length} value(s) in \\`value\\` match no \\`items\\` entry ` +\n `and are rendered in neither pane, so a user can neither see nor remove them: ` +\n `${orphans.map(v => JSON.stringify(v)).join(', ')}. ` +\n `If \\`items\\` loads after \\`value\\`, this settles on its own.`\n );\n }\n\n protected readonly canMoveRight = computed(\n () => !this.disabled() && !this.readonly() && this.source().checkedCount > 0\n );\n protected readonly canMoveLeft = computed(\n () => !this.disabled() && !this.readonly() && this.target().checkedCount > 0\n );\n\n protected readonly classes = computed(() => {\n const parts = ['wr-transfer'];\n if (this.disabled()) parts.push('wr-transfer--disabled');\n else if (this.readonly()) parts.push('wr-transfer--readonly');\n if (this.searchable()) parts.push('wr-transfer--searchable');\n return parts.join(' ');\n });\n\n protected isChecked(pane: 'source' | 'target', item: WrTransferItem): boolean {\n return (pane === 'source' ? this.sourceChecked() : this.targetChecked()).includes(item.value);\n }\n\n protected toggle(pane: 'source' | 'target', item: WrTransferItem, checked: boolean): void {\n if (item.disabled || this.readonly()) return;\n const box = pane === 'source' ? this.sourceChecked : this.targetChecked;\n const current = box();\n if (checked) {\n box.set([...current, item.value]);\n return;\n }\n // A `Set` compares with SameValueZero, which is what `WrTransferItem['value']`\n // is documented to use and what `isChecked`'s `includes` already does. A `!==`\n // filter cannot remove `NaN` from its own list, so such a row drew itself\n // unchecked while staying staged.\n const next = new Set(current);\n next.delete(item.value);\n box.set([...next]);\n }\n\n /** Header checkbox — stages or clears every enabled row the filter shows. */\n protected toggleAll(pane: 'source' | 'target', checked: boolean): void {\n if (this.readonly()) return;\n const state = pane === 'source' ? this.source() : this.target();\n const box = pane === 'source' ? this.sourceChecked : this.targetChecked;\n box.set(checked ? state.rows.filter(item => !item.disabled).map(item => item.value) : []);\n }\n\n protected onSearch(pane: 'source' | 'target', event: Event): void {\n const query = (event.target as HTMLInputElement | null)?.value ?? '';\n (pane === 'source' ? this.sourceQuery : this.targetQuery).set(query);\n }\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly injector = inject(Injector);\n\n /**\n * Keep focus in the widget after a move.\n *\n * A move empties the pane's staging set, which is exactly what disables the\n * button that was just pressed — so the element holding DOM focus went\n * `disabled` as a RESULT of its own activation and the browser dropped focus\n * to `<body>`. From there the next Tab restarts at the top of the document,\n * which for a keyboard user is being thrown out of a control they were in the\n * middle of using.\n *\n * The landing is the FIRST ROW OF THE PANE THE ROWS ARRIVED IN, and the\n * obvious alternative does not work: after a move BOTH buttons are disabled,\n * because each needs something ticked and the move cleared the tick on one\n * side and arrived unticked on the other. The rows that just moved are where\n * the user's attention is and where the next action lives, so that is where\n * focus goes.\n *\n * `afterNextRender`, not `queueMicrotask`: under zoneless CD the microtask\n * runs before the moved rows are in the DOM, so the focus call would land on\n * the pane as it was before the move.\n */\n private restoreFocusAfterMove(landing: 'source' | 'target'): void {\n afterNextRender(\n () => {\n const root = this.host.nativeElement;\n const pane =\n landing === 'target'\n ? root.querySelector<HTMLElement>('.wr-transfer__pane--target')\n : root.querySelector<HTMLElement>('.wr-transfer__pane:not(.wr-transfer__pane--target)');\n const row = pane?.querySelector<HTMLInputElement>('.wr-transfer__item input:not([disabled])');\n row?.focus();\n },\n { injector: this.injector }\n );\n }\n\n protected moveRight(): void {\n if (this.disabled() || this.readonly()) return;\n // `source().checked`, not the raw staging box: rows a filter change hid are\n // neither counted nor ticked any more, so moving them would transfer rows the\n // pane never showed as chosen — and, since staging outlives an external write\n // to `value`, could land the same value on the right twice.\n const moving = this.source().checked;\n if (moving.length === 0) return;\n this.value.set([...this.selected(), ...moving]);\n this.sourceChecked.set([]);\n this.touch.emit();\n this.restoreFocusAfterMove('target');\n }\n\n protected moveLeft(): void {\n if (this.disabled() || this.readonly()) return;\n const moving = new Set(this.target().checked);\n if (moving.size === 0) return;\n this.value.set(this.selected().filter(v => !moving.has(v)));\n this.targetChecked.set([]);\n this.touch.emit();\n this.restoreFocusAfterMove('source');\n }\n\n /** Filter, then derive the header state from what survived. */\n private pane(rows: readonly WrTransferItem[], query: string, checked: readonly unknown[]): PaneState {\n const q = query.trim().toLowerCase();\n const visible = q ? rows.filter(item => item.label.toLowerCase().includes(q)) : rows;\n const enabled = visible.filter(item => !item.disabled);\n const staged = new Set(checked);\n const shown = enabled.filter(item => staged.has(item.value)).map(item => item.value);\n return {\n rows: visible,\n checked: shown,\n checkedCount: shown.length,\n enabledCount: enabled.length,\n allChecked: enabled.length > 0 && shown.length === enabled.length,\n someChecked: shown.length > 0 && shown.length < enabled.length,\n };\n }\n}\n","<!--\n Two panes and the buttons between them. Each pane is a PLAIN `<ul>` of\n checkboxes, deliberately: dressing it as a `role=\"listbox\"` of `role=\"option\"`\n rows reads better in the abstract but is invalid — an option may not contain an\n interactive control, and the axe gate says so. The checkbox is the thing the\n user operates, so it is the thing the semantics should describe; the pane\n heading names the group.\n-->\n@for (pane of panes; track pane) {\n @let state = pane === 'source' ? source() : target();\n @let title = pane === 'source' ? resolvedSourceTitle() : resolvedTargetTitle();\n\n <div class=\"wr-transfer__pane\" [class.wr-transfer__pane--target]=\"pane === 'target'\">\n <div class=\"wr-transfer__head\">\n <wr-checkbox\n size=\"sm\"\n [checked]=\"state.allChecked\"\n [indeterminate]=\"state.someChecked\"\n [disabled]=\"disabled() || state.enabledCount === 0\"\n [readonly]=\"readonly()\"\n [ariaLabel]=\"selectAllAria({ action: resolvedSelectAll(), pane: title })\"\n (checkedChange)=\"toggleAll(pane, $event)\"\n />\n <span class=\"wr-transfer__title\">{{ title }}</span>\n <span class=\"wr-transfer__count\">{{\n countLabel({ checked: state.checkedCount, total: state.rows.length })\n }}</span>\n </div>\n\n @if (searchable()) {\n <div class=\"wr-transfer__search\">\n <input\n wrInput\n size=\"sm\"\n type=\"search\"\n [placeholder]=\"resolvedSearch()\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"`${title} — ${resolvedSearch()}`\"\n (input)=\"onSearch(pane, $event)\"\n />\n </div>\n }\n\n <ul class=\"wr-transfer__list\" [attr.aria-label]=\"title\">\n @for (item of state.rows; track item.value) {\n <li class=\"wr-transfer__item\" [class.wr-transfer__item--disabled]=\"item.disabled\">\n <wr-checkbox\n size=\"sm\"\n [checked]=\"isChecked(pane, item)\"\n [disabled]=\"disabled() || !!item.disabled\"\n [readonly]=\"readonly()\"\n (checkedChange)=\"toggle(pane, item, $event)\"\n (touch)=\"touch.emit()\"\n >\n {{ item.label }}\n </wr-checkbox>\n </li>\n } @empty {\n <li class=\"wr-transfer__empty\">{{ resolvedEmpty() }}</li>\n }\n </ul>\n </div>\n\n <!-- The buttons live between the panes, so they are emitted after the first. -->\n @if (pane === 'source') {\n <div class=\"wr-transfer__actions\">\n <button\n wr-btn\n type=\"button\"\n size=\"sm\"\n color=\"primary\"\n outlined\n class=\"wr-transfer__move wr-transfer__move--to-target\"\n [disabled]=\"!canMoveRight()\"\n [attr.aria-label]=\"resolvedToTarget()\"\n (click)=\"moveRight()\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n </button>\n <button\n wr-btn\n type=\"button\"\n size=\"sm\"\n color=\"primary\"\n outlined\n class=\"wr-transfer__move wr-transfer__move--to-source\"\n [disabled]=\"!canMoveLeft()\"\n [attr.aria-label]=\"resolvedToSource()\"\n (click)=\"moveLeft()\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m15 18-6-6 6-6\" />\n </svg>\n </button>\n </div>\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-transfer.mjs","sources":["../../../projects/lib/transfer/transfer.ts","../../../projects/lib/transfer/transfer.html","../../../projects/lib/transfer/ngwr-transfer.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 } from '@angular/cdk/coercion';\nimport {\n Component,\n ElementRef,\n Injector,\n ViewEncapsulation,\n afterNextRender,\n computed,\n inject,\n input,\n isDevMode,\n model,\n output,\n signal,\n} from '@angular/core';\nimport type { FormValueControl } from '@angular/forms/signals';\n\nimport { WrButton } from 'ngwr/button';\nimport { WrCheckbox } from 'ngwr/checkbox';\nimport { WR_FORM_FIELD, useFormFieldAria } from 'ngwr/form';\nimport { useI18nFormatter, useI18nText } from 'ngwr/i18n';\nimport { WrInput } from 'ngwr/input';\n\nimport type { WrTransferItem } from './interfaces';\n\n/** A pane's rows plus the header state derived from them. */\ninterface PaneState {\n readonly rows: readonly WrTransferItem[];\n /**\n * The staged values this pane is actually SHOWING — visible and enabled. The\n * staging signals can hold more than that (a filter change hides rows without\n * unstaging them), and every consumer of the staged set has to agree on which\n * one it means: the count, the header checkbox and the move all read this.\n */\n readonly checked: readonly unknown[];\n readonly checkedCount: number;\n readonly enabledCount: number;\n readonly allChecked: boolean;\n readonly someChecked: boolean;\n}\n\n/**\n * Dual-listbox picker: two panes and the buttons that move rows between them.\n *\n * The full item set is `[items]` and the RIGHT pane is the value — `[(value)]`\n * holds the chosen `WrTransferItem['value']`s, everything else stays left. The\n * checked state inside each pane is transient staging, deliberately not part of\n * the value: what a form cares about is which rows ended up on the right.\n *\n * A signal-forms native control (`FormValueControl<readonly unknown[]>`), so\n * `[formField]` binds straight to `value`; `[(ngModel)]` and reactive forms keep\n * working through Angular's bridge, and `[(value)]` is the standalone shape.\n *\n * @example\n * ```html\n * <!-- Standalone -->\n * <wr-transfer [items]=\"permissions\" [(value)]=\"granted\" />\n *\n * <!-- Searchable, with pane titles -->\n * <wr-transfer\n * searchable\n * sourceTitle=\"Available\"\n * targetTitle=\"Granted\"\n * [items]=\"permissions\"\n * [formField]=\"form.granted\"\n * />\n * ```\n *\n * @see https://ngwr.dev/reference/components/transfer\n */\n@Component({\n selector: 'wr-transfer',\n templateUrl: './transfer.html',\n encapsulation: ViewEncapsulation.None,\n host: {\n '[class]': 'classes()',\n // `role=\"group\"` so the error state below has somewhere legible to live: the\n // control is a composite with no single element carrying its semantics, and\n // `aria-invalid` on a bare `generic` host is announced by nothing.\n role: 'group',\n '[attr.aria-invalid]': 'fieldAria.ariaInvalid()',\n '[attr.aria-describedby]': 'fieldAria.describedBy()',\n },\n // The transfer is the control a `<wr-form-field>` wraps; the checkboxes and\n // the search inputs in its own template are parts, not controls. Without this\n // shield each of them found the field's token and announced the one error as\n // its own — which is why `fieldAria` below reads the field with `skipSelf`.\n providers: [{ provide: WR_FORM_FIELD, useValue: null }],\n imports: [WrButton, WrCheckbox, WrInput],\n})\nexport class WrTransfer implements FormValueControl<readonly unknown[]> {\n /** Every row, in either pane. Membership of the right pane is `value`. */\n readonly items = input<readonly WrTransferItem[]>([]);\n\n /**\n * Values currently in the RIGHT pane. Two-way bindable; bound automatically\n * by `[formField]` / `[(ngModel)]`.\n */\n readonly value = model<readonly unknown[]>([]);\n\n /** Emitted on blur / commit so a bound field marks itself touched. */\n readonly touch = output<void>();\n\n /** Disable the whole control. @default false */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n /**\n * Refuse changes to the value while both panes stay focusable and readable.\n * Bound automatically from the field's readonly state when used with\n * `[formField]`.\n *\n * The move buttons go inert and the row checkboxes go read-only; SEARCH keeps\n * working, because filtering a pane changes what is shown and not what is\n * chosen. No `aria-readonly` on the host: role `group` does not support the\n * state, so each row's checkbox mirrors its own instead.\n *\n * @default false\n */\n readonly readonly = input(false, { transform: coerceBooleanProperty });\n\n /** The surrounding `<wr-form-field>`'s error state. @internal */\n protected readonly fieldAria = useFormFieldAria({ skipSelf: true });\n\n /** Show a filter box above each pane. @default false */\n readonly searchable = input(false, { transform: coerceBooleanProperty });\n\n /** Heading above the left pane. Falls back to `transfer.source`. */\n readonly sourceTitle = input<string | null>(null);\n\n /** Heading above the right pane. Falls back to `transfer.target`. */\n readonly targetTitle = input<string | null>(null);\n\n /** Placeholder in both filter boxes. Falls back to `transfer.search`. */\n readonly searchPlaceholder = input<string | null>(null);\n\n /** Shown in a pane with no rows. Falls back to `transfer.empty`. */\n readonly emptyText = input<string | null>(null);\n\n /**\n * Accessible name of each pane's select-all checkbox, composed with the pane\n * heading. Falls back to `transfer.selectAll`.\n */\n readonly selectAllLabel = input<string | null>(null);\n\n /** Accessible name of the move-right button. Falls back to `transfer.toTarget`. */\n readonly toTargetLabel = input<string | null>(null);\n\n /** Accessible name of the move-left button. Falls back to `transfer.toSource`. */\n readonly toSourceLabel = input<string | null>(null);\n\n protected readonly resolvedSourceTitle = useI18nText(this.sourceTitle, 'transfer.source', 'Available');\n protected readonly resolvedTargetTitle = useI18nText(this.targetTitle, 'transfer.target', 'Selected');\n protected readonly resolvedSearch = useI18nText(this.searchPlaceholder, 'transfer.search', 'Search');\n protected readonly resolvedEmpty = useI18nText(this.emptyText, 'transfer.empty', 'Nothing here');\n protected readonly resolvedSelectAll = useI18nText(this.selectAllLabel, 'transfer.selectAll', 'Select all');\n\n /**\n * The select-all checkbox's accessible name, composed IN THE CATALOG.\n *\n * It used to be a template literal — `` `${title} — ${selectAll}` `` — which\n * froze both the separator and the operand order into English. A translator\n * could change each half and not the sentence they make, which is the exact\n * defect the calendar and event-calendar catalogs were rewritten to remove.\n * The key ships as `{{pane}} — {{action}}` in every locale, so nothing reads\n * differently today and every locale can now reorder it without a code change.\n */\n protected readonly selectAllAria = useI18nFormatter('transfer.selectAllAria', '{{pane}} — {{action}}');\n protected readonly resolvedToTarget = useI18nText(this.toTargetLabel, 'transfer.toTarget', 'Move to selected');\n protected readonly resolvedToSource = useI18nText(this.toSourceLabel, 'transfer.toSource', 'Move to available');\n\n /** `{{checked}} / {{total}}` under each heading. @internal */\n protected readonly countLabel = useI18nFormatter('transfer.count', '{{checked}} / {{total}}');\n\n /** Pane order — the template iterates it so both panes share one block. */\n protected readonly panes = ['source', 'target'] as const;\n\n private readonly sourceQuery = signal('');\n private readonly targetQuery = signal('');\n\n /** Staged rows, per pane. Cleared as soon as a move commits them. */\n private readonly sourceChecked = signal<readonly unknown[]>([]);\n private readonly targetChecked = signal<readonly unknown[]>([]);\n\n // The value as a guaranteed array — a classic-forms binding can write null even\n // though the type is `readonly unknown[]`, so normalise every read. Same hazard\n // `wr-checkbox-group` guards; here an unguarded `.map` threw outright.\n private readonly selected = computed<readonly unknown[]>(() => {\n const v = this.value();\n return Array.isArray(v) ? v : [];\n });\n\n private readonly valueSet = computed(() => new Set(this.selected()));\n\n protected readonly source = computed<PaneState>(() =>\n this.pane(\n this.items().filter(item => !this.valueSet().has(item.value)),\n this.sourceQuery(),\n this.sourceChecked()\n )\n );\n\n protected readonly target = computed<PaneState>(() => {\n // Right-pane order follows `value`, not `items`: the order a user built is\n // the one they expect to read back.\n const rows = this.selected()\n .map(v => this.items().find(item => item.value === v))\n .filter((item): item is WrTransferItem => item !== undefined);\n\n if (isDevMode() && rows.length !== this.selected().length) this.warnAboutOrphans();\n\n return this.pane(rows, this.targetQuery(), this.targetChecked());\n });\n\n /**\n * Say something when `value` holds a value no `items` entry matches.\n *\n * Such a value is in NEITHER pane — the left one filters out anything already\n * selected and the right one can only render rows it found — and the header\n * counts the rows it shows, so nothing on screen contradicts anything. The\n * result is a value the user can neither see nor remove, and no sign that it\n * is there.\n *\n * A warning rather than an invented row, which matches how the library treats\n * the same question elsewhere: `wr-select` renders a value outside its option\n * list only under an explicit `freeText`, so an unmatched value is a mode a\n * consumer opts into, not a shape a component guesses at. It also stays quiet\n * about the common transient case — `items` arriving after `value` — because\n * the message names the values and a developer can see them settle.\n */\n private warnAboutOrphans(): void {\n const known = new Set(this.items().map(item => item.value));\n const orphans = this.selected().filter(v => !known.has(v));\n if (orphans.length === 0) return;\n\n // eslint-disable-next-line no-console -- dev-mode validation\n console.warn(\n `[NGWR] <wr-transfer>: ${orphans.length} value(s) in \\`value\\` match no \\`items\\` entry ` +\n `and are rendered in neither pane, so a user can neither see nor remove them: ` +\n `${orphans.map(v => JSON.stringify(v)).join(', ')}. ` +\n `If \\`items\\` loads after \\`value\\`, this settles on its own.`\n );\n }\n\n protected readonly canMoveRight = computed(\n () => !this.disabled() && !this.readonly() && this.source().checkedCount > 0\n );\n protected readonly canMoveLeft = computed(\n () => !this.disabled() && !this.readonly() && this.target().checkedCount > 0\n );\n\n protected readonly classes = computed(() => {\n const parts = ['wr-transfer'];\n if (this.disabled()) parts.push('wr-transfer--disabled');\n else if (this.readonly()) parts.push('wr-transfer--readonly');\n if (this.searchable()) parts.push('wr-transfer--searchable');\n return parts.join(' ');\n });\n\n protected isChecked(pane: 'source' | 'target', item: WrTransferItem): boolean {\n return (pane === 'source' ? this.sourceChecked() : this.targetChecked()).includes(item.value);\n }\n\n protected toggle(pane: 'source' | 'target', item: WrTransferItem, checked: boolean): void {\n if (item.disabled || this.readonly()) return;\n const box = pane === 'source' ? this.sourceChecked : this.targetChecked;\n const current = box();\n if (checked) {\n box.set([...current, item.value]);\n return;\n }\n // A `Set` compares with SameValueZero, which is what `WrTransferItem['value']`\n // is documented to use and what `isChecked`'s `includes` already does. A `!==`\n // filter cannot remove `NaN` from its own list, so such a row drew itself\n // unchecked while staying staged.\n const next = new Set(current);\n next.delete(item.value);\n box.set([...next]);\n }\n\n /** Header checkbox — stages or clears every enabled row the filter shows. */\n protected toggleAll(pane: 'source' | 'target', checked: boolean): void {\n if (this.readonly()) return;\n const state = pane === 'source' ? this.source() : this.target();\n const box = pane === 'source' ? this.sourceChecked : this.targetChecked;\n box.set(checked ? state.rows.filter(item => !item.disabled).map(item => item.value) : []);\n }\n\n protected onSearch(pane: 'source' | 'target', event: Event): void {\n const query = (event.target as HTMLInputElement | null)?.value ?? '';\n (pane === 'source' ? this.sourceQuery : this.targetQuery).set(query);\n }\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly injector = inject(Injector);\n\n /**\n * Keep focus in the widget after a move.\n *\n * A move empties the pane's staging set, which is exactly what disables the\n * button that was just pressed — so the element holding DOM focus went\n * `disabled` as a RESULT of its own activation and the browser dropped focus\n * to `<body>`. From there the next Tab restarts at the top of the document,\n * which for a keyboard user is being thrown out of a control they were in the\n * middle of using.\n *\n * The landing is the FIRST ROW OF THE PANE THE ROWS ARRIVED IN, and the\n * obvious alternative does not work: after a move BOTH buttons are disabled,\n * because each needs something ticked and the move cleared the tick on one\n * side and arrived unticked on the other. The rows that just moved are where\n * the user's attention is and where the next action lives, so that is where\n * focus goes.\n *\n * `afterNextRender`, not `queueMicrotask`: under zoneless CD the microtask\n * runs before the moved rows are in the DOM, so the focus call would land on\n * the pane as it was before the move.\n */\n private restoreFocusAfterMove(landing: 'source' | 'target'): void {\n afterNextRender(\n () => {\n const root = this.host.nativeElement;\n const pane =\n landing === 'target'\n ? root.querySelector<HTMLElement>('.wr-transfer__pane--target')\n : root.querySelector<HTMLElement>('.wr-transfer__pane:not(.wr-transfer__pane--target)');\n const row = pane?.querySelector<HTMLInputElement>('.wr-transfer__item input:not([disabled])');\n row?.focus();\n },\n { injector: this.injector }\n );\n }\n\n protected moveRight(): void {\n if (this.disabled() || this.readonly()) return;\n // `source().checked`, not the raw staging box: rows a filter change hid are\n // neither counted nor ticked any more, so moving them would transfer rows the\n // pane never showed as chosen — and, since staging outlives an external write\n // to `value`, could land the same value on the right twice.\n const moving = this.source().checked;\n if (moving.length === 0) return;\n this.value.set([...this.selected(), ...moving]);\n this.sourceChecked.set([]);\n this.touch.emit();\n this.restoreFocusAfterMove('target');\n }\n\n protected moveLeft(): void {\n if (this.disabled() || this.readonly()) return;\n const moving = new Set(this.target().checked);\n if (moving.size === 0) return;\n this.value.set(this.selected().filter(v => !moving.has(v)));\n this.targetChecked.set([]);\n this.touch.emit();\n this.restoreFocusAfterMove('source');\n }\n\n /** Filter, then derive the header state from what survived. */\n private pane(rows: readonly WrTransferItem[], query: string, checked: readonly unknown[]): PaneState {\n const q = query.trim().toLowerCase();\n const visible = q ? rows.filter(item => item.label.toLowerCase().includes(q)) : rows;\n const enabled = visible.filter(item => !item.disabled);\n const staged = new Set(checked);\n const shown = enabled.filter(item => staged.has(item.value)).map(item => item.value);\n return {\n rows: visible,\n checked: shown,\n checkedCount: shown.length,\n enabledCount: enabled.length,\n allChecked: enabled.length > 0 && shown.length === enabled.length,\n someChecked: shown.length > 0 && shown.length < enabled.length,\n };\n }\n}\n","<!--\n Two panes and the buttons between them. Each pane is a PLAIN `<ul>` of\n checkboxes, deliberately: dressing it as a `role=\"listbox\"` of `role=\"option\"`\n rows reads better in the abstract but is invalid — an option may not contain an\n interactive control, and the axe gate says so. The checkbox is the thing the\n user operates, so it is the thing the semantics should describe; the pane\n heading names the group.\n-->\n@for (pane of panes; track pane) {\n @let state = pane === 'source' ? source() : target();\n @let title = pane === 'source' ? resolvedSourceTitle() : resolvedTargetTitle();\n\n <div class=\"wr-transfer__pane\" [class.wr-transfer__pane--target]=\"pane === 'target'\">\n <div class=\"wr-transfer__head\">\n <wr-checkbox\n size=\"sm\"\n [checked]=\"state.allChecked\"\n [indeterminate]=\"state.someChecked\"\n [disabled]=\"disabled() || state.enabledCount === 0\"\n [readonly]=\"readonly()\"\n [ariaLabel]=\"selectAllAria({ action: resolvedSelectAll(), pane: title })\"\n (checkedChange)=\"toggleAll(pane, $event)\"\n />\n <span class=\"wr-transfer__title\">{{ title }}</span>\n <span class=\"wr-transfer__count\">{{\n countLabel({ checked: state.checkedCount, total: state.rows.length })\n }}</span>\n </div>\n\n @if (searchable()) {\n <div class=\"wr-transfer__search\">\n <input\n wrInput\n size=\"sm\"\n type=\"search\"\n [placeholder]=\"resolvedSearch()\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"`${title} — ${resolvedSearch()}`\"\n (input)=\"onSearch(pane, $event)\"\n />\n </div>\n }\n\n <ul class=\"wr-transfer__list\" [attr.aria-label]=\"title\">\n @for (item of state.rows; track item.value) {\n <li class=\"wr-transfer__item\" [class.wr-transfer__item--disabled]=\"item.disabled\">\n <wr-checkbox\n size=\"sm\"\n [checked]=\"isChecked(pane, item)\"\n [disabled]=\"disabled() || !!item.disabled\"\n [readonly]=\"readonly()\"\n (checkedChange)=\"toggle(pane, item, $event)\"\n (touch)=\"touch.emit()\"\n >\n {{ item.label }}\n </wr-checkbox>\n </li>\n } @empty {\n <li class=\"wr-transfer__empty\">{{ resolvedEmpty() }}</li>\n }\n </ul>\n </div>\n\n <!-- The buttons live between the panes, so they are emitted after the first. -->\n @if (pane === 'source') {\n <div class=\"wr-transfer__actions\">\n <button\n wr-btn\n type=\"button\"\n size=\"sm\"\n color=\"primary\"\n outlined\n class=\"wr-transfer__move wr-transfer__move--to-target\"\n [disabled]=\"!canMoveRight()\"\n [attr.aria-label]=\"resolvedToTarget()\"\n (click)=\"moveRight()\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n </button>\n <button\n wr-btn\n type=\"button\"\n size=\"sm\"\n color=\"primary\"\n outlined\n class=\"wr-transfer__move wr-transfer__move--to-source\"\n [disabled]=\"!canMoveLeft()\"\n [attr.aria-label]=\"resolvedToSource()\"\n (click)=\"moveLeft()\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m15 18-6-6 6-6\" />\n </svg>\n </button>\n </div>\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}