ngwr 10.2.0 → 11.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (471) hide show
  1. package/README.md +39 -19
  2. package/anchor/styles/_index.scss +4 -4
  3. package/back-top/styles/_index.scss +6 -1
  4. package/blur-text/styles/_index.scss +13 -0
  5. package/button/styles/_index.scss +11 -6
  6. package/carousel/styles/_index.scss +13 -2
  7. package/cascader/styles/_index.scss +2 -2
  8. package/circular-text/styles/_index.scss +2 -0
  9. package/collapse/styles/_index.scss +1 -1
  10. package/color-picker/styles/_index.scss +6 -1
  11. package/compare/styles/_index.scss +1 -2
  12. package/context-menu/styles/_index.scss +6 -1
  13. package/descriptions/styles/_index.scss +2 -2
  14. package/dialog/styles/_index.scss +38 -0
  15. package/drawer/styles/_index.scss +20 -1
  16. package/dropdown/styles/_index.scss +19 -5
  17. package/empty/styles/_index.scss +10 -0
  18. package/fesm2022/ngwr-action-sheet.mjs +15 -5
  19. package/fesm2022/ngwr-action-sheet.mjs.map +1 -1
  20. package/fesm2022/ngwr-affix.mjs +43 -16
  21. package/fesm2022/ngwr-affix.mjs.map +1 -1
  22. package/fesm2022/ngwr-alert.mjs +3 -3
  23. package/fesm2022/ngwr-anchor.mjs +20 -8
  24. package/fesm2022/ngwr-anchor.mjs.map +1 -1
  25. package/fesm2022/ngwr-aurora.mjs +4 -4
  26. package/fesm2022/ngwr-aurora.mjs.map +1 -1
  27. package/fesm2022/ngwr-avatar.mjs +33 -9
  28. package/fesm2022/ngwr-avatar.mjs.map +1 -1
  29. package/fesm2022/ngwr-back-top.mjs +8 -4
  30. package/fesm2022/ngwr-back-top.mjs.map +1 -1
  31. package/fesm2022/ngwr-badge.mjs +6 -6
  32. package/fesm2022/ngwr-badge.mjs.map +1 -1
  33. package/fesm2022/ngwr-bar-chart.mjs +32 -11
  34. package/fesm2022/ngwr-bar-chart.mjs.map +1 -1
  35. package/fesm2022/ngwr-blur-text.mjs +4 -4
  36. package/fesm2022/ngwr-blur-text.mjs.map +1 -1
  37. package/fesm2022/ngwr-border-glow.mjs +4 -4
  38. package/fesm2022/ngwr-border-glow.mjs.map +1 -1
  39. package/fesm2022/ngwr-breadcrumbs.mjs +9 -8
  40. package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
  41. package/fesm2022/ngwr-burger.mjs +11 -6
  42. package/fesm2022/ngwr-burger.mjs.map +1 -1
  43. package/fesm2022/ngwr-button-testing.mjs +96 -0
  44. package/fesm2022/ngwr-button-testing.mjs.map +1 -0
  45. package/fesm2022/ngwr-button.mjs +89 -24
  46. package/fesm2022/ngwr-button.mjs.map +1 -1
  47. package/fesm2022/ngwr-calendar-heatmap.mjs +42 -10
  48. package/fesm2022/ngwr-calendar-heatmap.mjs.map +1 -1
  49. package/fesm2022/ngwr-calendar.mjs +108 -9
  50. package/fesm2022/ngwr-calendar.mjs.map +1 -1
  51. package/fesm2022/ngwr-card.mjs +10 -10
  52. package/fesm2022/ngwr-card.mjs.map +1 -1
  53. package/fesm2022/ngwr-carousel-testing.mjs +377 -0
  54. package/fesm2022/ngwr-carousel-testing.mjs.map +1 -0
  55. package/fesm2022/ngwr-carousel.mjs +72 -18
  56. package/fesm2022/ngwr-carousel.mjs.map +1 -1
  57. package/fesm2022/ngwr-cascader-testing.mjs +534 -0
  58. package/fesm2022/ngwr-cascader-testing.mjs.map +1 -0
  59. package/fesm2022/ngwr-cascader.mjs +4 -4
  60. package/fesm2022/ngwr-cascader.mjs.map +1 -1
  61. package/fesm2022/ngwr-checkbox-testing.mjs +90 -0
  62. package/fesm2022/ngwr-checkbox-testing.mjs.map +1 -0
  63. package/fesm2022/ngwr-checkbox.mjs +15 -9
  64. package/fesm2022/ngwr-checkbox.mjs.map +1 -1
  65. package/fesm2022/ngwr-circular-text.mjs +4 -4
  66. package/fesm2022/ngwr-circular-text.mjs.map +1 -1
  67. package/fesm2022/ngwr-click-spark.mjs +4 -4
  68. package/fesm2022/ngwr-click-spark.mjs.map +1 -1
  69. package/fesm2022/ngwr-clipboard.mjs +18 -4
  70. package/fesm2022/ngwr-clipboard.mjs.map +1 -1
  71. package/fesm2022/ngwr-collapse-testing.mjs +368 -0
  72. package/fesm2022/ngwr-collapse-testing.mjs.map +1 -0
  73. package/fesm2022/ngwr-collapse.mjs +9 -9
  74. package/fesm2022/ngwr-color-picker.mjs +139 -19
  75. package/fesm2022/ngwr-color-picker.mjs.map +1 -1
  76. package/fesm2022/ngwr-command-palette-testing.mjs +589 -0
  77. package/fesm2022/ngwr-command-palette-testing.mjs.map +1 -0
  78. package/fesm2022/ngwr-command-palette.mjs +60 -10
  79. package/fesm2022/ngwr-command-palette.mjs.map +1 -1
  80. package/fesm2022/ngwr-compare.mjs +105 -15
  81. package/fesm2022/ngwr-compare.mjs.map +1 -1
  82. package/fesm2022/ngwr-confetti.mjs +3 -3
  83. package/fesm2022/ngwr-config.mjs +106 -0
  84. package/fesm2022/ngwr-config.mjs.map +1 -0
  85. package/fesm2022/ngwr-context-menu-testing.mjs +631 -0
  86. package/fesm2022/ngwr-context-menu-testing.mjs.map +1 -0
  87. package/fesm2022/ngwr-context-menu.mjs +104 -18
  88. package/fesm2022/ngwr-context-menu.mjs.map +1 -1
  89. package/fesm2022/ngwr-cookie.mjs +8 -4
  90. package/fesm2022/ngwr-cookie.mjs.map +1 -1
  91. package/fesm2022/ngwr-counter.mjs +17 -9
  92. package/fesm2022/ngwr-counter.mjs.map +1 -1
  93. package/fesm2022/ngwr-date-adapter-fns.mjs +3 -3
  94. package/fesm2022/ngwr-date-adapter-luxon.mjs +55 -7
  95. package/fesm2022/ngwr-date-adapter-luxon.mjs.map +1 -1
  96. package/fesm2022/ngwr-date-adapter.mjs +57 -11
  97. package/fesm2022/ngwr-date-adapter.mjs.map +1 -1
  98. package/fesm2022/ngwr-date-picker-testing.mjs +766 -0
  99. package/fesm2022/ngwr-date-picker-testing.mjs.map +1 -0
  100. package/fesm2022/ngwr-date-picker.mjs +409 -57
  101. package/fesm2022/ngwr-date-picker.mjs.map +1 -1
  102. package/fesm2022/ngwr-decrypt-text.mjs +30 -12
  103. package/fesm2022/ngwr-decrypt-text.mjs.map +1 -1
  104. package/fesm2022/ngwr-density.mjs +6 -6
  105. package/fesm2022/ngwr-descriptions.mjs +6 -6
  106. package/fesm2022/ngwr-dialog-testing.mjs +89 -0
  107. package/fesm2022/ngwr-dialog-testing.mjs.map +1 -0
  108. package/fesm2022/ngwr-dialog.mjs +33 -17
  109. package/fesm2022/ngwr-dialog.mjs.map +1 -1
  110. package/fesm2022/ngwr-directives.mjs +48 -24
  111. package/fesm2022/ngwr-directives.mjs.map +1 -1
  112. package/fesm2022/ngwr-divider.mjs +3 -3
  113. package/fesm2022/ngwr-donut-chart.mjs +24 -7
  114. package/fesm2022/ngwr-donut-chart.mjs.map +1 -1
  115. package/fesm2022/ngwr-drag-drop.mjs +7 -7
  116. package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
  117. package/fesm2022/ngwr-drawer-testing.mjs +250 -0
  118. package/fesm2022/ngwr-drawer-testing.mjs.map +1 -0
  119. package/fesm2022/ngwr-drawer.mjs +37 -19
  120. package/fesm2022/ngwr-drawer.mjs.map +1 -1
  121. package/fesm2022/ngwr-dropdown-testing.mjs +291 -0
  122. package/fesm2022/ngwr-dropdown-testing.mjs.map +1 -0
  123. package/fesm2022/ngwr-dropdown.mjs +19 -11
  124. package/fesm2022/ngwr-dropdown.mjs.map +1 -1
  125. package/fesm2022/ngwr-empty.mjs +26 -9
  126. package/fesm2022/ngwr-empty.mjs.map +1 -1
  127. package/fesm2022/ngwr-event-calendar.mjs +62 -15
  128. package/fesm2022/ngwr-event-calendar.mjs.map +1 -1
  129. package/fesm2022/ngwr-falling-text.mjs +4 -4
  130. package/fesm2022/ngwr-falling-text.mjs.map +1 -1
  131. package/fesm2022/ngwr-file-upload-testing.mjs +332 -0
  132. package/fesm2022/ngwr-file-upload-testing.mjs.map +1 -0
  133. package/fesm2022/ngwr-file-upload.mjs +3 -3
  134. package/fesm2022/ngwr-form-testing.mjs +451 -0
  135. package/fesm2022/ngwr-form-testing.mjs.map +1 -0
  136. package/fesm2022/ngwr-form.mjs +28 -12
  137. package/fesm2022/ngwr-form.mjs.map +1 -1
  138. package/fesm2022/ngwr-fuzzy-text.mjs +11 -4
  139. package/fesm2022/ngwr-fuzzy-text.mjs.map +1 -1
  140. package/fesm2022/ngwr-gauge.mjs +21 -7
  141. package/fesm2022/ngwr-gauge.mjs.map +1 -1
  142. package/fesm2022/ngwr-glitch-text.mjs +4 -4
  143. package/fesm2022/ngwr-glitch-text.mjs.map +1 -1
  144. package/fesm2022/ngwr-gradient-text.mjs +4 -4
  145. package/fesm2022/ngwr-gradient-text.mjs.map +1 -1
  146. package/fesm2022/ngwr-hotkey.mjs +31 -10
  147. package/fesm2022/ngwr-hotkey.mjs.map +1 -1
  148. package/fesm2022/ngwr-i18n-en.mjs +61 -0
  149. package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
  150. package/fesm2022/ngwr-i18n-ru.mjs +59 -0
  151. package/fesm2022/ngwr-i18n-ru.mjs.map +1 -1
  152. package/fesm2022/ngwr-i18n.mjs +9 -9
  153. package/fesm2022/ngwr-icon.mjs +6 -6
  154. package/fesm2022/ngwr-image-cropper.mjs +26 -3
  155. package/fesm2022/ngwr-image-cropper.mjs.map +1 -1
  156. package/fesm2022/ngwr-input-number-testing.mjs +306 -0
  157. package/fesm2022/ngwr-input-number-testing.mjs.map +1 -0
  158. package/fesm2022/ngwr-input-number.mjs +37 -5
  159. package/fesm2022/ngwr-input-number.mjs.map +1 -1
  160. package/fesm2022/ngwr-input-otp-testing.mjs +419 -0
  161. package/fesm2022/ngwr-input-otp-testing.mjs.map +1 -0
  162. package/fesm2022/ngwr-input-otp.mjs +39 -8
  163. package/fesm2022/ngwr-input-otp.mjs.map +1 -1
  164. package/fesm2022/ngwr-input-testing.mjs +102 -0
  165. package/fesm2022/ngwr-input-testing.mjs.map +1 -0
  166. package/fesm2022/ngwr-input.mjs +62 -25
  167. package/fesm2022/ngwr-input.mjs.map +1 -1
  168. package/fesm2022/ngwr-keyboard.mjs +3 -3
  169. package/fesm2022/ngwr-knob.mjs +46 -10
  170. package/fesm2022/ngwr-knob.mjs.map +1 -1
  171. package/fesm2022/ngwr-layout.mjs +36 -20
  172. package/fesm2022/ngwr-layout.mjs.map +1 -1
  173. package/fesm2022/ngwr-lightbox.mjs +35 -8
  174. package/fesm2022/ngwr-lightbox.mjs.map +1 -1
  175. package/fesm2022/ngwr-line-chart.mjs +19 -6
  176. package/fesm2022/ngwr-line-chart.mjs.map +1 -1
  177. package/fesm2022/ngwr-list.mjs +14 -9
  178. package/fesm2022/ngwr-list.mjs.map +1 -1
  179. package/fesm2022/ngwr-loading-bar.mjs +71 -31
  180. package/fesm2022/ngwr-loading-bar.mjs.map +1 -1
  181. package/fesm2022/ngwr-markdown-testing.mjs +516 -0
  182. package/fesm2022/ngwr-markdown-testing.mjs.map +1 -0
  183. package/fesm2022/ngwr-markdown.mjs +1492 -0
  184. package/fesm2022/ngwr-markdown.mjs.map +1 -0
  185. package/fesm2022/ngwr-marquee.mjs +19 -8
  186. package/fesm2022/ngwr-marquee.mjs.map +1 -1
  187. package/fesm2022/ngwr-media.mjs +3 -3
  188. package/fesm2022/ngwr-mention-testing.mjs +513 -0
  189. package/fesm2022/ngwr-mention-testing.mjs.map +1 -0
  190. package/fesm2022/ngwr-mention.mjs +16 -7
  191. package/fesm2022/ngwr-mention.mjs.map +1 -1
  192. package/fesm2022/ngwr-meta.mjs +28 -13
  193. package/fesm2022/ngwr-meta.mjs.map +1 -1
  194. package/fesm2022/ngwr-meter-group.mjs +22 -8
  195. package/fesm2022/ngwr-meter-group.mjs.map +1 -1
  196. package/fesm2022/ngwr-overlay.mjs +57 -8
  197. package/fesm2022/ngwr-overlay.mjs.map +1 -1
  198. package/fesm2022/ngwr-page-header.mjs +3 -3
  199. package/fesm2022/ngwr-pagination-testing.mjs +389 -0
  200. package/fesm2022/ngwr-pagination-testing.mjs.map +1 -0
  201. package/fesm2022/ngwr-pagination.mjs +27 -11
  202. package/fesm2022/ngwr-pagination.mjs.map +1 -1
  203. package/fesm2022/ngwr-pipes.mjs +21 -21
  204. package/fesm2022/ngwr-platform.mjs +9 -9
  205. package/fesm2022/ngwr-popconfirm-testing.mjs +309 -0
  206. package/fesm2022/ngwr-popconfirm-testing.mjs.map +1 -0
  207. package/fesm2022/ngwr-popconfirm.mjs +99 -21
  208. package/fesm2022/ngwr-popconfirm.mjs.map +1 -1
  209. package/fesm2022/ngwr-popover-testing.mjs +316 -0
  210. package/fesm2022/ngwr-popover-testing.mjs.map +1 -0
  211. package/fesm2022/ngwr-popover.mjs +48 -10
  212. package/fesm2022/ngwr-popover.mjs.map +1 -1
  213. package/fesm2022/ngwr-progress.mjs +3 -3
  214. package/fesm2022/ngwr-pull-to-refresh.mjs +19 -4
  215. package/fesm2022/ngwr-pull-to-refresh.mjs.map +1 -1
  216. package/fesm2022/ngwr-qr.mjs +15 -5
  217. package/fesm2022/ngwr-qr.mjs.map +1 -1
  218. package/fesm2022/ngwr-radio-testing.mjs +392 -0
  219. package/fesm2022/ngwr-radio-testing.mjs.map +1 -0
  220. package/fesm2022/ngwr-radio.mjs +16 -9
  221. package/fesm2022/ngwr-radio.mjs.map +1 -1
  222. package/fesm2022/ngwr-rating-testing.mjs +384 -0
  223. package/fesm2022/ngwr-rating-testing.mjs.map +1 -0
  224. package/fesm2022/ngwr-rating.mjs +40 -5
  225. package/fesm2022/ngwr-rating.mjs.map +1 -1
  226. package/fesm2022/ngwr-result.mjs +12 -12
  227. package/fesm2022/ngwr-rotating-text.mjs +3 -3
  228. package/fesm2022/ngwr-scroll.mjs +3 -3
  229. package/fesm2022/ngwr-segmented-testing.mjs +512 -0
  230. package/fesm2022/ngwr-segmented-testing.mjs.map +1 -0
  231. package/fesm2022/ngwr-segmented.mjs +3 -3
  232. package/fesm2022/ngwr-select-testing.mjs +268 -0
  233. package/fesm2022/ngwr-select-testing.mjs.map +1 -0
  234. package/fesm2022/ngwr-select.mjs +96 -25
  235. package/fesm2022/ngwr-select.mjs.map +1 -1
  236. package/fesm2022/ngwr-shiny-text.mjs +7 -7
  237. package/fesm2022/ngwr-shiny-text.mjs.map +1 -1
  238. package/fesm2022/ngwr-sidebar.mjs +67 -14
  239. package/fesm2022/ngwr-sidebar.mjs.map +1 -1
  240. package/fesm2022/ngwr-skeleton.mjs +3 -3
  241. package/fesm2022/ngwr-slider-testing.mjs +478 -0
  242. package/fesm2022/ngwr-slider-testing.mjs.map +1 -0
  243. package/fesm2022/ngwr-slider.mjs +59 -15
  244. package/fesm2022/ngwr-slider.mjs.map +1 -1
  245. package/fesm2022/ngwr-sparkline.mjs +28 -8
  246. package/fesm2022/ngwr-sparkline.mjs.map +1 -1
  247. package/fesm2022/ngwr-speed-dial.mjs +39 -6
  248. package/fesm2022/ngwr-speed-dial.mjs.map +1 -1
  249. package/fesm2022/ngwr-spinner.mjs +14 -5
  250. package/fesm2022/ngwr-spinner.mjs.map +1 -1
  251. package/fesm2022/ngwr-splash-cursor.mjs +4 -4
  252. package/fesm2022/ngwr-splash-cursor.mjs.map +1 -1
  253. package/fesm2022/ngwr-split-text.mjs +4 -4
  254. package/fesm2022/ngwr-split-text.mjs.map +1 -1
  255. package/fesm2022/ngwr-splitter.mjs +72 -11
  256. package/fesm2022/ngwr-splitter.mjs.map +1 -1
  257. package/fesm2022/ngwr-spotlight-card.mjs +7 -7
  258. package/fesm2022/ngwr-spotlight-card.mjs.map +1 -1
  259. package/fesm2022/ngwr-squircle.mjs +6 -6
  260. package/fesm2022/ngwr-star-border.mjs +4 -4
  261. package/fesm2022/ngwr-star-border.mjs.map +1 -1
  262. package/fesm2022/ngwr-statistic.mjs +33 -16
  263. package/fesm2022/ngwr-statistic.mjs.map +1 -1
  264. package/fesm2022/ngwr-stepper-testing.mjs +477 -0
  265. package/fesm2022/ngwr-stepper-testing.mjs.map +1 -0
  266. package/fesm2022/ngwr-stepper.mjs +6 -6
  267. package/fesm2022/ngwr-storage.mjs +27 -17
  268. package/fesm2022/ngwr-storage.mjs.map +1 -1
  269. package/fesm2022/ngwr-switch-testing.mjs +77 -0
  270. package/fesm2022/ngwr-switch-testing.mjs.map +1 -0
  271. package/fesm2022/ngwr-switch.mjs +12 -6
  272. package/fesm2022/ngwr-switch.mjs.map +1 -1
  273. package/fesm2022/ngwr-table-testing.mjs +580 -0
  274. package/fesm2022/ngwr-table-testing.mjs.map +1 -0
  275. package/fesm2022/ngwr-table.mjs +105 -44
  276. package/fesm2022/ngwr-table.mjs.map +1 -1
  277. package/fesm2022/ngwr-tabs-testing.mjs +617 -0
  278. package/fesm2022/ngwr-tabs-testing.mjs.map +1 -0
  279. package/fesm2022/ngwr-tabs.mjs +44 -12
  280. package/fesm2022/ngwr-tabs.mjs.map +1 -1
  281. package/fesm2022/ngwr-textarea-testing.mjs +238 -0
  282. package/fesm2022/ngwr-textarea-testing.mjs.map +1 -0
  283. package/fesm2022/ngwr-textarea.mjs +35 -7
  284. package/fesm2022/ngwr-textarea.mjs.map +1 -1
  285. package/fesm2022/ngwr-theme.mjs +3 -3
  286. package/fesm2022/ngwr-tilt-card.mjs +7 -7
  287. package/fesm2022/ngwr-tilt-card.mjs.map +1 -1
  288. package/fesm2022/ngwr-timeline.mjs +6 -6
  289. package/fesm2022/ngwr-toast-testing.mjs +101 -0
  290. package/fesm2022/ngwr-toast-testing.mjs.map +1 -0
  291. package/fesm2022/ngwr-toast.mjs +55 -21
  292. package/fesm2022/ngwr-toast.mjs.map +1 -1
  293. package/fesm2022/ngwr-toolbar.mjs +3 -3
  294. package/fesm2022/ngwr-tour.mjs +67 -15
  295. package/fesm2022/ngwr-tour.mjs.map +1 -1
  296. package/fesm2022/ngwr-transfer-testing.mjs +538 -0
  297. package/fesm2022/ngwr-transfer-testing.mjs.map +1 -0
  298. package/fesm2022/ngwr-transfer.mjs +47 -16
  299. package/fesm2022/ngwr-transfer.mjs.map +1 -1
  300. package/fesm2022/ngwr-tree-testing.mjs +734 -0
  301. package/fesm2022/ngwr-tree-testing.mjs.map +1 -0
  302. package/fesm2022/ngwr-tree.mjs +75 -9
  303. package/fesm2022/ngwr-tree.mjs.map +1 -1
  304. package/fesm2022/ngwr-typewriter.mjs +7 -5
  305. package/fesm2022/ngwr-typewriter.mjs.map +1 -1
  306. package/fesm2022/ngwr-typography.mjs +3 -3
  307. package/fesm2022/ngwr-version.mjs +1 -1
  308. package/fesm2022/ngwr-version.mjs.map +1 -1
  309. package/fesm2022/ngwr-virtual-scroll.mjs +33 -7
  310. package/fesm2022/ngwr-virtual-scroll.mjs.map +1 -1
  311. package/fesm2022/ngwr-waves.mjs +5 -5
  312. package/fesm2022/ngwr-waves.mjs.map +1 -1
  313. package/fesm2022/ngwr-window.mjs +88 -18
  314. package/fesm2022/ngwr-window.mjs.map +1 -1
  315. package/gauge/styles/_index.scss +1 -1
  316. package/glitch-text/styles/_index.scss +4 -0
  317. package/i18n/en.json +56 -0
  318. package/i18n/ru.json +56 -0
  319. package/image-cropper/styles/_index.scss +13 -1
  320. package/input/styles/_index.scss +2 -2
  321. package/input-number/styles/_index.scss +7 -2
  322. package/knob/styles/_index.scss +8 -1
  323. package/layout/styles/_index.scss +3 -3
  324. package/lightbox/styles/_index.scss +10 -2
  325. package/line-chart/styles/_index.scss +6 -0
  326. package/llms-full.txt +151 -4
  327. package/llms.txt +57 -8
  328. package/loading-bar/styles/_index.scss +1 -2
  329. package/markdown/styles/_index.scss +296 -0
  330. package/marquee/styles/_index.scss +12 -0
  331. package/mcp/api.js +512 -0
  332. package/mcp/catalog.js +157 -0
  333. package/mcp/server.js +273 -0
  334. package/mcp/tools.js +366 -0
  335. package/meter-group/styles/_index.scss +1 -1
  336. package/package.json +186 -35
  337. package/pagination/styles/_index.scss +6 -6
  338. package/popover/styles/_index.scss +37 -5
  339. package/rating/styles/_index.scss +10 -0
  340. package/schematics/use/symbol-map.json +2 -0
  341. package/segmented/styles/_index.scss +7 -0
  342. package/select/styles/_index.scss +29 -9
  343. package/sidebar/styles/_index.scss +30 -5
  344. package/slider/styles/_index.scss +15 -0
  345. package/speed-dial/styles/_index.scss +20 -0
  346. package/split-text/styles/_index.scss +13 -0
  347. package/star-border/styles/_index.scss +2 -0
  348. package/stepper/styles/_index.scss +1 -1
  349. package/styles/_grid.scss +4 -4
  350. package/styles.scss +1 -0
  351. package/switch/styles/_index.scss +5 -3
  352. package/table/styles/_index.scss +22 -11
  353. package/tabs/styles/_index.scss +11 -1
  354. package/textarea/styles/_index.scss +5 -0
  355. package/theme/styles/_colors.scss +29 -13
  356. package/theme/styles/_dark.scss +11 -3
  357. package/theme/styles/_mixins.scss +3 -0
  358. package/timeline/styles/_index.scss +2 -2
  359. package/toast/styles/_index.scss +17 -8
  360. package/toolbar/styles/_index.scss +3 -3
  361. package/tour/styles/_index.scss +7 -1
  362. package/tree/styles/_index.scss +5 -3
  363. package/types/ngwr-action-sheet.d.ts +9 -1
  364. package/types/ngwr-affix.d.ts +7 -1
  365. package/types/ngwr-anchor.d.ts +8 -1
  366. package/types/ngwr-avatar.d.ts +13 -3
  367. package/types/ngwr-bar-chart.d.ts +16 -0
  368. package/types/ngwr-burger.d.ts +6 -2
  369. package/types/ngwr-button-testing.d.ts +85 -0
  370. package/types/ngwr-button.d.ts +58 -10
  371. package/types/ngwr-calendar-heatmap.d.ts +16 -2
  372. package/types/ngwr-calendar.d.ts +37 -1
  373. package/types/ngwr-carousel-testing.d.ts +257 -0
  374. package/types/ngwr-carousel.d.ts +20 -4
  375. package/types/ngwr-cascader-testing.d.ts +392 -0
  376. package/types/ngwr-checkbox-testing.d.ts +77 -0
  377. package/types/ngwr-checkbox.d.ts +7 -2
  378. package/types/ngwr-clipboard.d.ts +8 -1
  379. package/types/ngwr-collapse-testing.d.ts +290 -0
  380. package/types/ngwr-color-picker.d.ts +20 -11
  381. package/types/ngwr-command-palette-testing.d.ts +437 -0
  382. package/types/ngwr-command-palette.d.ts +25 -2
  383. package/types/ngwr-compare.d.ts +50 -2
  384. package/types/ngwr-config.d.ts +176 -0
  385. package/types/ngwr-context-menu-testing.d.ts +401 -0
  386. package/types/ngwr-context-menu.d.ts +65 -17
  387. package/types/ngwr-counter.d.ts +6 -1
  388. package/types/ngwr-date-adapter-luxon.d.ts +26 -0
  389. package/types/ngwr-date-picker-testing.d.ts +518 -0
  390. package/types/ngwr-date-picker.d.ts +128 -8
  391. package/types/ngwr-dialog-testing.d.ts +79 -0
  392. package/types/ngwr-dialog.d.ts +13 -0
  393. package/types/ngwr-directives.d.ts +10 -1
  394. package/types/ngwr-donut-chart.d.ts +8 -1
  395. package/types/ngwr-drawer-testing.d.ts +196 -0
  396. package/types/ngwr-drawer.d.ts +15 -0
  397. package/types/ngwr-dropdown-testing.d.ts +202 -0
  398. package/types/ngwr-dropdown.d.ts +7 -1
  399. package/types/ngwr-empty.d.ts +19 -4
  400. package/types/ngwr-event-calendar.d.ts +26 -1
  401. package/types/ngwr-file-upload-testing.d.ts +194 -0
  402. package/types/ngwr-form-testing.d.ts +379 -0
  403. package/types/ngwr-form.d.ts +17 -0
  404. package/types/ngwr-gauge.d.ts +13 -1
  405. package/types/ngwr-hotkey.d.ts +2 -0
  406. package/types/ngwr-image-cropper.d.ts +10 -0
  407. package/types/ngwr-input-number-testing.d.ts +226 -0
  408. package/types/ngwr-input-number.d.ts +29 -1
  409. package/types/ngwr-input-otp-testing.d.ts +299 -0
  410. package/types/ngwr-input-otp.d.ts +23 -2
  411. package/types/ngwr-input-testing.d.ts +84 -0
  412. package/types/ngwr-input.d.ts +20 -6
  413. package/types/ngwr-knob.d.ts +18 -0
  414. package/types/ngwr-layout.d.ts +1 -0
  415. package/types/ngwr-lightbox.d.ts +17 -3
  416. package/types/ngwr-line-chart.d.ts +9 -2
  417. package/types/ngwr-list.d.ts +7 -2
  418. package/types/ngwr-loading-bar.d.ts +4 -7
  419. package/types/ngwr-markdown-testing.d.ts +462 -0
  420. package/types/ngwr-markdown.d.ts +534 -0
  421. package/types/ngwr-marquee.d.ts +12 -2
  422. package/types/ngwr-mention-testing.d.ts +359 -0
  423. package/types/ngwr-meta.d.ts +4 -2
  424. package/types/ngwr-meter-group.d.ts +11 -1
  425. package/types/ngwr-overlay.d.ts +33 -2
  426. package/types/ngwr-pagination-testing.d.ts +291 -0
  427. package/types/ngwr-pagination.d.ts +7 -1
  428. package/types/ngwr-popconfirm-testing.d.ts +235 -0
  429. package/types/ngwr-popconfirm.d.ts +31 -21
  430. package/types/ngwr-popover-testing.d.ts +221 -0
  431. package/types/ngwr-popover.d.ts +19 -2
  432. package/types/ngwr-pull-to-refresh.d.ts +7 -0
  433. package/types/ngwr-qr.d.ts +9 -1
  434. package/types/ngwr-radio-testing.d.ts +296 -0
  435. package/types/ngwr-radio.d.ts +8 -2
  436. package/types/ngwr-rating-testing.d.ts +291 -0
  437. package/types/ngwr-rating.d.ts +23 -0
  438. package/types/ngwr-segmented-testing.d.ts +401 -0
  439. package/types/ngwr-select-testing.d.ts +175 -0
  440. package/types/ngwr-select.d.ts +45 -4
  441. package/types/ngwr-sidebar.d.ts +17 -2
  442. package/types/ngwr-slider-testing.d.ts +329 -0
  443. package/types/ngwr-slider.d.ts +35 -1
  444. package/types/ngwr-sparkline.d.ts +12 -2
  445. package/types/ngwr-speed-dial.d.ts +17 -18
  446. package/types/ngwr-spinner.d.ts +8 -1
  447. package/types/ngwr-splitter.d.ts +24 -1
  448. package/types/ngwr-statistic.d.ts +12 -2
  449. package/types/ngwr-stepper-testing.d.ts +346 -0
  450. package/types/ngwr-storage.d.ts +10 -1
  451. package/types/ngwr-switch-testing.d.ts +66 -0
  452. package/types/ngwr-switch.d.ts +7 -2
  453. package/types/ngwr-table-testing.d.ts +423 -0
  454. package/types/ngwr-table.d.ts +42 -0
  455. package/types/ngwr-tabs-testing.d.ts +470 -0
  456. package/types/ngwr-tabs.d.ts +9 -0
  457. package/types/ngwr-textarea-testing.d.ts +184 -0
  458. package/types/ngwr-textarea.d.ts +7 -2
  459. package/types/ngwr-toast-testing.d.ts +80 -0
  460. package/types/ngwr-toast.d.ts +19 -4
  461. package/types/ngwr-tour.d.ts +27 -0
  462. package/types/ngwr-transfer-testing.d.ts +444 -0
  463. package/types/ngwr-transfer.d.ts +16 -1
  464. package/types/ngwr-tree-testing.d.ts +501 -0
  465. package/types/ngwr-tree.d.ts +33 -0
  466. package/types/ngwr-version.d.ts +1 -1
  467. package/types/ngwr-virtual-scroll.d.ts +13 -1
  468. package/types/ngwr-window.d.ts +23 -2
  469. package/typewriter/styles/_index.scss +1 -1
  470. package/typography/styles/_index.scss +1 -1
  471. package/window/styles/_index.scss +32 -9
@@ -2,15 +2,13 @@ import { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coerci
2
2
  import { ScrollStrategyOptions } from '@angular/cdk/overlay';
3
3
  import { ComponentPortal } from '@angular/cdk/portal';
4
4
  import * as i0 from '@angular/core';
5
- import { input, inject, model, output, signal, computed, effect, untracked, ViewEncapsulation, Component, ElementRef, DestroyRef, viewChild } from '@angular/core';
5
+ import { input, inject, ElementRef, model, output, signal, computed, afterNextRender, effect, untracked, ViewEncapsulation, Component, DestroyRef, viewChild } from '@angular/core';
6
6
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
7
7
  import { WrCalendar } from 'ngwr/calendar';
8
8
  import { WrDateAdapter, WR_DATE_LOCALE } from 'ngwr/date-adapter';
9
9
  import { readI18nText, useI18nText } from 'ngwr/i18n';
10
10
  import { WrInput, WrInputGroup, WrInputSuffix } from 'ngwr/input';
11
11
  import { WR_OVERLAY, WrOutsideClick } from 'ngwr/overlay';
12
- import * as i1 from '@angular/forms';
13
- import { FormsModule } from '@angular/forms';
14
12
  import { clamp } from 'ngwr/utils';
15
13
 
16
14
  /**
@@ -54,7 +52,13 @@ class WrTimePanel {
54
52
  disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
55
53
  /** Read-only — values cannot be changed. @default false */
56
54
  readonly = input(false, { ...(ngDevMode ? { debugName: "readonly" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
55
+ /**
56
+ * Move focus onto the hours field once the panel is on screen. Off by
57
+ * default — see `WrCalendar.autoFocus` for why. @default false
58
+ */
59
+ autoFocus = input(false, { ...(ngDevMode ? { debugName: "autoFocus" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
57
60
  adapter = inject(WrDateAdapter);
61
+ host = inject(ElementRef);
58
62
  locale = inject(WR_DATE_LOCALE);
59
63
  /**
60
64
  * Form value — the selected time as a `Date` (its date portion is preserved).
@@ -78,6 +82,14 @@ class WrTimePanel {
78
82
  effectiveDisabled = computed(() => this.disabled(), /* @ts-ignore */
79
83
  ...(ngDevMode ? [{ debugName: "effectiveDisabled" }] : /* istanbul ignore next */ []));
80
84
  constructor() {
85
+ // The hours field, not the increment button: a stepper is a shortcut, the
86
+ // number is the control. Deferred because the inputs are not in the DOM
87
+ // until the panel's first change-detection pass.
88
+ afterNextRender(() => {
89
+ if (!this.autoFocus())
90
+ return;
91
+ this.host.nativeElement.querySelector('.wr-time-picker__input')?.focus();
92
+ });
81
93
  // Mirror an external `value` write into the internal h/m/s state (the old
82
94
  // `writeValue` body). Guarded against the echo of our own `emit()` so a live
83
95
  // edit is never clobbered by re-deriving it.
@@ -146,7 +158,12 @@ class WrTimePanel {
146
158
  lastEmitted = null;
147
159
  // Typed-input handlers
148
160
  onHoursInput(event) {
149
- const n = Number(event.target.value);
161
+ const raw = event.target.value;
162
+ // An emptied box is someone mid-retype, not a request for zero: `Number('')`
163
+ // is 0, so committing here rewrote the field they had just cleared.
164
+ if (!raw.trim())
165
+ return;
166
+ const n = Number(raw);
150
167
  if (Number.isNaN(n))
151
168
  return;
152
169
  if (this.is12h()) {
@@ -159,14 +176,24 @@ class WrTimePanel {
159
176
  this.emit();
160
177
  }
161
178
  onMinutesInput(event) {
162
- const n = Number(event.target.value);
179
+ const raw = event.target.value;
180
+ // An emptied box is someone mid-retype, not a request for zero: `Number('')`
181
+ // is 0, so committing here rewrote the field they had just cleared.
182
+ if (!raw.trim())
183
+ return;
184
+ const n = Number(raw);
163
185
  if (Number.isNaN(n))
164
186
  return;
165
187
  this.minutes.set(clamp(Math.trunc(n), 0, 59));
166
188
  this.emit();
167
189
  }
168
190
  onSecondsInput(event) {
169
- const n = Number(event.target.value);
191
+ const raw = event.target.value;
192
+ // An emptied box is someone mid-retype, not a request for zero: `Number('')`
193
+ // is 0, so committing here rewrote the field they had just cleared.
194
+ if (!raw.trim())
195
+ return;
196
+ const n = Number(raw);
170
197
  if (Number.isNaN(n))
171
198
  return;
172
199
  this.seconds.set(clamp(Math.trunc(n), 0, 59));
@@ -207,13 +234,13 @@ class WrTimePanel {
207
234
  this.lastEmitted = next;
208
235
  this.value.set(next);
209
236
  }
210
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrTimePanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
211
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: WrTimePanel, isStandalone: true, selector: "wr-time-picker", inputs: { format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", 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 }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: "<div class=\"wr-time-picker__col\">\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--up\"\n aria-label=\"Increment hours\"\n [disabled]=\"!interactive()\"\n (click)=\"stepHours(1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\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=\"m18 15-6-6-6 6\" />\n </svg>\n </button>\n <input\n class=\"wr-time-picker__input\"\n type=\"text\"\n inputmode=\"numeric\"\n aria-label=\"Hours\"\n [value]=\"hoursDisplay()\"\n [disabled]=\"effectiveDisabled()\"\n [readonly]=\"readonly()\"\n (input)=\"onHoursInput($event)\"\n (blur)=\"onBlur()\"\n />\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--down\"\n aria-label=\"Decrement hours\"\n [disabled]=\"!interactive()\"\n (click)=\"stepHours(-1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\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=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n</div>\n\n<span class=\"wr-time-picker__sep\" aria-hidden=\"true\">:</span>\n\n<div class=\"wr-time-picker__col\">\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--up\"\n aria-label=\"Increment minutes\"\n [disabled]=\"!interactive()\"\n (click)=\"stepMinutes(1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\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=\"m18 15-6-6-6 6\" />\n </svg>\n </button>\n <input\n class=\"wr-time-picker__input\"\n type=\"text\"\n inputmode=\"numeric\"\n aria-label=\"Minutes\"\n [value]=\"minutesDisplay()\"\n [disabled]=\"effectiveDisabled()\"\n [readonly]=\"readonly()\"\n (input)=\"onMinutesInput($event)\"\n (blur)=\"onBlur()\"\n />\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--down\"\n aria-label=\"Decrement minutes\"\n [disabled]=\"!interactive()\"\n (click)=\"stepMinutes(-1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\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=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n</div>\n\n@if (showSeconds()) {\n <span class=\"wr-time-picker__sep\" aria-hidden=\"true\">:</span>\n\n <div class=\"wr-time-picker__col\">\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--up\"\n aria-label=\"Increment seconds\"\n [disabled]=\"!interactive()\"\n (click)=\"stepSeconds(1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\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=\"m18 15-6-6-6 6\" />\n </svg>\n </button>\n <input\n class=\"wr-time-picker__input\"\n type=\"text\"\n inputmode=\"numeric\"\n aria-label=\"Seconds\"\n [value]=\"secondsDisplay()\"\n [disabled]=\"effectiveDisabled()\"\n [readonly]=\"readonly()\"\n (input)=\"onSecondsInput($event)\"\n (blur)=\"onBlur()\"\n />\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--down\"\n aria-label=\"Decrement seconds\"\n [disabled]=\"!interactive()\"\n (click)=\"stepSeconds(-1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\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=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n </div>\n}\n\n@if (is12h()) {\n <div class=\"wr-time-picker__col wr-time-picker__col--ampm\">\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--up\"\n aria-label=\"Toggle AM / PM\"\n [disabled]=\"!interactive()\"\n (click)=\"toggleAmPm()\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\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=\"m18 15-6-6-6 6\" />\n </svg>\n </button>\n <span class=\"wr-time-picker__label\" aria-live=\"polite\">{{ amPmLabel() }}</span>\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--down\"\n aria-label=\"Toggle AM / PM\"\n [disabled]=\"!interactive()\"\n (click)=\"toggleAmPm()\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\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=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n </div>\n}\n", encapsulation: i0.ViewEncapsulation.None });
237
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrTimePanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
238
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: WrTimePanel, isStandalone: true, selector: "wr-time-picker", inputs: { format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", 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 }, autoFocus: { classPropertyName: "autoFocus", publicName: "autoFocus", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: "<div class=\"wr-time-picker__col\">\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--up\"\n aria-label=\"Increment hours\"\n [disabled]=\"!interactive()\"\n (click)=\"stepHours(1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\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=\"m18 15-6-6-6 6\" />\n </svg>\n </button>\n <input\n class=\"wr-time-picker__input\"\n type=\"text\"\n inputmode=\"numeric\"\n aria-label=\"Hours\"\n [value]=\"hoursDisplay()\"\n [disabled]=\"effectiveDisabled()\"\n [readonly]=\"readonly()\"\n (input)=\"onHoursInput($event)\"\n (blur)=\"onBlur()\"\n />\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--down\"\n aria-label=\"Decrement hours\"\n [disabled]=\"!interactive()\"\n (click)=\"stepHours(-1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\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=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n</div>\n\n<span class=\"wr-time-picker__sep\" aria-hidden=\"true\">:</span>\n\n<div class=\"wr-time-picker__col\">\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--up\"\n aria-label=\"Increment minutes\"\n [disabled]=\"!interactive()\"\n (click)=\"stepMinutes(1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\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=\"m18 15-6-6-6 6\" />\n </svg>\n </button>\n <input\n class=\"wr-time-picker__input\"\n type=\"text\"\n inputmode=\"numeric\"\n aria-label=\"Minutes\"\n [value]=\"minutesDisplay()\"\n [disabled]=\"effectiveDisabled()\"\n [readonly]=\"readonly()\"\n (input)=\"onMinutesInput($event)\"\n (blur)=\"onBlur()\"\n />\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--down\"\n aria-label=\"Decrement minutes\"\n [disabled]=\"!interactive()\"\n (click)=\"stepMinutes(-1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\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=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n</div>\n\n@if (showSeconds()) {\n <span class=\"wr-time-picker__sep\" aria-hidden=\"true\">:</span>\n\n <div class=\"wr-time-picker__col\">\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--up\"\n aria-label=\"Increment seconds\"\n [disabled]=\"!interactive()\"\n (click)=\"stepSeconds(1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\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=\"m18 15-6-6-6 6\" />\n </svg>\n </button>\n <input\n class=\"wr-time-picker__input\"\n type=\"text\"\n inputmode=\"numeric\"\n aria-label=\"Seconds\"\n [value]=\"secondsDisplay()\"\n [disabled]=\"effectiveDisabled()\"\n [readonly]=\"readonly()\"\n (input)=\"onSecondsInput($event)\"\n (blur)=\"onBlur()\"\n />\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--down\"\n aria-label=\"Decrement seconds\"\n [disabled]=\"!interactive()\"\n (click)=\"stepSeconds(-1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\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=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n </div>\n}\n\n@if (is12h()) {\n <div class=\"wr-time-picker__col wr-time-picker__col--ampm\">\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--up\"\n aria-label=\"Toggle AM / PM\"\n [disabled]=\"!interactive()\"\n (click)=\"toggleAmPm()\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\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=\"m18 15-6-6-6 6\" />\n </svg>\n </button>\n <span class=\"wr-time-picker__label\" aria-live=\"polite\">{{ amPmLabel() }}</span>\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--down\"\n aria-label=\"Toggle AM / PM\"\n [disabled]=\"!interactive()\"\n (click)=\"toggleAmPm()\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\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=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n </div>\n}\n", encapsulation: i0.ViewEncapsulation.None });
212
239
  }
213
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrTimePanel, decorators: [{
240
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrTimePanel, decorators: [{
214
241
  type: Component,
215
242
  args: [{ selector: 'wr-time-picker', encapsulation: ViewEncapsulation.None, host: { '[class]': 'classes()' }, template: "<div class=\"wr-time-picker__col\">\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--up\"\n aria-label=\"Increment hours\"\n [disabled]=\"!interactive()\"\n (click)=\"stepHours(1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\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=\"m18 15-6-6-6 6\" />\n </svg>\n </button>\n <input\n class=\"wr-time-picker__input\"\n type=\"text\"\n inputmode=\"numeric\"\n aria-label=\"Hours\"\n [value]=\"hoursDisplay()\"\n [disabled]=\"effectiveDisabled()\"\n [readonly]=\"readonly()\"\n (input)=\"onHoursInput($event)\"\n (blur)=\"onBlur()\"\n />\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--down\"\n aria-label=\"Decrement hours\"\n [disabled]=\"!interactive()\"\n (click)=\"stepHours(-1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\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=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n</div>\n\n<span class=\"wr-time-picker__sep\" aria-hidden=\"true\">:</span>\n\n<div class=\"wr-time-picker__col\">\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--up\"\n aria-label=\"Increment minutes\"\n [disabled]=\"!interactive()\"\n (click)=\"stepMinutes(1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\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=\"m18 15-6-6-6 6\" />\n </svg>\n </button>\n <input\n class=\"wr-time-picker__input\"\n type=\"text\"\n inputmode=\"numeric\"\n aria-label=\"Minutes\"\n [value]=\"minutesDisplay()\"\n [disabled]=\"effectiveDisabled()\"\n [readonly]=\"readonly()\"\n (input)=\"onMinutesInput($event)\"\n (blur)=\"onBlur()\"\n />\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--down\"\n aria-label=\"Decrement minutes\"\n [disabled]=\"!interactive()\"\n (click)=\"stepMinutes(-1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\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=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n</div>\n\n@if (showSeconds()) {\n <span class=\"wr-time-picker__sep\" aria-hidden=\"true\">:</span>\n\n <div class=\"wr-time-picker__col\">\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--up\"\n aria-label=\"Increment seconds\"\n [disabled]=\"!interactive()\"\n (click)=\"stepSeconds(1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\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=\"m18 15-6-6-6 6\" />\n </svg>\n </button>\n <input\n class=\"wr-time-picker__input\"\n type=\"text\"\n inputmode=\"numeric\"\n aria-label=\"Seconds\"\n [value]=\"secondsDisplay()\"\n [disabled]=\"effectiveDisabled()\"\n [readonly]=\"readonly()\"\n (input)=\"onSecondsInput($event)\"\n (blur)=\"onBlur()\"\n />\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--down\"\n aria-label=\"Decrement seconds\"\n [disabled]=\"!interactive()\"\n (click)=\"stepSeconds(-1)\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\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=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n </div>\n}\n\n@if (is12h()) {\n <div class=\"wr-time-picker__col wr-time-picker__col--ampm\">\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--up\"\n aria-label=\"Toggle AM / PM\"\n [disabled]=\"!interactive()\"\n (click)=\"toggleAmPm()\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\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=\"m18 15-6-6-6 6\" />\n </svg>\n </button>\n <span class=\"wr-time-picker__label\" aria-live=\"polite\">{{ amPmLabel() }}</span>\n <button\n type=\"button\"\n class=\"wr-time-picker__step wr-time-picker__step--down\"\n aria-label=\"Toggle AM / PM\"\n [disabled]=\"!interactive()\"\n (click)=\"toggleAmPm()\"\n >\n <svg\n class=\"wr-time-picker__chevron\"\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=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n </div>\n}\n" }]
216
- }], ctorParameters: () => [], propDecorators: { format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], touch: [{ type: i0.Output, args: ["touch"] }] } });
243
+ }], ctorParameters: () => [], propDecorators: { format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], autoFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoFocus", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], touch: [{ type: i0.Output, args: ["touch"] }] } });
217
244
 
218
245
  /**
219
246
  * @license
@@ -243,6 +270,13 @@ class WrDateTimePanel {
243
270
  ...(ngDevMode ? [{ debugName: "showSeconds" }] : /* istanbul ignore next */ []));
244
271
  step = input(1, /* @ts-ignore */
245
272
  ...(ngDevMode ? [{ debugName: "step" }] : /* istanbul ignore next */ []));
273
+ /**
274
+ * Forwarded to the calendar only: a datetime panel opened from the keyboard
275
+ * lands on the day grid, never on the hours field. Picking the date first is
276
+ * the order the panel is laid out in, and the time fields are one Tab away.
277
+ */
278
+ autoFocus = input(false, /* @ts-ignore */
279
+ ...(ngDevMode ? [{ debugName: "autoFocus" }] : /* istanbul ignore next */ []));
246
280
  changed = output();
247
281
  adapter = inject(WrDateAdapter);
248
282
  /** Date portion used by the calendar — falls back to today when value is null. */
@@ -265,13 +299,13 @@ class WrDateTimePanel {
265
299
  const combined = this.adapter.setTime(this.adapter.createDate(this.adapter.getYear(base), this.adapter.getMonth(base), this.adapter.getDate(base)), this.adapter.getHours(time), this.adapter.getMinutes(time), this.adapter.getSeconds(time));
266
300
  this.changed.emit(combined);
267
301
  }
268
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrDateTimePanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
269
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.0", type: WrDateTimePanel, isStandalone: true, selector: "wr-date-time-panel", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, dateFilter: { classPropertyName: "dateFilter", publicName: "dateFilter", isSignal: true, isRequired: false, transformFunction: null }, timeFormat: { classPropertyName: "timeFormat", publicName: "timeFormat", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changed: "changed" }, host: { classAttribute: "wr-date-time-panel" }, ngImport: i0, template: "<wr-calendar\n [date]=\"calendarValue()\"\n [min]=\"min()\"\n [max]=\"max()\"\n [dateFilter]=\"dateFilter()\"\n (dateChange)=\"onCalendarSelect($event)\"\n/>\n\n<div class=\"wr-date-time-panel__time\">\n <wr-time-picker\n [ngModel]=\"timeValue()\"\n [format]=\"timeFormat()\"\n [showSeconds]=\"showSeconds()\"\n [step]=\"step()\"\n (ngModelChange)=\"onTimeChange($event)\"\n />\n</div>\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: WrCalendar, selector: "wr-calendar", inputs: ["mode", "date", "range", "min", "max", "dateFilter", "disabled"], outputs: ["dateChange", "rangeChange"] }, { kind: "component", type: WrTimePanel, selector: "wr-time-picker", inputs: ["format", "showSeconds", "step", "disabled", "readonly", "value"], outputs: ["valueChange", "touch"] }], encapsulation: i0.ViewEncapsulation.None });
302
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrDateTimePanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
303
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.1", type: WrDateTimePanel, isStandalone: true, selector: "wr-date-time-panel", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, dateFilter: { classPropertyName: "dateFilter", publicName: "dateFilter", isSignal: true, isRequired: false, transformFunction: null }, timeFormat: { classPropertyName: "timeFormat", publicName: "timeFormat", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, autoFocus: { classPropertyName: "autoFocus", publicName: "autoFocus", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changed: "changed" }, host: { classAttribute: "wr-date-time-panel" }, ngImport: i0, template: "<wr-calendar\n [date]=\"calendarValue()\"\n [min]=\"min()\"\n [max]=\"max()\"\n [dateFilter]=\"dateFilter()\"\n [autoFocus]=\"autoFocus()\"\n (dateChange)=\"onCalendarSelect($event)\"\n/>\n\n<div class=\"wr-date-time-panel__time\">\n <wr-time-picker\n [value]=\"timeValue()\"\n [format]=\"timeFormat()\"\n [showSeconds]=\"showSeconds()\"\n [step]=\"step()\"\n (valueChange)=\"onTimeChange($event)\"\n />\n</div>\n", dependencies: [{ kind: "component", type: WrCalendar, selector: "wr-calendar", inputs: ["mode", "date", "range", "min", "max", "dateFilter", "autoFocus", "disabled"], outputs: ["dateChange", "rangeChange"] }, { kind: "component", type: WrTimePanel, selector: "wr-time-picker", inputs: ["format", "showSeconds", "step", "disabled", "readonly", "autoFocus", "value"], outputs: ["valueChange", "touch"] }], encapsulation: i0.ViewEncapsulation.None });
270
304
  }
271
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrDateTimePanel, decorators: [{
305
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrDateTimePanel, decorators: [{
272
306
  type: Component,
273
- args: [{ selector: 'wr-date-time-panel', encapsulation: ViewEncapsulation.None, host: { class: 'wr-date-time-panel' }, imports: [FormsModule, WrCalendar, WrTimePanel], template: "<wr-calendar\n [date]=\"calendarValue()\"\n [min]=\"min()\"\n [max]=\"max()\"\n [dateFilter]=\"dateFilter()\"\n (dateChange)=\"onCalendarSelect($event)\"\n/>\n\n<div class=\"wr-date-time-panel__time\">\n <wr-time-picker\n [ngModel]=\"timeValue()\"\n [format]=\"timeFormat()\"\n [showSeconds]=\"showSeconds()\"\n [step]=\"step()\"\n (ngModelChange)=\"onTimeChange($event)\"\n />\n</div>\n" }]
274
- }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], dateFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFilter", required: false }] }], timeFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeFormat", required: false }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], changed: [{ type: i0.Output, args: ["changed"] }] } });
307
+ args: [{ selector: 'wr-date-time-panel', encapsulation: ViewEncapsulation.None, host: { class: 'wr-date-time-panel' }, imports: [WrCalendar, WrTimePanel], template: "<wr-calendar\n [date]=\"calendarValue()\"\n [min]=\"min()\"\n [max]=\"max()\"\n [dateFilter]=\"dateFilter()\"\n [autoFocus]=\"autoFocus()\"\n (dateChange)=\"onCalendarSelect($event)\"\n/>\n\n<div class=\"wr-date-time-panel__time\">\n <wr-time-picker\n [value]=\"timeValue()\"\n [format]=\"timeFormat()\"\n [showSeconds]=\"showSeconds()\"\n [step]=\"step()\"\n (valueChange)=\"onTimeChange($event)\"\n />\n</div>\n" }]
308
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], dateFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFilter", required: false }] }], timeFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeFormat", required: false }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], autoFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoFocus", required: false }] }], changed: [{ type: i0.Output, args: ["changed"] }] } });
275
309
 
276
310
  /**
277
311
  * @license
@@ -279,6 +313,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
279
313
  * Use of this source code is governed by an MIT-style license that can be
280
314
  * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
281
315
  */
316
+ let panelUid = 0;
282
317
  /**
283
318
  * Unified date / time / date-time picker. Same `<input>` + popover skeleton
284
319
  * for every mode — the overlay content swaps based on `[mode]`:
@@ -372,6 +407,8 @@ class WrDatePicker {
372
407
  destroyRef = inject(DestroyRef);
373
408
  inputEl = viewChild.required('input', /* @ts-ignore */
374
409
  ...(ngDevMode ? [{ debugName: "inputEl" }] : /* istanbul ignore next */ []));
410
+ triggerEl = viewChild('trigger', /* @ts-ignore */
411
+ ...(ngDevMode ? [{ debugName: "triggerEl" }] : /* istanbul ignore next */ []));
375
412
  /** The picked Date. Bound by `[formField]`, or two-way via `[(value)]`. */
376
413
  value = model(null, /* @ts-ignore */
377
414
  ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
@@ -383,6 +420,14 @@ class WrDatePicker {
383
420
  /** Whether the popover is currently open. */
384
421
  overlayOpen = signal(false, /* @ts-ignore */
385
422
  ...(ngDevMode ? [{ debugName: "overlayOpen" }] : /* istanbul ignore next */ []));
423
+ /**
424
+ * Where focus came from, captured as an explicit argument at open time —
425
+ * never read off `document.activeElement`, which by then may already be the
426
+ * pane. Every close path that took focus INTO the panel hands it back here.
427
+ */
428
+ openedFrom = null;
429
+ /** Whether the panel this open cycle should take focus. */
430
+ autoFocusPanel = false;
386
431
  /** Resolved format — falls back to a mode-appropriate default. */
387
432
  resolvedFormat = computed(() => {
388
433
  const explicit = this.format();
@@ -408,6 +453,9 @@ class WrDatePicker {
408
453
  labelDate = readI18nText('datePicker.open', 'Open calendar');
409
454
  labelTime = readI18nText('datePicker.openTime', 'Open time picker');
410
455
  labelDateTime = readI18nText('datePicker.openDateTime', 'Open date and time picker');
456
+ panelLabelDate = readI18nText('datePicker.panel', 'Choose date');
457
+ panelLabelTime = readI18nText('datePicker.panelTime', 'Choose time');
458
+ panelLabelDateTime = readI18nText('datePicker.panelDateTime', 'Choose date and time');
411
459
  /**
412
460
  * Accessible name of the text field. Falls back to the placeholder, then to
413
461
  * the same catalog string the calendar button uses — the field is a
@@ -434,6 +482,28 @@ class WrDatePicker {
434
482
  return this.labelDate;
435
483
  }, /* @ts-ignore */
436
484
  ...(ngDevMode ? [{ debugName: "triggerLabel" }] : /* istanbul ignore next */ []));
485
+ /**
486
+ * Accessible name of the popup. The trigger advertises
487
+ * `aria-haspopup="dialog"`, so the panel is a `role="dialog"` — and an unnamed
488
+ * dialog announces as a bare "dialog". Defaults to the catalog's
489
+ * `datePicker.panel*` string for the current `mode`.
490
+ */
491
+ panelAriaLabel = input(null, /* @ts-ignore */
492
+ ...(ngDevMode ? [{ debugName: "panelAriaLabel" }] : /* istanbul ignore next */ []));
493
+ /** Popup id — what the trigger's `aria-controls` points at while open. */
494
+ panelId = `wr-date-picker-panel-${++panelUid}`;
495
+ resolvedPanelLabel = computed(() => {
496
+ const explicit = this.panelAriaLabel();
497
+ if (explicit)
498
+ return explicit;
499
+ const m = this.mode();
500
+ if (m === 'time')
501
+ return this.panelLabelTime;
502
+ if (m === 'datetime')
503
+ return this.panelLabelDateTime;
504
+ return this.panelLabelDate;
505
+ }, /* @ts-ignore */
506
+ ...(ngDevMode ? [{ debugName: "resolvedPanelLabel" }] : /* istanbul ignore next */ []));
437
507
  classes = computed(() => {
438
508
  const parts = ['wr-date-picker', `wr-date-picker--${this.mode()}`];
439
509
  if (this.disabled())
@@ -446,6 +516,12 @@ class WrDatePicker {
446
516
  * the typed value in real time (not just on reopen). */
447
517
  dateRef = signal(null, /* @ts-ignore */
448
518
  ...(ngDevMode ? [{ debugName: "dateRef" }] : /* istanbul ignore next */ []));
519
+ timeRef = signal(null, /* @ts-ignore */
520
+ ...(ngDevMode ? [{ debugName: "timeRef" }] : /* istanbul ignore next */ []));
521
+ dateTimeRef = signal(null, /* @ts-ignore */
522
+ ...(ngDevMode ? [{ debugName: "dateTimeRef" }] : /* istanbul ignore next */ []));
523
+ /** The last value an open panel handed us, so the live push never echoes it back. */
524
+ lastFromPanel = null;
449
525
  /** Last value we pushed into the model ourselves — lets the sync effect
450
526
  * skip the echo of our own edits (so a live keystroke's raw text is never
451
527
  * reformatted mid-type). */
@@ -474,6 +550,43 @@ class WrDatePicker {
474
550
  if (ref)
475
551
  ref.setInput('date', this.value());
476
552
  });
553
+ // …and the constraints with it. Pushing these only at attach time meant a
554
+ // `[min]` (or `[max]`, or the filter) that changed while the popover was open
555
+ // kept the stale constraint until the next reopen — `wr-date-range-picker`
556
+ // carries the same effect under a comment saying exactly that.
557
+ effect(() => {
558
+ const ref = this.dateRef();
559
+ if (!ref)
560
+ return;
561
+ ref.setInput('min', this.min());
562
+ ref.setInput('max', this.max());
563
+ ref.setInput('dateFilter', this.dateFilter());
564
+ });
565
+ effect(() => {
566
+ const ref = this.timeRef();
567
+ if (!ref)
568
+ return;
569
+ ref.setInput('format', this.timeFormat());
570
+ ref.setInput('showSeconds', this.showSeconds());
571
+ ref.setInput('step', this.step());
572
+ });
573
+ // The datetime panel had no live sync at all: a date typed into the field
574
+ // while it was open never reached it, so the next stepper click emitted the
575
+ // panel's own stale value and silently undid the typing.
576
+ effect(() => {
577
+ const ref = this.dateTimeRef();
578
+ if (!ref)
579
+ return;
580
+ const value = this.value();
581
+ if (value !== this.lastFromPanel)
582
+ ref.setInput('value', value);
583
+ ref.setInput('min', this.min());
584
+ ref.setInput('max', this.max());
585
+ ref.setInput('dateFilter', this.dateFilter());
586
+ ref.setInput('timeFormat', this.timeFormat());
587
+ ref.setInput('showSeconds', this.showSeconds());
588
+ ref.setInput('step', this.step());
589
+ });
477
590
  }
478
591
  // Template handlers
479
592
  onInput(event) {
@@ -503,22 +616,69 @@ class WrDatePicker {
503
616
  openOnInput() {
504
617
  if (this.disabled() || this.overlayRef)
505
618
  return;
506
- this.openOverlay();
619
+ // Deliberately WITHOUT focus: this click placed a caret in the text field,
620
+ // and yanking focus into the grid would throw away what the user just did.
621
+ // `Alt+ArrowDown` / `ArrowDown` are the keyboard way in — see onFieldKey.
622
+ this.openOverlay(this.inputEl().nativeElement, false);
507
623
  }
508
624
  toggleOverlay() {
509
625
  if (this.disabled())
510
626
  return;
511
627
  if (this.overlayRef) {
628
+ // Focus is already on the trigger — nothing to restore.
512
629
  this.closeOverlay();
513
630
  }
514
631
  else {
515
- this.openOverlay();
632
+ this.openOverlay(this.triggerEl()?.nativeElement ?? null, true);
633
+ }
634
+ }
635
+ /**
636
+ * The keyboard route into the panel, per the APG date-picker pattern.
637
+ *
638
+ * `Alt+ArrowDown` opens and takes focus; a bare arrow moves focus in when the
639
+ * panel is ALREADY open, which is how someone who opened it by clicking the
640
+ * field gets to the grid. Every other key — characters, Backspace, the
641
+ * horizontal arrows, Home / End — is left to the field untouched, so typing a
642
+ * date keeps working exactly as before.
643
+ */
644
+ onFieldKey(event) {
645
+ if (this.disabled())
646
+ return;
647
+ const vertical = event.key === 'ArrowDown' || event.key === 'ArrowUp';
648
+ if (!vertical)
649
+ return;
650
+ if (event.altKey && event.key === 'ArrowDown' && !this.overlayRef) {
651
+ event.preventDefault();
652
+ this.openOverlay(this.inputEl().nativeElement, true);
653
+ return;
654
+ }
655
+ if (this.overlayRef) {
656
+ event.preventDefault();
657
+ this.focusPanel();
516
658
  }
517
659
  }
660
+ /**
661
+ * Move focus into an already-mounted panel. A plain query is right HERE and
662
+ * wrong at mount time: the panel has settled, so there is no deferral to get
663
+ * wrong — and it keeps `autoFocus` as the single piece of panel API.
664
+ */
665
+ focusPanel() {
666
+ const pane = this.overlayRef?.overlayElement;
667
+ const target = pane?.querySelector('.wr-calendar__day--focused:not([disabled])') ??
668
+ pane?.querySelector('.wr-time-picker__input');
669
+ target?.focus();
670
+ }
671
+ /** Hand focus back to whatever opened the panel, if it is still on the page. */
672
+ restoreFocus() {
673
+ const target = this.openedFrom?.isConnected ? this.openedFrom : this.inputEl().nativeElement;
674
+ target?.focus();
675
+ }
518
676
  // Overlay
519
- openOverlay() {
677
+ openOverlay(openedFrom = null, autoFocus = false) {
520
678
  if (this.overlayRef)
521
679
  return;
680
+ this.openedFrom = openedFrom;
681
+ this.autoFocusPanel = autoFocus;
522
682
  const positionStrategy = this.overlay
523
683
  .position()
524
684
  .flexibleConnectedTo(this.host)
@@ -534,6 +694,15 @@ class WrDatePicker {
534
694
  scrollStrategy: this.scrollStrategies.reposition(),
535
695
  panelClass: 'wr-date-picker-overlay',
536
696
  });
697
+ // The trigger promises `aria-haspopup="dialog"`; the pane is the element it
698
+ // points at, so the role, the name and the id all belong here. Non-modal on
699
+ // purpose — focus is not trapped, and the panel closes on outside click or
700
+ // Escape.
701
+ const pane = this.overlayRef.overlayElement;
702
+ pane.id = this.panelId;
703
+ pane.setAttribute('role', 'dialog');
704
+ pane.setAttribute('aria-modal', 'false');
705
+ pane.setAttribute('aria-label', this.resolvedPanelLabel());
537
706
  this.overlayOpen.set(true);
538
707
  // Dispatch by mode — pick the panel + wire its emissions.
539
708
  const m = this.mode();
@@ -571,6 +740,7 @@ class WrDatePicker {
571
740
  ref.setInput('min', this.min());
572
741
  ref.setInput('max', this.max());
573
742
  ref.setInput('dateFilter', this.dateFilter());
743
+ ref.setInput('autoFocus', this.autoFocusPanel);
574
744
  ref.instance.date.subscribe(next => {
575
745
  if (!next)
576
746
  return;
@@ -585,10 +755,13 @@ class WrDatePicker {
585
755
  ref.setInput('format', this.timeFormat());
586
756
  ref.setInput('showSeconds', this.showSeconds());
587
757
  ref.setInput('step', this.step());
758
+ ref.setInput('autoFocus', this.autoFocusPanel);
588
759
  ref.setInput('value', this.value() ?? this.adapter.today());
760
+ this.timeRef.set(ref);
589
761
  ref.instance.value.subscribe((next) => {
590
762
  if (!next)
591
763
  return;
764
+ this.lastFromPanel = next;
592
765
  this.commit(next);
593
766
  });
594
767
  }
@@ -603,7 +776,10 @@ class WrDatePicker {
603
776
  ref.setInput('timeFormat', this.timeFormat());
604
777
  ref.setInput('showSeconds', this.showSeconds());
605
778
  ref.setInput('step', this.step());
779
+ ref.setInput('autoFocus', this.autoFocusPanel);
780
+ this.dateTimeRef.set(ref);
606
781
  ref.instance.changed.subscribe(next => {
782
+ this.lastFromPanel = next;
607
783
  this.commit(next);
608
784
  ref.setInput('value', next);
609
785
  });
@@ -618,8 +794,19 @@ class WrDatePicker {
618
794
  this.lastValue = next;
619
795
  this.value.set(next);
620
796
  }
797
+ /**
798
+ * Focus goes back to the opener only when it was still INSIDE the panel —
799
+ * dropped there, it would land on `<body>` and the next Tab would restart
800
+ * from the top of the page. When focus had already moved elsewhere (a click
801
+ * on another control, which is itself what closed us) it is left alone:
802
+ * stealing it back would fight the user for the caret.
803
+ */
621
804
  closeOverlay() {
805
+ const pane = this.overlayRef?.overlayElement;
806
+ const inside = !!pane && pane.contains(document.activeElement);
622
807
  this.dispose();
808
+ if (inside)
809
+ this.restoreFocus();
623
810
  }
624
811
  dispose() {
625
812
  if (this.overlayRef) {
@@ -627,7 +814,10 @@ class WrDatePicker {
627
814
  this.overlayRef = null;
628
815
  }
629
816
  this.dateRef.set(null);
817
+ this.timeRef.set(null);
818
+ this.dateTimeRef.set(null);
630
819
  this.overlayOpen.set(false);
820
+ this.autoFocusPanel = false;
631
821
  }
632
822
  // Helpers
633
823
  isOutOfBounds(date) {
@@ -639,6 +829,12 @@ class WrDatePicker {
639
829
  const max = this.max();
640
830
  if (max && this.adapter.compareDate(date, max) > 0)
641
831
  return true;
832
+ // Covers `dateFilter` as well as the bounds — the calendar disables filtered
833
+ // days, so accepting them from the keyboard made the two entry paths
834
+ // disagree. Same check, same reason, as `wr-date-range-picker`.
835
+ const filter = this.dateFilter();
836
+ if (filter && !filter(date))
837
+ return true;
642
838
  return false;
643
839
  }
644
840
  sameDate(a, b) {
@@ -648,13 +844,13 @@ class WrDatePicker {
648
844
  return false;
649
845
  return a.getTime() === b.getTime();
650
846
  }
651
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrDatePicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
652
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: WrDatePicker, isStandalone: true, selector: "wr-date-picker", inputs: { mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, dateFilter: { classPropertyName: "dateFilter", publicName: "dateFilter", isSignal: true, isRequired: false, transformFunction: null }, timeFormat: { classPropertyName: "timeFormat", publicName: "timeFormat", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", 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 }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { properties: { "class": "classes()" } }, viewQueries: [{ propertyName: "inputEl", first: true, predicate: ["input"], descendants: true, isSignal: true }], ngImport: i0, template: "<wr-input-group>\n <!--\n A plain textbox, per the APG date-picker-dialog pattern: `aria-haspopup` and\n `aria-expanded` are not permitted on `textbox` and belong to the trigger\n button below, which is the thing that opens the dialog.\n -->\n <input\n #input\n wrInput\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n [value]=\"text()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (click)=\"openOnInput()\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n />\n <button\n type=\"button\"\n wrInputSuffix\n class=\"wr-date-picker__trigger\"\n [attr.aria-label]=\"triggerLabel()\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-expanded]=\"overlayOpen()\"\n [disabled]=\"disabled()\"\n (click)=\"toggleOverlay()\"\n >\n @if (isTime()) {\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"5.75\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"7\" y1=\"7\" x2=\"7\" y2=\"3.75\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n <line x1=\"7\" y1=\"7\" x2=\"9.5\" y2=\"7\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n </svg>\n } @else {\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" aria-hidden=\"true\">\n <rect x=\"1.5\" y=\"2.5\" width=\"11\" height=\"10\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"1.5\" y1=\"5.5\" x2=\"12.5\" y2=\"5.5\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"4\" y1=\"1\" x2=\"4\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n <line x1=\"10\" y1=\"1\" x2=\"10\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n @if (isDateTime()) {\n <circle cx=\"7\" cy=\"9\" r=\"1.5\" fill=\"currentColor\" />\n }\n </svg>\n }\n </button>\n</wr-input-group>\n", dependencies: [{ kind: "directive", type: WrInput, selector: "input[wrInput], textarea[wrInput]", inputs: ["wrSize", "rounded"] }, { kind: "component", type: WrInputGroup, selector: "wr-input-group", inputs: ["rounded"] }, { kind: "directive", type: WrInputSuffix, selector: "[wrInputSuffix]" }], encapsulation: i0.ViewEncapsulation.None });
847
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrDatePicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
848
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: WrDatePicker, isStandalone: true, selector: "wr-date-picker", inputs: { mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, dateFilter: { classPropertyName: "dateFilter", publicName: "dateFilter", isSignal: true, isRequired: false, transformFunction: null }, timeFormat: { classPropertyName: "timeFormat", publicName: "timeFormat", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", 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 }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, panelAriaLabel: { classPropertyName: "panelAriaLabel", publicName: "panelAriaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { properties: { "class": "classes()" } }, viewQueries: [{ propertyName: "inputEl", first: true, predicate: ["input"], descendants: true, isSignal: true }, { propertyName: "triggerEl", first: true, predicate: ["trigger"], descendants: true, isSignal: true }], ngImport: i0, template: "<wr-input-group>\n <!--\n A plain textbox, per the APG date-picker-dialog pattern: `aria-haspopup` and\n `aria-expanded` are not permitted on `textbox` and belong to the trigger\n button below, which is the thing that opens the dialog.\n -->\n <input\n #input\n wrInput\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n [value]=\"text()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (click)=\"openOnInput()\"\n (keydown)=\"onFieldKey($event)\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n />\n <button\n #trigger\n type=\"button\"\n wrInputSuffix\n class=\"wr-date-picker__trigger\"\n [attr.aria-label]=\"triggerLabel()\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-expanded]=\"overlayOpen()\"\n [attr.aria-controls]=\"overlayOpen() ? panelId : null\"\n [disabled]=\"disabled()\"\n (click)=\"toggleOverlay()\"\n >\n @if (isTime()) {\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"5.75\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"7\" y1=\"7\" x2=\"7\" y2=\"3.75\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n <line x1=\"7\" y1=\"7\" x2=\"9.5\" y2=\"7\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n </svg>\n } @else {\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" aria-hidden=\"true\">\n <rect x=\"1.5\" y=\"2.5\" width=\"11\" height=\"10\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"1.5\" y1=\"5.5\" x2=\"12.5\" y2=\"5.5\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"4\" y1=\"1\" x2=\"4\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n <line x1=\"10\" y1=\"1\" x2=\"10\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n @if (isDateTime()) {\n <circle cx=\"7\" cy=\"9\" r=\"1.5\" fill=\"currentColor\" />\n }\n </svg>\n }\n </button>\n</wr-input-group>\n", dependencies: [{ kind: "directive", type: WrInput, selector: "input[wrInput], textarea[wrInput]", inputs: ["wrSize", "rounded"] }, { kind: "component", type: WrInputGroup, selector: "wr-input-group", inputs: ["rounded"] }, { kind: "directive", type: WrInputSuffix, selector: "[wrInputSuffix]" }], encapsulation: i0.ViewEncapsulation.None });
653
849
  }
654
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrDatePicker, decorators: [{
850
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrDatePicker, decorators: [{
655
851
  type: Component,
656
- args: [{ selector: 'wr-date-picker', encapsulation: ViewEncapsulation.None, host: { '[class]': 'classes()' }, imports: [WrInput, WrInputGroup, WrInputSuffix], template: "<wr-input-group>\n <!--\n A plain textbox, per the APG date-picker-dialog pattern: `aria-haspopup` and\n `aria-expanded` are not permitted on `textbox` and belong to the trigger\n button below, which is the thing that opens the dialog.\n -->\n <input\n #input\n wrInput\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n [value]=\"text()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (click)=\"openOnInput()\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n />\n <button\n type=\"button\"\n wrInputSuffix\n class=\"wr-date-picker__trigger\"\n [attr.aria-label]=\"triggerLabel()\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-expanded]=\"overlayOpen()\"\n [disabled]=\"disabled()\"\n (click)=\"toggleOverlay()\"\n >\n @if (isTime()) {\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"5.75\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"7\" y1=\"7\" x2=\"7\" y2=\"3.75\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n <line x1=\"7\" y1=\"7\" x2=\"9.5\" y2=\"7\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n </svg>\n } @else {\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" aria-hidden=\"true\">\n <rect x=\"1.5\" y=\"2.5\" width=\"11\" height=\"10\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"1.5\" y1=\"5.5\" x2=\"12.5\" y2=\"5.5\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"4\" y1=\"1\" x2=\"4\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n <line x1=\"10\" y1=\"1\" x2=\"10\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n @if (isDateTime()) {\n <circle cx=\"7\" cy=\"9\" r=\"1.5\" fill=\"currentColor\" />\n }\n </svg>\n }\n </button>\n</wr-input-group>\n" }]
657
- }], ctorParameters: () => [], propDecorators: { mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], dateFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFilter", required: false }] }], timeFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeFormat", required: false }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], inputEl: [{ type: i0.ViewChild, args: ['input', { isSignal: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], touch: [{ type: i0.Output, args: ["touch"] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
852
+ args: [{ selector: 'wr-date-picker', encapsulation: ViewEncapsulation.None, host: { '[class]': 'classes()' }, imports: [WrInput, WrInputGroup, WrInputSuffix], template: "<wr-input-group>\n <!--\n A plain textbox, per the APG date-picker-dialog pattern: `aria-haspopup` and\n `aria-expanded` are not permitted on `textbox` and belong to the trigger\n button below, which is the thing that opens the dialog.\n -->\n <input\n #input\n wrInput\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n [value]=\"text()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (click)=\"openOnInput()\"\n (keydown)=\"onFieldKey($event)\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n />\n <button\n #trigger\n type=\"button\"\n wrInputSuffix\n class=\"wr-date-picker__trigger\"\n [attr.aria-label]=\"triggerLabel()\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-expanded]=\"overlayOpen()\"\n [attr.aria-controls]=\"overlayOpen() ? panelId : null\"\n [disabled]=\"disabled()\"\n (click)=\"toggleOverlay()\"\n >\n @if (isTime()) {\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"5.75\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"7\" y1=\"7\" x2=\"7\" y2=\"3.75\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n <line x1=\"7\" y1=\"7\" x2=\"9.5\" y2=\"7\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n </svg>\n } @else {\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" aria-hidden=\"true\">\n <rect x=\"1.5\" y=\"2.5\" width=\"11\" height=\"10\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"1.5\" y1=\"5.5\" x2=\"12.5\" y2=\"5.5\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"4\" y1=\"1\" x2=\"4\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n <line x1=\"10\" y1=\"1\" x2=\"10\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n @if (isDateTime()) {\n <circle cx=\"7\" cy=\"9\" r=\"1.5\" fill=\"currentColor\" />\n }\n </svg>\n }\n </button>\n</wr-input-group>\n" }]
853
+ }], ctorParameters: () => [], propDecorators: { mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], dateFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFilter", required: false }] }], timeFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeFormat", required: false }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], inputEl: [{ type: i0.ViewChild, args: ['input', { isSignal: true }] }], triggerEl: [{ type: i0.ViewChild, args: ['trigger', { isSignal: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], touch: [{ type: i0.Output, args: ["touch"] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], panelAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelAriaLabel", required: false }] }] } });
658
854
 
659
855
  /**
660
856
  * @license
@@ -671,6 +867,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
671
867
  * preview); this panel only re-attaches the times so a datetime range keeps the
672
868
  * hours the user set while the dates move around.
673
869
  *
870
+ * The steppers bind `WrTimePanel`'s own `value` model, NOT `[ngModel]`. The
871
+ * classic-forms bridge defers its first write, and under zoneless change
872
+ * detection that write lost the race with the panel's own echo guard: a range
873
+ * bound to 16:00–17:00 opened showing 00:00 on both ends, and the first click
874
+ * on a stepper committed midnight-plus-one over the real value.
875
+ *
674
876
  * @internal
675
877
  */
676
878
  class WrDateRangePanel {
@@ -690,7 +892,24 @@ class WrDateRangePanel {
690
892
  ...(ngDevMode ? [{ debugName: "showSeconds" }] : /* istanbul ignore next */ []));
691
893
  step = input(1, /* @ts-ignore */
692
894
  ...(ngDevMode ? [{ debugName: "step" }] : /* istanbul ignore next */ []));
895
+ /**
896
+ * Forwarded to the calendar only: a range panel opened from the keyboard
897
+ * lands on the day grid, never on a time field. Dates come first here — the
898
+ * steppers are for the range you have already drawn.
899
+ */
900
+ autoFocus = input(false, /* @ts-ignore */
901
+ ...(ngDevMode ? [{ debugName: "autoFocus" }] : /* istanbul ignore next */ []));
902
+ /** A range change from the CALENDAR — the picker is free to sort it. */
693
903
  changed = output();
904
+ /**
905
+ * A range change from one of the TIME steppers, which must NOT be sorted while
906
+ * it is happening. The steppers are bound to positions, so sorting mid-edit
907
+ * moves the user's change to the other end: raising a same-day start past the
908
+ * end left the start stuck and pushed the END up instead, once per click, on
909
+ * the button the user was not pressing. Ordering is settled when the popup
910
+ * closes — the same rule the text inputs already follow for typing.
911
+ */
912
+ timeChanged = output();
694
913
  adapter = inject(WrDateAdapter);
695
914
  startTimeLabel = readI18nText('datePicker.startTime', 'Start time');
696
915
  endTimeLabel = readI18nText('datePicker.endTime', 'End time');
@@ -745,7 +964,7 @@ class WrDateRangePanel {
745
964
  this.pendingStartTime.set(time);
746
965
  return;
747
966
  }
748
- this.changed.emit([this.withTimeOf(start, time), end]);
967
+ this.timeChanged.emit([this.withTimeOf(start, time), end]);
749
968
  }
750
969
  onEndTimeChange(time) {
751
970
  if (!time)
@@ -755,7 +974,7 @@ class WrDateRangePanel {
755
974
  this.pendingEndTime.set(time);
756
975
  return;
757
976
  }
758
- this.changed.emit([start, this.withTimeOf(end, time)]);
977
+ this.timeChanged.emit([start, this.withTimeOf(end, time)]);
759
978
  }
760
979
  /** `date`'s calendar day carrying `time`'s clock. Null date stays null. */
761
980
  withTimeOf(date, time) {
@@ -765,13 +984,13 @@ class WrDateRangePanel {
765
984
  return date;
766
985
  return this.adapter.setTime(this.adapter.createDate(this.adapter.getYear(date), this.adapter.getMonth(date), this.adapter.getDate(date)), this.adapter.getHours(time), this.adapter.getMinutes(time), this.adapter.getSeconds(time));
767
986
  }
768
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrDateRangePanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
769
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: WrDateRangePanel, isStandalone: true, selector: "wr-date-range-panel", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, dateFilter: { classPropertyName: "dateFilter", publicName: "dateFilter", isSignal: true, isRequired: false, transformFunction: null }, withTime: { classPropertyName: "withTime", publicName: "withTime", isSignal: true, isRequired: false, transformFunction: null }, timeFormat: { classPropertyName: "timeFormat", publicName: "timeFormat", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changed: "changed" }, host: { classAttribute: "wr-date-range-panel" }, ngImport: i0, template: "<wr-calendar\n mode=\"range\"\n [range]=\"calendarRange()\"\n [min]=\"min()\"\n [max]=\"max()\"\n [dateFilter]=\"dateFilter()\"\n (rangeChange)=\"onRangeChange($event)\"\n/>\n\n@if (withTime()) {\n <div class=\"wr-date-range-panel__times\">\n <!-- A time picker is several inputs, not one control, so each end is a\n labelled group rather than a <label>. -->\n <div class=\"wr-date-range-panel__time\" role=\"group\" [attr.aria-label]=\"startTimeLabel\">\n <span class=\"wr-date-range-panel__time-label\" aria-hidden=\"true\">{{ startTimeLabel }}</span>\n <wr-time-picker\n [ngModel]=\"startTime()\"\n [format]=\"timeFormat()\"\n [showSeconds]=\"showSeconds()\"\n [step]=\"step()\"\n (ngModelChange)=\"onStartTimeChange($event)\"\n />\n </div>\n <div class=\"wr-date-range-panel__time\" role=\"group\" [attr.aria-label]=\"endTimeLabel\">\n <span class=\"wr-date-range-panel__time-label\" aria-hidden=\"true\">{{ endTimeLabel }}</span>\n <wr-time-picker\n [ngModel]=\"endTime()\"\n [format]=\"timeFormat()\"\n [showSeconds]=\"showSeconds()\"\n [step]=\"step()\"\n (ngModelChange)=\"onEndTimeChange($event)\"\n />\n </div>\n </div>\n}\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: WrCalendar, selector: "wr-calendar", inputs: ["mode", "date", "range", "min", "max", "dateFilter", "disabled"], outputs: ["dateChange", "rangeChange"] }, { kind: "component", type: WrTimePanel, selector: "wr-time-picker", inputs: ["format", "showSeconds", "step", "disabled", "readonly", "value"], outputs: ["valueChange", "touch"] }], encapsulation: i0.ViewEncapsulation.None });
987
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrDateRangePanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
988
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: WrDateRangePanel, isStandalone: true, selector: "wr-date-range-panel", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, dateFilter: { classPropertyName: "dateFilter", publicName: "dateFilter", isSignal: true, isRequired: false, transformFunction: null }, withTime: { classPropertyName: "withTime", publicName: "withTime", isSignal: true, isRequired: false, transformFunction: null }, timeFormat: { classPropertyName: "timeFormat", publicName: "timeFormat", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, autoFocus: { classPropertyName: "autoFocus", publicName: "autoFocus", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changed: "changed", timeChanged: "timeChanged" }, host: { classAttribute: "wr-date-range-panel" }, ngImport: i0, template: "<wr-calendar\n mode=\"range\"\n [range]=\"calendarRange()\"\n [min]=\"min()\"\n [max]=\"max()\"\n [dateFilter]=\"dateFilter()\"\n [autoFocus]=\"autoFocus()\"\n (rangeChange)=\"onRangeChange($event)\"\n/>\n\n@if (withTime()) {\n <div class=\"wr-date-range-panel__times\">\n <!-- A time picker is several inputs, not one control, so each end is a\n labelled group rather than a <label>. -->\n <div class=\"wr-date-range-panel__time\" role=\"group\" [attr.aria-label]=\"startTimeLabel\">\n <span class=\"wr-date-range-panel__time-label\" aria-hidden=\"true\">{{ startTimeLabel }}</span>\n <wr-time-picker\n [value]=\"startTime()\"\n [format]=\"timeFormat()\"\n [showSeconds]=\"showSeconds()\"\n [step]=\"step()\"\n (valueChange)=\"onStartTimeChange($event)\"\n />\n </div>\n <div class=\"wr-date-range-panel__time\" role=\"group\" [attr.aria-label]=\"endTimeLabel\">\n <span class=\"wr-date-range-panel__time-label\" aria-hidden=\"true\">{{ endTimeLabel }}</span>\n <wr-time-picker\n [value]=\"endTime()\"\n [format]=\"timeFormat()\"\n [showSeconds]=\"showSeconds()\"\n [step]=\"step()\"\n (valueChange)=\"onEndTimeChange($event)\"\n />\n </div>\n </div>\n}\n", dependencies: [{ kind: "component", type: WrCalendar, selector: "wr-calendar", inputs: ["mode", "date", "range", "min", "max", "dateFilter", "autoFocus", "disabled"], outputs: ["dateChange", "rangeChange"] }, { kind: "component", type: WrTimePanel, selector: "wr-time-picker", inputs: ["format", "showSeconds", "step", "disabled", "readonly", "autoFocus", "value"], outputs: ["valueChange", "touch"] }], encapsulation: i0.ViewEncapsulation.None });
770
989
  }
771
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrDateRangePanel, decorators: [{
990
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrDateRangePanel, decorators: [{
772
991
  type: Component,
773
- args: [{ selector: 'wr-date-range-panel', encapsulation: ViewEncapsulation.None, host: { class: 'wr-date-range-panel' }, imports: [FormsModule, WrCalendar, WrTimePanel], template: "<wr-calendar\n mode=\"range\"\n [range]=\"calendarRange()\"\n [min]=\"min()\"\n [max]=\"max()\"\n [dateFilter]=\"dateFilter()\"\n (rangeChange)=\"onRangeChange($event)\"\n/>\n\n@if (withTime()) {\n <div class=\"wr-date-range-panel__times\">\n <!-- A time picker is several inputs, not one control, so each end is a\n labelled group rather than a <label>. -->\n <div class=\"wr-date-range-panel__time\" role=\"group\" [attr.aria-label]=\"startTimeLabel\">\n <span class=\"wr-date-range-panel__time-label\" aria-hidden=\"true\">{{ startTimeLabel }}</span>\n <wr-time-picker\n [ngModel]=\"startTime()\"\n [format]=\"timeFormat()\"\n [showSeconds]=\"showSeconds()\"\n [step]=\"step()\"\n (ngModelChange)=\"onStartTimeChange($event)\"\n />\n </div>\n <div class=\"wr-date-range-panel__time\" role=\"group\" [attr.aria-label]=\"endTimeLabel\">\n <span class=\"wr-date-range-panel__time-label\" aria-hidden=\"true\">{{ endTimeLabel }}</span>\n <wr-time-picker\n [ngModel]=\"endTime()\"\n [format]=\"timeFormat()\"\n [showSeconds]=\"showSeconds()\"\n [step]=\"step()\"\n (ngModelChange)=\"onEndTimeChange($event)\"\n />\n </div>\n </div>\n}\n" }]
774
- }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], dateFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFilter", required: false }] }], withTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "withTime", required: false }] }], timeFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeFormat", required: false }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], changed: [{ type: i0.Output, args: ["changed"] }] } });
992
+ args: [{ selector: 'wr-date-range-panel', encapsulation: ViewEncapsulation.None, host: { class: 'wr-date-range-panel' }, imports: [WrCalendar, WrTimePanel], template: "<wr-calendar\n mode=\"range\"\n [range]=\"calendarRange()\"\n [min]=\"min()\"\n [max]=\"max()\"\n [dateFilter]=\"dateFilter()\"\n [autoFocus]=\"autoFocus()\"\n (rangeChange)=\"onRangeChange($event)\"\n/>\n\n@if (withTime()) {\n <div class=\"wr-date-range-panel__times\">\n <!-- A time picker is several inputs, not one control, so each end is a\n labelled group rather than a <label>. -->\n <div class=\"wr-date-range-panel__time\" role=\"group\" [attr.aria-label]=\"startTimeLabel\">\n <span class=\"wr-date-range-panel__time-label\" aria-hidden=\"true\">{{ startTimeLabel }}</span>\n <wr-time-picker\n [value]=\"startTime()\"\n [format]=\"timeFormat()\"\n [showSeconds]=\"showSeconds()\"\n [step]=\"step()\"\n (valueChange)=\"onStartTimeChange($event)\"\n />\n </div>\n <div class=\"wr-date-range-panel__time\" role=\"group\" [attr.aria-label]=\"endTimeLabel\">\n <span class=\"wr-date-range-panel__time-label\" aria-hidden=\"true\">{{ endTimeLabel }}</span>\n <wr-time-picker\n [value]=\"endTime()\"\n [format]=\"timeFormat()\"\n [showSeconds]=\"showSeconds()\"\n [step]=\"step()\"\n (valueChange)=\"onEndTimeChange($event)\"\n />\n </div>\n </div>\n}\n" }]
993
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], dateFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFilter", required: false }] }], withTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "withTime", required: false }] }], timeFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeFormat", required: false }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], autoFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoFocus", required: false }] }], changed: [{ type: i0.Output, args: ["changed"] }], timeChanged: [{ type: i0.Output, args: ["timeChanged"] }] } });
775
994
 
776
995
  /**
777
996
  * @license
@@ -779,6 +998,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
779
998
  * Use of this source code is governed by an MIT-style license that can be
780
999
  * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
781
1000
  */
1001
+ /** Per-instance popup ids, so `aria-controls` can point at one panel. */
1002
+ let rangePanelUid = 0;
782
1003
  /**
783
1004
  * Date-range picker — two text inputs sharing one range calendar.
784
1005
  *
@@ -861,7 +1082,17 @@ class WrDateRangePicker {
861
1082
  * @default false
862
1083
  */
863
1084
  disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
864
- /** Read-only — inputs not typeable, but the trigger icon still opens the overlay. @default false */
1085
+ /**
1086
+ * Read-only — neither the inputs nor the calendar can change the value.
1087
+ *
1088
+ * Deliberately stricter than `wr-date-picker`, which still opens its popup
1089
+ * while read-only: with two fields feeding one calendar there is no reading
1090
+ * of "untypeable" that leaves the grid free to rewrite both ends. The doc
1091
+ * used to promise the trigger still opened; the code has always refused, and
1092
+ * refusing is the behaviour worth keeping.
1093
+ *
1094
+ * @default false
1095
+ */
865
1096
  readonly = input(false, { ...(ngDevMode ? { debugName: "readonly" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
866
1097
  adapter = inject(WrDateAdapter);
867
1098
  overlay = inject(WR_OVERLAY);
@@ -871,6 +1102,10 @@ class WrDateRangePicker {
871
1102
  destroyRef = inject(DestroyRef);
872
1103
  startEl = viewChild.required('startInput', /* @ts-ignore */
873
1104
  ...(ngDevMode ? [{ debugName: "startEl" }] : /* istanbul ignore next */ []));
1105
+ endEl = viewChild.required('endInput', /* @ts-ignore */
1106
+ ...(ngDevMode ? [{ debugName: "endEl" }] : /* istanbul ignore next */ []));
1107
+ triggerEl = viewChild('trigger', /* @ts-ignore */
1108
+ ...(ngDevMode ? [{ debugName: "triggerEl" }] : /* istanbul ignore next */ []));
874
1109
  /** The picked range. Bound by `[formField]`, or two-way via `[(value)]`. */
875
1110
  value = model(null, /* @ts-ignore */
876
1111
  ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
@@ -884,6 +1119,16 @@ class WrDateRangePicker {
884
1119
  /** Whether the popover is currently open. */
885
1120
  overlayOpen = signal(false, /* @ts-ignore */
886
1121
  ...(ngDevMode ? [{ debugName: "overlayOpen" }] : /* istanbul ignore next */ []));
1122
+ /**
1123
+ * Which element opened the popup — captured as an argument, never read off
1124
+ * `document.activeElement`, which by then may already be the pane. With TWO
1125
+ * text inputs this is the whole point: "restore focus to the field" is
1126
+ * ambiguous here, and the old code resolved it by always picking the START
1127
+ * input, so closing from the end input threw the caret across the control.
1128
+ */
1129
+ openedFrom = null;
1130
+ /** Whether the panel this open cycle should take focus. */
1131
+ autoFocusPanel = false;
887
1132
  /** Resolved format — falls back to a mode-appropriate default. */
888
1133
  resolvedFormat = computed(() => this.format() ? String(this.format()) : this.mode() === 'datetime' ? 'shortDateTime' : 'shortDate', /* @ts-ignore */
889
1134
  ...(ngDevMode ? [{ debugName: "resolvedFormat" }] : /* istanbul ignore next */ []));
@@ -892,6 +1137,25 @@ class WrDateRangePicker {
892
1137
  triggerLabel = readI18nText('datePicker.openRange', 'Open range calendar');
893
1138
  startLabel = readI18nText('datePicker.rangeStart', 'Range start');
894
1139
  endLabel = readI18nText('datePicker.rangeEnd', 'Range end');
1140
+ panelLabelRange = readI18nText('datePicker.panelRange', 'Choose date range');
1141
+ panelLabelRangeDateTime = readI18nText('datePicker.panelRangeDateTime', 'Choose date and time range');
1142
+ /**
1143
+ * Accessible name of the popup. The trigger advertises
1144
+ * `aria-haspopup="dialog"`, so the pane is a `role="dialog"` — and an unnamed
1145
+ * dialog announces as a bare "dialog". Defaults to the catalog's
1146
+ * `datePicker.panelRange*` string for the current `mode`.
1147
+ */
1148
+ panelAriaLabel = input(null, /* @ts-ignore */
1149
+ ...(ngDevMode ? [{ debugName: "panelAriaLabel" }] : /* istanbul ignore next */ []));
1150
+ /** Popup id — what the trigger's `aria-controls` points at while open. */
1151
+ panelId = `wr-date-range-picker-panel-${++rangePanelUid}`;
1152
+ resolvedPanelLabel = computed(() => {
1153
+ const explicit = this.panelAriaLabel();
1154
+ if (explicit)
1155
+ return explicit;
1156
+ return this.isDateTime() ? this.panelLabelRangeDateTime : this.panelLabelRange;
1157
+ }, /* @ts-ignore */
1158
+ ...(ngDevMode ? [{ debugName: "resolvedPanelLabel" }] : /* istanbul ignore next */ []));
895
1159
  classes = computed(() => {
896
1160
  const parts = ['wr-date-range-picker', `wr-date-range-picker--${this.mode()}`];
897
1161
  if (this.disabled())
@@ -954,30 +1218,83 @@ class WrDateRangePicker {
954
1218
  // control as touched once focus actually leaves it, or tabbing from start to
955
1219
  // end would mark a bound field touched mid-entry.
956
1220
  const next = event.relatedTarget;
957
- if (!next || !this.host.nativeElement.contains(next))
1221
+ const leaving = !next || !this.host.nativeElement.contains(next);
1222
+ if (leaving)
958
1223
  this.touch.emit();
959
1224
  // Typing leaves the ends in whatever order they were entered; settle it
960
- // here, once the user has stopped.
961
- const [start, end] = this.commitRange(this.current(), { normalise: true });
1225
+ // here, once the user has stopped — and moving from one end to the other is
1226
+ // NOT stopping. Sorting on that hop took the start date the user had just
1227
+ // typed and moved it into the field they were tabbing into, leaving the old
1228
+ // end date under their cursor. Same rule the time steppers follow.
1229
+ const [start, end] = this.commitRange(this.current(), { normalise: leaving });
962
1230
  // Reformat to canonical on blur (cleans up `1/5/25` → `1/5/2025`).
963
1231
  this.startText.set(this.display(start));
964
1232
  this.endText.set(this.display(end));
965
1233
  }
966
1234
  /** Called by an input's click — opens the overlay if it isn't open already. */
967
- openOnInput() {
1235
+ openOnInput(end) {
968
1236
  if (this.disabled() || this.readonly() || this.overlayRef)
969
1237
  return;
970
- this.openOverlay();
1238
+ // Deliberately WITHOUT focus: this click placed a caret in one of the text
1239
+ // fields, and pulling focus into the grid would throw that away.
1240
+ // `Alt+ArrowDown` / `ArrowDown` are the keyboard way in — see onFieldKey.
1241
+ this.openOverlay(this.fieldEl(end), false);
971
1242
  }
972
1243
  toggleOverlay() {
973
1244
  // `readonly` blocks the calendar too — otherwise the inputs refuse typing
974
1245
  // while the popover happily edits the same value.
975
1246
  if (this.disabled() || this.readonly())
976
1247
  return;
977
- if (this.overlayRef)
1248
+ if (this.overlayRef) {
1249
+ // Focus is already on the trigger — nothing to restore.
978
1250
  this.closeOverlay();
979
- else
980
- this.openOverlay();
1251
+ }
1252
+ else {
1253
+ this.openOverlay(this.triggerEl()?.nativeElement ?? null, true);
1254
+ }
1255
+ }
1256
+ /**
1257
+ * The keyboard route into the popup, per the APG date-picker pattern, and the
1258
+ * only one either field has. `Alt+ArrowDown` opens and takes focus; a bare
1259
+ * vertical arrow walks focus in when the popup is ALREADY open, which is how
1260
+ * someone who opened it by clicking a field reaches the grid. Every other key
1261
+ * belongs to the field, so typing a date keeps working with the popup open.
1262
+ */
1263
+ onFieldKey(event, end) {
1264
+ if (this.disabled() || this.readonly())
1265
+ return;
1266
+ const vertical = event.key === 'ArrowDown' || event.key === 'ArrowUp';
1267
+ if (!vertical)
1268
+ return;
1269
+ if (event.altKey && event.key === 'ArrowDown' && !this.overlayRef) {
1270
+ event.preventDefault();
1271
+ this.openOverlay(this.fieldEl(end), true);
1272
+ return;
1273
+ }
1274
+ if (this.overlayRef) {
1275
+ event.preventDefault();
1276
+ this.focusPanel();
1277
+ }
1278
+ }
1279
+ /** The input element for an end — the two are otherwise addressed by index. */
1280
+ fieldEl(end) {
1281
+ return end === 0 ? this.startEl().nativeElement : this.endEl().nativeElement;
1282
+ }
1283
+ /**
1284
+ * Move focus into an already-mounted panel. A plain query is right HERE and
1285
+ * wrong at mount time: the panel has settled, so there is no deferral to get
1286
+ * wrong — and it keeps `autoFocus` as the single piece of panel API.
1287
+ */
1288
+ focusPanel() {
1289
+ const pane = this.overlayRef?.overlayElement;
1290
+ const target = pane?.querySelector('.wr-calendar__day--focused:not([disabled])') ??
1291
+ pane?.querySelector('.wr-time-picker__input');
1292
+ target?.focus();
1293
+ }
1294
+ /** Hand focus back to whatever opened the popup, if it is still on the page. */
1295
+ restoreFocus() {
1296
+ const target = this.openedFrom?.isConnected ? this.openedFrom : this.startEl().nativeElement;
1297
+ target.focus();
981
1298
  }
982
1299
  // Input parsing
983
1300
  onRangeInput(event, end) {
@@ -997,9 +1314,11 @@ class WrDateRangePicker {
997
1314
  this.commitRange(end === 0 ? [parsed, finish] : [start, parsed], { normalise: false });
998
1315
  }
999
1316
  // Overlay
1000
- openOverlay() {
1317
+ openOverlay(openedFrom = null, autoFocus = false) {
1001
1318
  if (this.overlayRef)
1002
1319
  return;
1320
+ this.openedFrom = openedFrom;
1321
+ this.autoFocusPanel = autoFocus;
1003
1322
  const positionStrategy = this.overlay
1004
1323
  .position()
1005
1324
  .flexibleConnectedTo(this.host)
@@ -1016,9 +1335,22 @@ class WrDateRangePicker {
1016
1335
  panelClass: 'wr-date-picker-overlay',
1017
1336
  });
1018
1337
  this.overlayOpen.set(true);
1338
+ // The trigger promises `aria-haspopup="dialog"`; the pane is the element it
1339
+ // points at, so the role, the name and the id all belong here. Non-modal on
1340
+ // purpose — the two text fields stay reachable while the calendar is up,
1341
+ // which is the whole interaction model.
1342
+ const pane = this.overlayRef.overlayElement;
1343
+ pane.id = this.panelId;
1344
+ pane.setAttribute('role', 'dialog');
1345
+ pane.setAttribute('aria-modal', 'false');
1346
+ pane.setAttribute('aria-label', this.resolvedPanelLabel());
1019
1347
  const ref = this.overlayRef.attach(new ComponentPortal(WrDateRangePanel));
1020
1348
  ref.setInput('value', this.value() ?? [null, null]);
1349
+ ref.setInput('autoFocus', this.autoFocusPanel);
1021
1350
  this.panelRef.set(ref);
1351
+ // A stepper edit belongs to the end it was made on. Sorting it here is what
1352
+ // made the start stepper stop responding once it passed the end.
1353
+ ref.instance.timeChanged.subscribe(next => this.commitRange(next, { normalise: false }));
1022
1354
  ref.instance.changed.subscribe(next => {
1023
1355
  const committed = this.commitRange(next, { normalise: true });
1024
1356
  // A complete date-only range is the end of the interaction; a datetime
@@ -1041,21 +1373,31 @@ class WrDateRangePicker {
1041
1373
  if (event.key === 'Escape') {
1042
1374
  event.preventDefault();
1043
1375
  this.closeOverlay();
1044
- this.startEl().nativeElement.focus();
1045
1376
  }
1046
1377
  });
1047
1378
  }
1048
1379
  /**
1049
- * Close the popover. `restoreFocus` returns focus to the start input — needed
1050
- * when the overlay is dismissed while focus lives inside it (picking the
1051
- * second date), because disposing then leaves focus on a removed element and
1052
- * the browser falls back to `<body>`.
1380
+ * Close the popover, handing focus back to whichever field or button opened
1381
+ * it — but ONLY when focus was still inside the pane. Dropped there it would
1382
+ * land on `<body>` and the next Tab would restart from the top of the page;
1383
+ * moved on by the user, it must be left where they put it.
1384
+ *
1385
+ * There is deliberately no "always restore" escape hatch. Escape reaches this
1386
+ * overlay from anywhere in the document (the CDK dispatches it to the topmost
1387
+ * one), so forcing a restore would drag the caret backwards out of the field
1388
+ * the user was actually typing in — into the one that happened to open the
1389
+ * popup, possibly several Tab stops away.
1053
1390
  */
1054
- closeOverlay(restoreFocus = false) {
1055
- const inside = this.overlayRef?.overlayElement.contains(this.host.nativeElement.ownerDocument.activeElement);
1391
+ closeOverlay() {
1392
+ const pane = this.overlayRef?.overlayElement;
1393
+ const inside = !!pane && pane.contains(this.host.nativeElement.ownerDocument.activeElement);
1056
1394
  this.dispose();
1057
- if (restoreFocus || inside)
1058
- this.startEl().nativeElement.focus();
1395
+ // The interaction is over, so settle the ordering an in-progress time edit
1396
+ // was allowed to leave inverted. Blur does the same for the text inputs;
1397
+ // without this, closing by clicking outside never passes through one.
1398
+ this.commitRange(this.current(), { normalise: true });
1399
+ if (inside)
1400
+ this.restoreFocus();
1059
1401
  }
1060
1402
  dispose() {
1061
1403
  if (this.overlayRef) {
@@ -1064,6 +1406,7 @@ class WrDateRangePicker {
1064
1406
  }
1065
1407
  this.panelRef.set(null);
1066
1408
  this.overlayOpen.set(false);
1409
+ this.autoFocusPanel = false;
1067
1410
  }
1068
1411
  // Commit
1069
1412
  /**
@@ -1150,20 +1493,29 @@ class WrDateRangePicker {
1150
1493
  return false;
1151
1494
  return a.getTime() === b.getTime();
1152
1495
  }
1496
+ /**
1497
+ * `null` and `[null, null]` are the same VALUE — an empty range — and treating
1498
+ * them as different is what let the FIRST blur on an untouched picker write
1499
+ * `[null, null]` over the `null` it was bound to. No date had moved, but
1500
+ * `model()` emitted: a bound `[formField]` went dirty from nothing but tabbing
1501
+ * through, and a consumer's `@if (period())` flipped from empty to truthy with
1502
+ * neither end picked. The write guard in `commitRange` is only as good as this
1503
+ * comparison.
1504
+ */
1153
1505
  sameRange(a, b) {
1154
1506
  if (a === b)
1155
1507
  return true;
1156
- if (!a || !b)
1157
- return false;
1158
- return this.sameDate(a[0], b[0]) && this.sameDate(a[1], b[1]);
1508
+ const [aStart, aEnd] = a ?? [null, null];
1509
+ const [bStart, bEnd] = b ?? [null, null];
1510
+ return this.sameDate(aStart, bStart) && this.sameDate(aEnd, bEnd);
1159
1511
  }
1160
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrDateRangePicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
1161
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: WrDateRangePicker, isStandalone: true, selector: "wr-date-range-picker", inputs: { mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, startPlaceholder: { classPropertyName: "startPlaceholder", publicName: "startPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, endPlaceholder: { classPropertyName: "endPlaceholder", publicName: "endPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, separator: { classPropertyName: "separator", publicName: "separator", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, dateFilter: { classPropertyName: "dateFilter", publicName: "dateFilter", isSignal: true, isRequired: false, transformFunction: null }, timeFormat: { classPropertyName: "timeFormat", publicName: "timeFormat", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", 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 }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { properties: { "class": "classes()" } }, viewQueries: [{ propertyName: "startEl", first: true, predicate: ["startInput"], descendants: true, isSignal: true }], ngImport: i0, template: "<wr-input-group>\n <input\n #startInput\n wrInput\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n class=\"wr-date-range-picker__input\"\n [attr.aria-label]=\"startLabel\"\n [value]=\"startText()\"\n [placeholder]=\"startPlaceholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (click)=\"openOnInput()\"\n (input)=\"onStartInput($event)\"\n (blur)=\"onBlur($event)\"\n />\n <span class=\"wr-date-range-picker__separator\" aria-hidden=\"true\">{{ separator() }}</span>\n <input\n wrInput\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n class=\"wr-date-range-picker__input\"\n [attr.aria-label]=\"endLabel\"\n [value]=\"endText()\"\n [placeholder]=\"endPlaceholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (click)=\"openOnInput()\"\n (input)=\"onEndInput($event)\"\n (blur)=\"onBlur($event)\"\n />\n <button\n type=\"button\"\n wrInputSuffix\n class=\"wr-date-picker__trigger\"\n [attr.aria-label]=\"triggerLabel\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-expanded]=\"overlayOpen()\"\n [disabled]=\"disabled()\"\n (click)=\"toggleOverlay()\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" aria-hidden=\"true\">\n <rect x=\"1.5\" y=\"2.5\" width=\"11\" height=\"10\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"1.5\" y1=\"5.5\" x2=\"12.5\" y2=\"5.5\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"4\" y1=\"1\" x2=\"4\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n <line x1=\"10\" y1=\"1\" x2=\"10\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n @if (isDateTime()) {\n <circle cx=\"7\" cy=\"9\" r=\"1.5\" fill=\"currentColor\" />\n }\n </svg>\n </button>\n</wr-input-group>\n", dependencies: [{ kind: "directive", type: WrInput, selector: "input[wrInput], textarea[wrInput]", inputs: ["wrSize", "rounded"] }, { kind: "component", type: WrInputGroup, selector: "wr-input-group", inputs: ["rounded"] }, { kind: "directive", type: WrInputSuffix, selector: "[wrInputSuffix]" }], encapsulation: i0.ViewEncapsulation.None });
1512
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrDateRangePicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
1513
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: WrDateRangePicker, isStandalone: true, selector: "wr-date-range-picker", inputs: { mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, startPlaceholder: { classPropertyName: "startPlaceholder", publicName: "startPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, endPlaceholder: { classPropertyName: "endPlaceholder", publicName: "endPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, separator: { classPropertyName: "separator", publicName: "separator", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, dateFilter: { classPropertyName: "dateFilter", publicName: "dateFilter", isSignal: true, isRequired: false, transformFunction: null }, timeFormat: { classPropertyName: "timeFormat", publicName: "timeFormat", isSignal: true, isRequired: false, transformFunction: null }, showSeconds: { classPropertyName: "showSeconds", publicName: "showSeconds", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", 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 }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, panelAriaLabel: { classPropertyName: "panelAriaLabel", publicName: "panelAriaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { properties: { "class": "classes()" } }, viewQueries: [{ propertyName: "startEl", first: true, predicate: ["startInput"], descendants: true, isSignal: true }, { propertyName: "endEl", first: true, predicate: ["endInput"], descendants: true, isSignal: true }, { propertyName: "triggerEl", first: true, predicate: ["trigger"], descendants: true, isSignal: true }], ngImport: i0, template: "<wr-input-group>\n <input\n #startInput\n wrInput\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n class=\"wr-date-range-picker__input\"\n [attr.aria-label]=\"startLabel\"\n [value]=\"startText()\"\n [placeholder]=\"startPlaceholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (click)=\"openOnInput(0)\"\n (keydown)=\"onFieldKey($event, 0)\"\n (input)=\"onStartInput($event)\"\n (blur)=\"onBlur($event)\"\n />\n <span class=\"wr-date-range-picker__separator\" aria-hidden=\"true\">{{ separator() }}</span>\n <input\n #endInput\n wrInput\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n class=\"wr-date-range-picker__input\"\n [attr.aria-label]=\"endLabel\"\n [value]=\"endText()\"\n [placeholder]=\"endPlaceholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (click)=\"openOnInput(1)\"\n (keydown)=\"onFieldKey($event, 1)\"\n (input)=\"onEndInput($event)\"\n (blur)=\"onBlur($event)\"\n />\n <!--\n `readonly` refuses to open the popup, so the trigger is disabled with it \u2014\n otherwise it stays a focusable button advertising `aria-haspopup=\"dialog\"`\n for a dialog it will never show.\n -->\n <button\n #trigger\n type=\"button\"\n wrInputSuffix\n class=\"wr-date-picker__trigger\"\n [attr.aria-label]=\"triggerLabel\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-expanded]=\"overlayOpen()\"\n [attr.aria-controls]=\"overlayOpen() ? panelId : null\"\n [disabled]=\"disabled() || readonly()\"\n (click)=\"toggleOverlay()\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" aria-hidden=\"true\">\n <rect x=\"1.5\" y=\"2.5\" width=\"11\" height=\"10\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"1.5\" y1=\"5.5\" x2=\"12.5\" y2=\"5.5\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"4\" y1=\"1\" x2=\"4\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n <line x1=\"10\" y1=\"1\" x2=\"10\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n @if (isDateTime()) {\n <circle cx=\"7\" cy=\"9\" r=\"1.5\" fill=\"currentColor\" />\n }\n </svg>\n </button>\n</wr-input-group>\n", dependencies: [{ kind: "directive", type: WrInput, selector: "input[wrInput], textarea[wrInput]", inputs: ["wrSize", "rounded"] }, { kind: "component", type: WrInputGroup, selector: "wr-input-group", inputs: ["rounded"] }, { kind: "directive", type: WrInputSuffix, selector: "[wrInputSuffix]" }], encapsulation: i0.ViewEncapsulation.None });
1162
1514
  }
1163
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrDateRangePicker, decorators: [{
1515
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrDateRangePicker, decorators: [{
1164
1516
  type: Component,
1165
- args: [{ selector: 'wr-date-range-picker', encapsulation: ViewEncapsulation.None, host: { '[class]': 'classes()' }, imports: [WrInput, WrInputGroup, WrInputSuffix], template: "<wr-input-group>\n <input\n #startInput\n wrInput\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n class=\"wr-date-range-picker__input\"\n [attr.aria-label]=\"startLabel\"\n [value]=\"startText()\"\n [placeholder]=\"startPlaceholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (click)=\"openOnInput()\"\n (input)=\"onStartInput($event)\"\n (blur)=\"onBlur($event)\"\n />\n <span class=\"wr-date-range-picker__separator\" aria-hidden=\"true\">{{ separator() }}</span>\n <input\n wrInput\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n class=\"wr-date-range-picker__input\"\n [attr.aria-label]=\"endLabel\"\n [value]=\"endText()\"\n [placeholder]=\"endPlaceholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (click)=\"openOnInput()\"\n (input)=\"onEndInput($event)\"\n (blur)=\"onBlur($event)\"\n />\n <button\n type=\"button\"\n wrInputSuffix\n class=\"wr-date-picker__trigger\"\n [attr.aria-label]=\"triggerLabel\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-expanded]=\"overlayOpen()\"\n [disabled]=\"disabled()\"\n (click)=\"toggleOverlay()\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" aria-hidden=\"true\">\n <rect x=\"1.5\" y=\"2.5\" width=\"11\" height=\"10\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"1.5\" y1=\"5.5\" x2=\"12.5\" y2=\"5.5\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"4\" y1=\"1\" x2=\"4\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n <line x1=\"10\" y1=\"1\" x2=\"10\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n @if (isDateTime()) {\n <circle cx=\"7\" cy=\"9\" r=\"1.5\" fill=\"currentColor\" />\n }\n </svg>\n </button>\n</wr-input-group>\n" }]
1166
- }], ctorParameters: () => [], propDecorators: { mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], startPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "startPlaceholder", required: false }] }], endPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "endPlaceholder", required: false }] }], separator: [{ type: i0.Input, args: [{ isSignal: true, alias: "separator", required: false }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: false }] }], dateFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFilter", required: false }] }], timeFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeFormat", required: false }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], startEl: [{ type: i0.ViewChild, args: ['startInput', { isSignal: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], touch: [{ type: i0.Output, args: ["touch"] }] } });
1517
+ args: [{ selector: 'wr-date-range-picker', encapsulation: ViewEncapsulation.None, host: { '[class]': 'classes()' }, imports: [WrInput, WrInputGroup, WrInputSuffix], template: "<wr-input-group>\n <input\n #startInput\n wrInput\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n class=\"wr-date-range-picker__input\"\n [attr.aria-label]=\"startLabel\"\n [value]=\"startText()\"\n [placeholder]=\"startPlaceholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (click)=\"openOnInput(0)\"\n (keydown)=\"onFieldKey($event, 0)\"\n (input)=\"onStartInput($event)\"\n (blur)=\"onBlur($event)\"\n />\n <span class=\"wr-date-range-picker__separator\" aria-hidden=\"true\">{{ separator() }}</span>\n <input\n #endInput\n wrInput\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n class=\"wr-date-range-picker__input\"\n [attr.aria-label]=\"endLabel\"\n [value]=\"endText()\"\n [placeholder]=\"endPlaceholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (click)=\"openOnInput(1)\"\n (keydown)=\"onFieldKey($event, 1)\"\n (input)=\"onEndInput($event)\"\n (blur)=\"onBlur($event)\"\n />\n <!--\n `readonly` refuses to open the popup, so the trigger is disabled with it \u2014\n otherwise it stays a focusable button advertising `aria-haspopup=\"dialog\"`\n for a dialog it will never show.\n -->\n <button\n #trigger\n type=\"button\"\n wrInputSuffix\n class=\"wr-date-picker__trigger\"\n [attr.aria-label]=\"triggerLabel\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-expanded]=\"overlayOpen()\"\n [attr.aria-controls]=\"overlayOpen() ? panelId : null\"\n [disabled]=\"disabled() || readonly()\"\n (click)=\"toggleOverlay()\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" aria-hidden=\"true\">\n <rect x=\"1.5\" y=\"2.5\" width=\"11\" height=\"10\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"1.5\" y1=\"5.5\" x2=\"12.5\" y2=\"5.5\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <line x1=\"4\" y1=\"1\" x2=\"4\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n <line x1=\"10\" y1=\"1\" x2=\"10\" y2=\"4\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n @if (isDateTime()) {\n <circle cx=\"7\" cy=\"9\" r=\"1.5\" fill=\"currentColor\" />\n }\n </svg>\n </button>\n</wr-input-group>\n" }]
1518
+ }], ctorParameters: () => [], propDecorators: { mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], startPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "startPlaceholder", required: false }] }], endPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "endPlaceholder", required: false }] }], separator: [{ type: i0.Input, args: [{ isSignal: true, alias: "separator", required: false }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: false }] }], dateFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFilter", required: false }] }], timeFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeFormat", required: false }] }], showSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSeconds", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], startEl: [{ type: i0.ViewChild, args: ['startInput', { isSignal: true }] }], endEl: [{ type: i0.ViewChild, args: ['endInput', { isSignal: true }] }], triggerEl: [{ type: i0.ViewChild, args: ['trigger', { isSignal: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], touch: [{ type: i0.Output, args: ["touch"] }], panelAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelAriaLabel", required: false }] }] } });
1167
1519
 
1168
1520
  /**
1169
1521
  * Generated bundle index. Do not edit.