vectis-ui 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (432) hide show
  1. package/README.md +68 -334
  2. package/dist/components/VAccordion/VAccordionItem.d.ts +4 -6
  3. package/dist/components/VAccordion/VAccordionItem.js.map +1 -1
  4. package/dist/components/VAccordion/VAccordionItem.vue_vue_type_script_setup_true_lang.js +21 -19
  5. package/dist/components/VAccordion/VAccordionItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  6. package/dist/components/VAccordion/context.d.ts +6 -1
  7. package/dist/components/VAccordion/context.js.map +1 -1
  8. package/dist/components/VAvatar/VAvatar.css +1 -1
  9. package/dist/components/VAvatar/VAvatar.d.ts +5 -3
  10. package/dist/components/VAvatar/VAvatar.js.map +1 -1
  11. package/dist/components/VAvatar/VAvatar.vue_vue_type_script_setup_true_lang.js +53 -39
  12. package/dist/components/VAvatar/VAvatar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  13. package/dist/components/VAvatar/VAvatarGroup.d.ts +12 -3
  14. package/dist/components/VAvatar/VAvatarGroup.js.map +1 -1
  15. package/dist/components/VAvatar/VAvatarGroup.vue_vue_type_script_setup_true_lang.js +27 -20
  16. package/dist/components/VAvatar/VAvatarGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  17. package/dist/components/VAvatar/context.d.ts +2 -2
  18. package/dist/components/VAvatar/context.js.map +1 -1
  19. package/dist/components/VBadge/VBadge.css +1 -1
  20. package/dist/components/VBadge/VBadge.d.ts +8 -4
  21. package/dist/components/VBadge/VBadge.js.map +1 -1
  22. package/dist/components/VBadge/VBadge.vue_vue_type_script_setup_true_lang.js +6 -3
  23. package/dist/components/VBadge/VBadge.vue_vue_type_script_setup_true_lang.js.map +1 -1
  24. package/dist/components/VBreadcrumb/VBreadcrumb.d.ts +5 -4
  25. package/dist/components/VBreadcrumb/VBreadcrumb.js.map +1 -1
  26. package/dist/components/VBreadcrumb/VBreadcrumb.vue_vue_type_script_setup_true_lang.js +8 -3
  27. package/dist/components/VBreadcrumb/VBreadcrumb.vue_vue_type_script_setup_true_lang.js.map +1 -1
  28. package/dist/components/VButton/VButton.css +1 -1
  29. package/dist/components/VButton/VButton.d.ts +4 -1
  30. package/dist/components/VButton/VButton.js.map +1 -1
  31. package/dist/components/VButton/VButton.vue_vue_type_script_setup_true_lang.js +8 -7
  32. package/dist/components/VButton/VButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
  33. package/dist/components/VButton/VButtonGroup.js.map +1 -1
  34. package/dist/components/VButton/VButtonGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  35. package/dist/components/VCalendar/VCalendar.css +1 -1
  36. package/dist/components/VCalendar/VCalendar.d.ts +15 -6
  37. package/dist/components/VCalendar/VCalendar.js.map +1 -1
  38. package/dist/components/VCalendar/VCalendar.vue_vue_type_script_setup_true_lang.js +144 -126
  39. package/dist/components/VCalendar/VCalendar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  40. package/dist/components/VCalendar/VCalendarEvent.css +1 -1
  41. package/dist/components/VCalendar/VCalendarEvent.d.ts +1 -1
  42. package/dist/components/VCalendar/VCalendarEvent.js.map +1 -1
  43. package/dist/components/VCalendar/VCalendarEvent.vue_vue_type_script_setup_true_lang.js.map +1 -1
  44. package/dist/components/VCalendar/VCalendarMonth.css +1 -1
  45. package/dist/components/VCalendar/VCalendarMonth.d.ts +1 -1
  46. package/dist/components/VCalendar/VCalendarMonth.js.map +1 -1
  47. package/dist/components/VCalendar/VCalendarMonth.vue_vue_type_script_setup_true_lang.js +99 -90
  48. package/dist/components/VCalendar/VCalendarMonth.vue_vue_type_script_setup_true_lang.js.map +1 -1
  49. package/dist/components/VCalendar/VCalendarTimeGrid.css +1 -1
  50. package/dist/components/VCalendar/VCalendarTimeGrid.d.ts +3 -3
  51. package/dist/components/VCalendar/VCalendarTimeGrid.js.map +1 -1
  52. package/dist/components/VCalendar/VCalendarTimeGrid.vue_vue_type_script_setup_true_lang.js +256 -246
  53. package/dist/components/VCalendar/VCalendarTimeGrid.vue_vue_type_script_setup_true_lang.js.map +1 -1
  54. package/dist/components/VCalendar/VCalendarYear.css +1 -1
  55. package/dist/components/VCalendar/VCalendarYear.d.ts +8 -1
  56. package/dist/components/VCalendar/VCalendarYear.js.map +1 -1
  57. package/dist/components/VCalendar/VCalendarYear.vue_vue_type_script_setup_true_lang.js +39 -32
  58. package/dist/components/VCalendar/VCalendarYear.vue_vue_type_script_setup_true_lang.js.map +1 -1
  59. package/dist/components/VCalendar/color.d.ts +1 -1
  60. package/dist/components/VCalendar/color.js.map +1 -1
  61. package/dist/components/VCalendar/edgeStep.d.ts +3 -3
  62. package/dist/components/VCalendar/edgeStep.js +5 -0
  63. package/dist/components/VCalendar/edgeStep.js.map +1 -1
  64. package/dist/components/VCalendar/gesture.d.ts +10 -9
  65. package/dist/components/VCalendar/gesture.js +60 -45
  66. package/dist/components/VCalendar/gesture.js.map +1 -1
  67. package/dist/components/VCalendar/keyboard.d.ts +22 -5
  68. package/dist/components/VCalendar/keyboard.js +17 -16
  69. package/dist/components/VCalendar/keyboard.js.map +1 -1
  70. package/dist/components/VCalendar/layout.d.ts +47 -37
  71. package/dist/components/VCalendar/layout.js +47 -37
  72. package/dist/components/VCalendar/layout.js.map +1 -1
  73. package/dist/components/VCalendar/timeGrid.d.ts +4 -4
  74. package/dist/components/VCalendar/timeGrid.js +6 -6
  75. package/dist/components/VCalendar/timeGrid.js.map +1 -1
  76. package/dist/components/VCalendar/types.d.ts +5 -5
  77. package/dist/components/VCarousel/VCarousel.css +1 -1
  78. package/dist/components/VCarousel/VCarousel.d.ts +59 -38
  79. package/dist/components/VCarousel/VCarousel.js.map +1 -1
  80. package/dist/components/VCarousel/VCarousel.vue_vue_type_script_setup_true_lang.js +161 -132
  81. package/dist/components/VCarousel/VCarousel.vue_vue_type_script_setup_true_lang.js.map +1 -1
  82. package/dist/components/VCarousel/VCarouselItem.d.ts +1 -1
  83. package/dist/components/VCarousel/VCarouselItem.js.map +1 -1
  84. package/dist/components/VCarousel/VCarouselItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  85. package/dist/components/VCarousel/context.d.ts +1 -1
  86. package/dist/components/VCarousel/context.js.map +1 -1
  87. package/dist/components/VCheckbox/VCheckbox.css +1 -1
  88. package/dist/components/VCheckbox/VCheckbox.d.ts +2 -2
  89. package/dist/components/VCheckbox/VCheckbox.js.map +1 -1
  90. package/dist/components/VCheckbox/VCheckbox.vue_vue_type_script_setup_true_lang.js +10 -8
  91. package/dist/components/VCheckbox/VCheckbox.vue_vue_type_script_setup_true_lang.js.map +1 -1
  92. package/dist/components/VChip/VChip.css +1 -1
  93. package/dist/components/VChip/VChip.d.ts +7 -2
  94. package/dist/components/VChip/VChip.js.map +1 -1
  95. package/dist/components/VChip/VChip.vue_vue_type_script_setup_true_lang.js +69 -55
  96. package/dist/components/VChip/VChip.vue_vue_type_script_setup_true_lang.js.map +1 -1
  97. package/dist/components/VCombobox/VCombobox.css +1 -1
  98. package/dist/components/VCombobox/VCombobox.d.ts +50 -36
  99. package/dist/components/VCombobox/VCombobox.js.map +1 -1
  100. package/dist/components/VCombobox/VCombobox.vue_vue_type_script_setup_true_lang.js +167 -161
  101. package/dist/components/VCombobox/VCombobox.vue_vue_type_script_setup_true_lang.js.map +1 -1
  102. package/dist/components/VCombobox/VComboboxGroup.css +1 -1
  103. package/dist/components/VCombobox/VComboboxGroup.js.map +1 -1
  104. package/dist/components/VCombobox/VComboboxGroup.vue_vue_type_script_setup_true_lang.js +1 -1
  105. package/dist/components/VCombobox/VComboboxGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  106. package/dist/components/VCombobox/infiniteScroll.d.ts +12 -3
  107. package/dist/components/VCombobox/infiniteScroll.js +18 -12
  108. package/dist/components/VCombobox/infiniteScroll.js.map +1 -1
  109. package/dist/components/VDataTable/VDataTable.css +1 -1
  110. package/dist/components/VDataTable/VDataTable.d.ts +55 -24
  111. package/dist/components/VDataTable/VDataTable.js.map +1 -1
  112. package/dist/components/VDataTable/VDataTable.vue_vue_type_script_setup_true_lang.js +192 -155
  113. package/dist/components/VDataTable/VDataTable.vue_vue_type_script_setup_true_lang.js.map +1 -1
  114. package/dist/components/VDateInput/VDateInput.css +1 -1
  115. package/dist/components/VDateInput/VDateInput.d.ts +15 -12
  116. package/dist/components/VDateInput/VDateInput.js.map +1 -1
  117. package/dist/components/VDateInput/VDateInput.vue_vue_type_script_setup_true_lang.js +180 -160
  118. package/dist/components/VDateInput/VDateInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
  119. package/dist/components/VDateInput/mask.d.ts +95 -0
  120. package/dist/components/VDateInput/mask.js +118 -0
  121. package/dist/components/VDateInput/mask.js.map +1 -0
  122. package/dist/components/VDatePicker/VDatePicker.css +1 -1
  123. package/dist/components/VDatePicker/VDatePicker.d.ts +6 -5
  124. package/dist/components/VDatePicker/VDatePicker.js.map +1 -1
  125. package/dist/components/VDatePicker/VDatePicker.vue_vue_type_script_setup_true_lang.js +204 -173
  126. package/dist/components/VDatePicker/VDatePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
  127. package/dist/components/VDatePicker/keyboard.d.ts +3 -3
  128. package/dist/components/VDatePicker/keyboard.js.map +1 -1
  129. package/dist/components/VDatePicker/names.d.ts +34 -0
  130. package/dist/components/VDatePicker/names.js +42 -0
  131. package/dist/components/VDatePicker/names.js.map +1 -0
  132. package/dist/components/VDialog/VDialog.css +1 -1
  133. package/dist/components/VDialog/VDialog.d.ts +2 -2
  134. package/dist/components/VDialog/VDialog.js.map +1 -1
  135. package/dist/components/VDialog/VDialog.vue_vue_type_script_setup_true_lang.js +63 -41
  136. package/dist/components/VDialog/VDialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
  137. package/dist/components/VFileInput/VFileInput.d.ts +38 -25
  138. package/dist/components/VFileInput/VFileInput.js.map +1 -1
  139. package/dist/components/VFileInput/VFileInput.vue_vue_type_script_setup_true_lang.js +74 -71
  140. package/dist/components/VFileInput/VFileInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
  141. package/dist/components/VFileInput/truncate.d.ts +4 -4
  142. package/dist/components/VFileInput/truncate.js.map +1 -1
  143. package/dist/components/VFilePicker/VFilePicker.css +1 -1
  144. package/dist/components/VFilePicker/VFilePicker.d.ts +54 -37
  145. package/dist/components/VFilePicker/VFilePicker.js.map +1 -1
  146. package/dist/components/VFilePicker/VFilePicker.vue_vue_type_script_setup_true_lang.js +152 -135
  147. package/dist/components/VFilePicker/VFilePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
  148. package/dist/components/VFilePicker/fileKind.d.ts +2 -2
  149. package/dist/components/VFilePicker/fileKind.js.map +1 -1
  150. package/dist/components/VHotkeys/VHotkeys.css +1 -1
  151. package/dist/components/VHotkeys/VHotkeys.d.ts +10 -8
  152. package/dist/components/VHotkeys/VHotkeys.js.map +1 -1
  153. package/dist/components/VHotkeys/VHotkeys.vue_vue_type_script_setup_true_lang.js +22 -20
  154. package/dist/components/VHotkeys/VHotkeys.vue_vue_type_script_setup_true_lang.js.map +1 -1
  155. package/dist/components/VHotkeys/platform.d.ts +9 -7
  156. package/dist/components/VHotkeys/platform.js +41 -30
  157. package/dist/components/VHotkeys/platform.js.map +1 -1
  158. package/dist/components/VIcon/VIcon.css +1 -1
  159. package/dist/components/VIcon/VIcon.d.ts +6 -6
  160. package/dist/components/VIcon/VIcon.js.map +1 -1
  161. package/dist/components/VIcon/VIcon.vue_vue_type_script_setup_true_lang.js.map +1 -1
  162. package/dist/components/VIcon/iconProps.d.ts +4 -4
  163. package/dist/components/VIcon/iconProps.js.map +1 -1
  164. package/dist/components/VIcon/icons/index.d.ts +1 -1
  165. package/dist/components/VIcon/icons/index.js.map +1 -1
  166. package/dist/components/VIcon/icons/names.d.ts +1 -1
  167. package/dist/components/VIcon/icons/names.js.map +1 -1
  168. package/dist/components/VIcon/resolver.d.ts +3 -3
  169. package/dist/components/VIcon/resolver.js +23 -20
  170. package/dist/components/VIcon/resolver.js.map +1 -1
  171. package/dist/components/VIcon/types.d.ts +4 -4
  172. package/dist/components/VIconButton/VIconButton.d.ts +4 -4
  173. package/dist/components/VIconButton/VIconButton.js.map +1 -1
  174. package/dist/components/VIconButton/VIconButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
  175. package/dist/components/VInput/VInput.d.ts +16 -8
  176. package/dist/components/VInput/VInput.js.map +1 -1
  177. package/dist/components/VInput/VInput.vue_vue_type_script_setup_true_lang.js +22 -16
  178. package/dist/components/VInput/VInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
  179. package/dist/components/VInput/VInputGroup.css +1 -1
  180. package/dist/components/VInput/VInputGroup.js.map +1 -1
  181. package/dist/components/VInput/VInputGroup.vue_vue_type_script_setup_true_lang.js +43 -28
  182. package/dist/components/VInput/VInputGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  183. package/dist/components/VInputOTP/VInputOTP.css +1 -1
  184. package/dist/components/VInputOTP/VInputOTP.d.ts +3 -3
  185. package/dist/components/VInputOTP/VInputOTP.js.map +1 -1
  186. package/dist/components/VInputOTP/VInputOTP.vue_vue_type_script_setup_true_lang.js +152 -85
  187. package/dist/components/VInputOTP/VInputOTP.vue_vue_type_script_setup_true_lang.js.map +1 -1
  188. package/dist/components/VMenu/VMenu.d.ts +4 -4
  189. package/dist/components/VMenu/VMenu.js.map +1 -1
  190. package/dist/components/VMenu/VMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
  191. package/dist/components/VMenu/VMenuGroup.css +1 -1
  192. package/dist/components/VMenu/VMenuGroup.js.map +1 -1
  193. package/dist/components/VMenu/VMenuGroup.vue_vue_type_script_setup_true_lang.js +18 -11
  194. package/dist/components/VMenu/VMenuGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  195. package/dist/components/VMenu/VMenuItem.css +1 -1
  196. package/dist/components/VMenu/VMenuItem.d.ts +6 -6
  197. package/dist/components/VMenu/VMenuItem.js.map +1 -1
  198. package/dist/components/VMenu/VMenuItem.vue_vue_type_script_setup_true_lang.js +83 -69
  199. package/dist/components/VMenu/VMenuItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  200. package/dist/components/VMenu/VMenuPanel.css +1 -1
  201. package/dist/components/VMenu/VMenuPanel.d.ts +2 -2
  202. package/dist/components/VMenu/VMenuPanel.js.map +1 -1
  203. package/dist/components/VMenu/VMenuPanel.vue_vue_type_script_setup_true_lang.js +56 -55
  204. package/dist/components/VMenu/VMenuPanel.vue_vue_type_script_setup_true_lang.js.map +1 -1
  205. package/dist/components/VMenu/context.d.ts +2 -2
  206. package/dist/components/VMenu/context.js.map +1 -1
  207. package/dist/components/VPagination/VPagination.css +1 -1
  208. package/dist/components/VPagination/VPagination.d.ts +22 -9
  209. package/dist/components/VPagination/VPagination.js.map +1 -1
  210. package/dist/components/VPagination/VPagination.vue_vue_type_script_setup_true_lang.js +67 -57
  211. package/dist/components/VPagination/VPagination.vue_vue_type_script_setup_true_lang.js.map +1 -1
  212. package/dist/components/VPopover/VPopover.css +1 -1
  213. package/dist/components/VPopover/VPopover.d.ts +1 -1
  214. package/dist/components/VPopover/VPopover.js.map +1 -1
  215. package/dist/components/VPopover/VPopover.vue_vue_type_script_setup_true_lang.js.map +1 -1
  216. package/dist/components/VProgressCircular/VProgressCircular.css +1 -1
  217. package/dist/components/VProgressCircular/VProgressCircular.d.ts +12 -7
  218. package/dist/components/VProgressCircular/VProgressCircular.js.map +1 -1
  219. package/dist/components/VProgressCircular/VProgressCircular.vue_vue_type_script_setup_true_lang.js.map +1 -1
  220. package/dist/components/VProgressLinear/VProgressLinear.css +1 -1
  221. package/dist/components/VProgressLinear/VProgressLinear.d.ts +15 -10
  222. package/dist/components/VProgressLinear/VProgressLinear.js.map +1 -1
  223. package/dist/components/VProgressLinear/VProgressLinear.vue_vue_type_script_setup_true_lang.js.map +1 -1
  224. package/dist/components/VRadio/VRadio.css +1 -1
  225. package/dist/components/VRadio/VRadio.js.map +1 -1
  226. package/dist/components/VRadio/VRadio.vue_vue_type_script_setup_true_lang.js +3 -3
  227. package/dist/components/VRadio/VRadio.vue_vue_type_script_setup_true_lang.js.map +1 -1
  228. package/dist/components/VSeparator/VSeparator.d.ts +1 -1
  229. package/dist/components/VSeparator/VSeparator.js.map +1 -1
  230. package/dist/components/VSeparator/VSeparator.vue_vue_type_script_setup_true_lang.js.map +1 -1
  231. package/dist/components/VSideNavigation/VSideNavigation.d.ts +2 -2
  232. package/dist/components/VSideNavigation/VSideNavigation.js.map +1 -1
  233. package/dist/components/VSideNavigation/VSideNavigation.vue_vue_type_script_setup_true_lang.js +1 -1
  234. package/dist/components/VSideNavigation/VSideNavigation.vue_vue_type_script_setup_true_lang.js.map +1 -1
  235. package/dist/components/VSideNavigation/VSideNavigationGroup.css +1 -1
  236. package/dist/components/VSideNavigation/VSideNavigationGroup.js.map +1 -1
  237. package/dist/components/VSideNavigation/VSideNavigationGroup.vue_vue_type_script_setup_true_lang.js +1 -1
  238. package/dist/components/VSideNavigation/VSideNavigationGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  239. package/dist/components/VSideNavigation/VSideNavigationItem.css +1 -1
  240. package/dist/components/VSideNavigation/VSideNavigationItem.d.ts +12 -13
  241. package/dist/components/VSideNavigation/VSideNavigationItem.js.map +1 -1
  242. package/dist/components/VSideNavigation/VSideNavigationItem.vue_vue_type_script_setup_true_lang.js +87 -68
  243. package/dist/components/VSideNavigation/VSideNavigationItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  244. package/dist/components/VSkeletonLoader/VSkeletonLoader.css +1 -1
  245. package/dist/components/VSkeletonLoader/VSkeletonLoader.d.ts +10 -7
  246. package/dist/components/VSkeletonLoader/VSkeletonLoader.js.map +1 -1
  247. package/dist/components/VSkeletonLoader/VSkeletonLoader.vue_vue_type_script_setup_true_lang.js +5 -5
  248. package/dist/components/VSkeletonLoader/VSkeletonLoader.vue_vue_type_script_setup_true_lang.js.map +1 -1
  249. package/dist/components/VSlider/VSlider.css +1 -1
  250. package/dist/components/VSlider/VSlider.d.ts +21 -7
  251. package/dist/components/VSlider/VSlider.js.map +1 -1
  252. package/dist/components/VSlider/VSlider.vue_vue_type_script_setup_true_lang.js +159 -140
  253. package/dist/components/VSlider/VSlider.vue_vue_type_script_setup_true_lang.js.map +1 -1
  254. package/dist/components/VSnackbar/VSnackbar.css +1 -1
  255. package/dist/components/VSnackbar/VSnackbar.d.ts +4 -4
  256. package/dist/components/VSnackbar/VSnackbar.js.map +1 -1
  257. package/dist/components/VSnackbar/VSnackbar.vue_vue_type_script_setup_true_lang.js +85 -59
  258. package/dist/components/VSnackbar/VSnackbar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  259. package/dist/components/VSnackbar/state.d.ts +7 -7
  260. package/dist/components/VSnackbar/state.js +13 -11
  261. package/dist/components/VSnackbar/state.js.map +1 -1
  262. package/dist/components/VSpinner/VSpinner.css +1 -1
  263. package/dist/components/VSpinner/VSpinner.js.map +1 -1
  264. package/dist/components/VSpinner/VSpinner.vue_vue_type_script_setup_true_lang.js.map +1 -1
  265. package/dist/components/VSwitch/VSwitch.css +1 -1
  266. package/dist/components/VSwitch/VSwitch.d.ts +1 -1
  267. package/dist/components/VSwitch/VSwitch.js.map +1 -1
  268. package/dist/components/VSwitch/VSwitch.vue_vue_type_script_setup_true_lang.js +4 -4
  269. package/dist/components/VSwitch/VSwitch.vue_vue_type_script_setup_true_lang.js.map +1 -1
  270. package/dist/components/VTabs/VTab.css +1 -1
  271. package/dist/components/VTabs/VTab.d.ts +4 -0
  272. package/dist/components/VTabs/VTab.js.map +1 -1
  273. package/dist/components/VTabs/VTab.vue_vue_type_script_setup_true_lang.js +9 -8
  274. package/dist/components/VTabs/VTab.vue_vue_type_script_setup_true_lang.js.map +1 -1
  275. package/dist/components/VTabs/VTabs.css +1 -1
  276. package/dist/components/VTabs/VTabs.d.ts +17 -7
  277. package/dist/components/VTabs/VTabs.js.map +1 -1
  278. package/dist/components/VTabs/VTabs.vue_vue_type_script_setup_true_lang.js +84 -77
  279. package/dist/components/VTabs/VTabs.vue_vue_type_script_setup_true_lang.js.map +1 -1
  280. package/dist/components/VTextarea/VTextarea.d.ts +8 -8
  281. package/dist/components/VTextarea/VTextarea.js.map +1 -1
  282. package/dist/components/VTextarea/VTextarea.vue_vue_type_script_setup_true_lang.js +71 -69
  283. package/dist/components/VTextarea/VTextarea.vue_vue_type_script_setup_true_lang.js.map +1 -1
  284. package/dist/components/VTimeInput/VTimeInput.css +1 -1
  285. package/dist/components/VTimeInput/VTimeInput.d.ts +21 -12
  286. package/dist/components/VTimeInput/VTimeInput.js.map +1 -1
  287. package/dist/components/VTimeInput/VTimeInput.vue_vue_type_script_setup_true_lang.js +230 -206
  288. package/dist/components/VTimeInput/VTimeInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
  289. package/dist/components/VTimeInput/search.d.ts +17 -2
  290. package/dist/components/VTimeInput/search.js +19 -9
  291. package/dist/components/VTimeInput/search.js.map +1 -1
  292. package/dist/components/VTimePicker/VTimePicker.css +1 -1
  293. package/dist/components/VTimePicker/VTimePicker.d.ts +8 -7
  294. package/dist/components/VTimePicker/VTimePicker.js.map +1 -1
  295. package/dist/components/VTimePicker/VTimePicker.vue_vue_type_script_setup_true_lang.js +128 -106
  296. package/dist/components/VTimePicker/VTimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
  297. package/dist/components/VTimePicker/limits.d.ts +11 -4
  298. package/dist/components/VTimePicker/limits.js +3 -2
  299. package/dist/components/VTimePicker/limits.js.map +1 -1
  300. package/dist/components/VToast/VToast.css +1 -1
  301. package/dist/components/VToast/VToast.js.map +1 -1
  302. package/dist/components/VToast/VToast.vue_vue_type_script_setup_true_lang.js +33 -37
  303. package/dist/components/VToast/VToast.vue_vue_type_script_setup_true_lang.js.map +1 -1
  304. package/dist/components/VToast/VToaster.js.map +1 -1
  305. package/dist/components/VToast/VToaster.vue_vue_type_script_setup_true_lang.js +91 -61
  306. package/dist/components/VToast/VToaster.vue_vue_type_script_setup_true_lang.js.map +1 -1
  307. package/dist/components/VToast/state.d.ts +8 -6
  308. package/dist/components/VToast/state.js +15 -13
  309. package/dist/components/VToast/state.js.map +1 -1
  310. package/dist/components/VToggle/VToggle.css +1 -1
  311. package/dist/components/VToggle/VToggle.d.ts +9 -4
  312. package/dist/components/VToggle/VToggle.js.map +1 -1
  313. package/dist/components/VToggle/VToggle.vue_vue_type_script_setup_true_lang.js +2 -1
  314. package/dist/components/VToggle/VToggle.vue_vue_type_script_setup_true_lang.js.map +1 -1
  315. package/dist/components/VToggle/VToggleItem.d.ts +4 -0
  316. package/dist/components/VToggle/VToggleItem.js.map +1 -1
  317. package/dist/components/VToggle/VToggleItem.vue_vue_type_script_setup_true_lang.js +5 -5
  318. package/dist/components/VToggle/VToggleItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  319. package/dist/components/VTooltip/VTooltip.css +1 -1
  320. package/dist/components/VTooltip/VTooltip.d.ts +17 -10
  321. package/dist/components/VTooltip/VTooltip.js.map +1 -1
  322. package/dist/components/VTooltip/VTooltip.vue_vue_type_script_setup_true_lang.js +46 -26
  323. package/dist/components/VTooltip/VTooltip.vue_vue_type_script_setup_true_lang.js.map +1 -1
  324. package/dist/components/VTypography/VTypography.css +1 -1
  325. package/dist/components/VTypography/VTypography.d.ts +6 -4
  326. package/dist/components/VTypography/VTypography.js.map +1 -1
  327. package/dist/components/VTypography/VTypography.vue_vue_type_script_setup_true_lang.js.map +1 -1
  328. package/dist/composables/useAriaLabel.js +1 -1
  329. package/dist/composables/useAriaLabel.js.map +1 -1
  330. package/dist/composables/useClearable.d.ts +2 -2
  331. package/dist/composables/useClearable.js.map +1 -1
  332. package/dist/composables/useDetailsOpen.d.ts +3 -3
  333. package/dist/composables/useDetailsOpen.js +14 -12
  334. package/dist/composables/useDetailsOpen.js.map +1 -1
  335. package/dist/composables/useFieldIds.d.ts +2 -1
  336. package/dist/composables/useFieldIds.js +6 -5
  337. package/dist/composables/useFieldIds.js.map +1 -1
  338. package/dist/composables/useFieldPanel.d.ts +2 -2
  339. package/dist/composables/useFieldPanel.js +47 -37
  340. package/dist/composables/useFieldPanel.js.map +1 -1
  341. package/dist/composables/useFileDrop.js +3 -3
  342. package/dist/composables/useFileDrop.js.map +1 -1
  343. package/dist/composables/useFileField.d.ts +1 -1
  344. package/dist/composables/useFileField.js +62 -41
  345. package/dist/composables/useFileField.js.map +1 -1
  346. package/dist/composables/useIconClickHandlers.d.ts +3 -3
  347. package/dist/composables/useIconClickHandlers.js +14 -13
  348. package/dist/composables/useIconClickHandlers.js.map +1 -1
  349. package/dist/composables/useInertLink.js +12 -10
  350. package/dist/composables/useInertLink.js.map +1 -1
  351. package/dist/composables/useLiveAnnouncer.d.ts +5 -0
  352. package/dist/composables/useLiveAnnouncer.js +23 -0
  353. package/dist/composables/useLiveAnnouncer.js.map +1 -0
  354. package/dist/composables/useMaskedField.d.ts +5 -5
  355. package/dist/composables/useMaskedField.js.map +1 -1
  356. package/dist/composables/usePopover.d.ts +3 -3
  357. package/dist/composables/usePopover.js +6 -4
  358. package/dist/composables/usePopover.js.map +1 -1
  359. package/dist/composables/useProgressValue.js +11 -2
  360. package/dist/composables/useProgressValue.js.map +1 -1
  361. package/dist/composables/useRootAttrs.d.ts +1 -1
  362. package/dist/composables/useRootAttrs.js.map +1 -1
  363. package/dist/composables/useSlotNodes.d.ts +18 -0
  364. package/dist/composables/useSlotNodes.js +13 -0
  365. package/dist/composables/useSlotNodes.js.map +1 -0
  366. package/dist/composables/useTextLimit.d.ts +2 -1
  367. package/dist/composables/useTextLimit.js +2 -2
  368. package/dist/composables/useTextLimit.js.map +1 -1
  369. package/dist/composables/useTimer.d.ts +5 -0
  370. package/dist/composables/useTimer.js +22 -11
  371. package/dist/composables/useTimer.js.map +1 -1
  372. package/dist/i18n/en.js +1 -1
  373. package/dist/i18n/en.js.map +1 -1
  374. package/dist/i18n/fr.js +14 -14
  375. package/dist/i18n/fr.js.map +1 -1
  376. package/dist/i18n/state.d.ts +7 -7
  377. package/dist/i18n/state.js +37 -28
  378. package/dist/i18n/state.js.map +1 -1
  379. package/dist/i18n/types.d.ts +12 -12
  380. package/dist/icons.d.ts +2 -2
  381. package/dist/index.d.ts +12 -11
  382. package/dist/styles.css +1 -1
  383. package/dist/tokens/css.d.ts +1 -1
  384. package/dist/tokens/css.js.map +1 -1
  385. package/dist/tokens/index.d.ts +6 -0
  386. package/dist/tokens/semantic.d.ts +6 -0
  387. package/dist/tokens/semantic.js +66 -60
  388. package/dist/tokens/semantic.js.map +1 -1
  389. package/dist/tokens/themes/dark.js +3 -3
  390. package/dist/tokens/themes/dark.js.map +1 -1
  391. package/dist/tokens.json +130 -66
  392. package/dist/types.d.ts +1 -1
  393. package/dist/utils/arrowNav.d.ts +4 -1
  394. package/dist/utils/arrowNav.js +7 -7
  395. package/dist/utils/arrowNav.js.map +1 -1
  396. package/dist/utils/chip.d.ts +1 -1
  397. package/dist/utils/chip.js.map +1 -1
  398. package/dist/utils/clock.d.ts +113 -0
  399. package/dist/utils/clock.js +84 -0
  400. package/dist/utils/clock.js.map +1 -0
  401. package/dist/utils/css.d.ts +6 -4
  402. package/dist/utils/css.js +2 -2
  403. package/dist/utils/css.js.map +1 -1
  404. package/dist/utils/date.d.ts +7 -102
  405. package/dist/utils/date.js +33 -160
  406. package/dist/utils/date.js.map +1 -1
  407. package/dist/utils/direction.d.ts +1 -1
  408. package/dist/utils/direction.js.map +1 -1
  409. package/dist/utils/env.d.ts +12 -3
  410. package/dist/utils/env.js +6 -0
  411. package/dist/utils/env.js.map +1 -0
  412. package/dist/utils/file.d.ts +3 -3
  413. package/dist/utils/file.js +1 -1
  414. package/dist/utils/file.js.map +1 -1
  415. package/dist/utils/focus.d.ts +1 -1
  416. package/dist/utils/focus.js.map +1 -1
  417. package/dist/utils/hostWarns.d.ts +1 -1
  418. package/dist/utils/hostWarns.js.map +1 -1
  419. package/dist/utils/ids.d.ts +1 -1
  420. package/dist/utils/ids.js.map +1 -1
  421. package/dist/utils/matcher.d.ts +2 -2
  422. package/dist/utils/matcher.js.map +1 -1
  423. package/dist/utils/memo.d.ts +1 -1
  424. package/dist/utils/memo.js.map +1 -1
  425. package/dist/utils/text.d.ts +3 -3
  426. package/dist/utils/text.js.map +1 -1
  427. package/dist/utils/time.d.ts +2 -101
  428. package/dist/utils/time.js +22 -98
  429. package/dist/utils/time.js.map +1 -1
  430. package/dist/utils/vnode.d.ts +5 -3
  431. package/dist/utils/vnode.js.map +1 -1
  432. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"VDatePicker.vue_vue_type_script_setup_true_lang.js","names":["$slots"],"sources":["../../../src/components/VDatePicker/VDatePicker.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @a11y @keyboard @core\n/**\n * A calendar shown directly in the page, as a grid of days, with a month view and a\n * year view behind it. It holds ALL the date, view and keyboard logic of the design\n * system; VDateInput does no more than dress it in a text field and a popover.\n *\n * The platform offers no accessible date grid to build on — `<input type=\"date\">`\n * can be neither styled nor composed — so the JavaScript here implements the ARIA\n * \"grid\" pattern by hand: a single cell in the tab order at a time, arrow and\n * page keys to move between dates, and selection of one date, a range or a list.\n * None of that can be expressed in HTML and CSS alone.\n *\n * Every date is handled in local time as an ISO `YYYY-MM-DD` string (see\n * `utils/date`), which is what keeps the server and the browser in agreement.\n */\n\nimport { computed, inject, nextTick, onMounted, ref, useId, watch, watchEffect } from 'vue'\nimport type { Ref } from 'vue'\n\nimport VButton from '../VButton/VButton.vue'\nimport VIcon from '../VIcon/VIcon.vue'\nimport { arrow_drop_down as arrowDropDownIcon } from '../VIcon/icons/arrow_drop_down'\nimport { arrow_drop_up as arrowDropUpIcon } from '../VIcon/icons/arrow_drop_up'\nimport { chevron_left as chevronLeftIcon } from '../VIcon/icons/chevron_left'\nimport { chevron_right as chevronRightIcon } from '../VIcon/icons/chevron_right'\nimport VIconButton from '../VIconButton/VIconButton.vue'\nimport {\n addDays,\n addMonths,\n buildMonthGrid,\n clampISO,\n compareISO,\n daysInMonth,\n firstDayOfWeekFor,\n formatISO,\n isDateAllowed,\n isoOf,\n isSameISO,\n isValidISO,\n monthName,\n monthNamesCompact,\n parseISO,\n weekdayNames,\n} from '../../utils/date'\n\nimport { PICKER_COLUMNS, dayStep, gridDelta } from './keyboard'\n\nimport { toggleValue } from '../../utils/array'\nimport { isDev } from '../../utils/env'\nimport { hostWarnsKey } from '../../utils/hostWarns'\nimport { resolveMatcher } from '../../utils/matcher'\nimport { clamp } from '../../utils/number'\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useMessages, useResolvedLocale } from '../../i18n/state'\n\nexport type DatePickerSelection = 'single' | 'range' | 'multiple'\n\n/**\n * A period between two dates, the value of a `range` selection. Either bound may be\n * null: between the first and the second click, a range has a start and no end yet.\n */\nexport interface DatePickerRange {\n /** The first day of the period, as an ISO `YYYY-MM-DD` string. */\n start: string | null\n /** The last day of the period, as an ISO `YYYY-MM-DD` string. */\n end: string | null\n}\n\n/** Something happening on a given day, shown as a coloured dot under its number. */\nexport interface DatePickerEvent {\n /** The day it falls on, as an ISO `YYYY-MM-DD` string. */\n date: string\n /** The colour of the dot, as any CSS colour. It is the accent colour by default. */\n color?: string\n /** A description of the event for assistive technology. */\n label?: string\n}\n\n/**\n * Which dates cannot be selected, given either as a list of ISO strings or as a\n * function answering that question for a date.\n */\nexport type DatePickerMatcher = string[] | ((iso: string) => boolean)\n\n/** The shape of the v-model, which follows whichever `selection` is in use. */\nexport type DatePickerValue = string | null | DatePickerRange | string[]\n\n/** Everything the `#day` slot is told about the day it draws. */\nexport interface DatePickerDaySlotProps {\n /** The day, as an ISO `YYYY-MM-DD` string. */\n iso: string\n /** The day of the month. */\n day: number\n /** Whether it belongs to the month on display rather than to a neighbouring one. */\n inMonth: boolean\n /** Whether it cannot be chosen: outside the bounds, or excluded by `disabledDates`. */\n disabled: boolean\n /** Whether it is selected. */\n selected: boolean\n /** Whether it is today. */\n today: boolean\n /** Whether it falls inside the selected period, both ends included. */\n inRange: boolean\n /** The events that fall on it. */\n events: DatePickerEvent[]\n}\n\ninterface DatePickerProps {\n /**\n * What the reader is picking: a single date, a period between two dates, or any\n * number of separate dates. It determines the shape of the v-model.\n */\n selection?: DatePickerSelection\n /**\n * A BCP 47 locale, which decides the month and day names and the first day of the\n * week. It TAKES PRECEDENCE over the design system's global locale (`setLocale`)\n * and falls back to it — which is why it has no literal default here: `undefined`\n * has to stay recognizable for the global locale to have its chance.\n */\n locale?: string\n /**\n * Forces the day the weeks start on (0 for Sunday through 6 for Saturday). Left\n * out, the locale decides.\n */\n firstDayOfWeek?: number\n /**\n * The earliest selectable date, as an ISO string. Neither navigation nor selection\n * goes back beyond it.\n */\n min?: string\n /**\n * The latest selectable date, as an ISO string. Neither navigation nor selection\n * goes past it.\n */\n max?: string\n /**\n * Dates that cannot be chosen, given as a list of ISO strings or as a function.\n * They stay visible, struck through, and can still be reached with the keyboard.\n */\n disabledDates?: DatePickerMatcher\n /**\n * Also fills the empty corners of the grid with the greyed days of the neighbouring\n * months. It is off by default.\n */\n showAdjacentDays?: boolean\n /**\n * Lets those neighbouring days be clicked, which moves the calendar to their month.\n * A clickable day has to be visible, so this implies showing them.\n */\n selectAdjacentDays?: boolean\n /** The events to mark, as up to three coloured dots under the day they fall on. */\n events?: DatePickerEvent[]\n /**\n * Makes the whole calendar unusable: no date can be chosen, no month reached, and\n * everything greys out through the colour tokens.\n */\n disabled?: boolean\n /**\n * Shows what is selected without letting it be changed. The calendar can still be\n * read and walked through — another month, another year — which is what separates it\n * from `disabled`.\n */\n readonly?: boolean\n /**\n * The accessible name of the whole picker, its header and its grid together. A range\n * shown as two calendars side by side needs one each, or a screen reader announces the\n * same group twice. It falls back to the dictionary, and a consumer `aria-label` wins.\n */\n label?: string\n}\n\nconst props = withDefaults(defineProps<DatePickerProps>(), {\n selection: 'single',\n locale: undefined,\n firstDayOfWeek: undefined,\n min: undefined,\n max: undefined,\n disabledDates: undefined,\n showAdjacentDays: false,\n selectAdjacentDays: false,\n events: undefined,\n disabled: false,\n readonly: false,\n label: undefined,\n})\n\n/**\n * What is selected, and its SHAPE follows `selection`: an ISO `YYYY-MM-DD` string for\n * `single`, a `{ start, end }` pair for `range`, an array of strings for `multiple`. Nothing\n * is selected to begin with.\n *\n * Every date is a plain local-time string, never a `Date`, so the value a consumer receives\n * cannot shift a day across time zones.\n */\nconst model = defineModel<DatePickerValue>({ default: null })\n\nconst emit = defineEmits<{\n /**\n * Emitted every time a date is chosen, carrying the complete value as it now\n * stands. VDateInput listens to it to close its panel on a single selection.\n */\n select: [value: DatePickerValue]\n}>()\n\ndefineSlots<{\n /**\n * Replaces the content of a day cell — to show a price or an availability under the\n * number, for instance. It receives everything known about that day, including\n * whether it belongs to the displayed month.\n */\n day?(props: DatePickerDaySlotProps): unknown\n /** The strip under the grid, for actions such as Close or Save, or for preset dates. */\n footer?(): unknown\n}>()\n\nconst gridLabelId = useId()\n\n// The navigation labels have no prop of their own: the dictionary is the single\n// place to change them, globally or per language — see `src/i18n/`.\nconst m = useMessages()\n// @a11y — a roleless box cannot carry an accessible name (axe: aria-prohibited-attr),\n// so the root is a named group: the VCarousel viewport arrangement.\nconst ariaLabel = useAriaLabel(() => props.label ?? m.value.datePicker.label)\nconst resolvedLocale = useResolvedLocale(() => props.locale)\n\n// @devwarn\n// Silent inside a host that forwards these props and reports on them itself (utils/hostWarns).\nif (isDev && !inject(hostWarnsKey, false)) {\n watchEffect(() => {\n if (props.min && props.max && compareISO(props.min, props.max) > 0)\n console.warn(\n `[VDatePicker] min \"${props.min}\" falls after max \"${props.max}\", so no date can be chosen.`,\n )\n })\n}\n\nconst resolvedFirstDay = computed(\n () => props.firstDayOfWeek ?? firstDayOfWeekFor(resolvedLocale.value),\n)\nconst weekdays = computed(() => weekdayNames(resolvedLocale.value, resolvedFirstDay.value, 'short'))\nconst weekdaysLong = computed(() =>\n weekdayNames(resolvedLocale.value, resolvedFirstDay.value, 'long'),\n)\nconst monthLabels = computed(() => monthNamesCompact(resolvedLocale.value))\n\nconst singleValue = computed(() =>\n props.selection === 'single' && typeof model.value === 'string' && isValidISO(model.value)\n ? model.value\n : null,\n)\nconst rangeValue = computed<DatePickerRange>(() => {\n if (\n props.selection === 'range' &&\n model.value &&\n typeof model.value === 'object' &&\n !Array.isArray(model.value)\n ) {\n return model.value as DatePickerRange\n }\n return { start: null, end: null }\n})\nconst multipleValues = computed<string[]>(() =>\n props.selection === 'multiple' && Array.isArray(model.value) ? model.value : [],\n)\n\n// `focusedISO` is the single source of truth for the view: the month on display is\n// derived from it, never stored separately, so the two cannot drift apart.\n//\n// TRAP — a range start or a list entry is validated HERE, the way the single value is\n// validated upstream. Those two reach this component exactly as the consumer wrote them,\n// and a malformed one (`{ start: 'foo' }`) made the focused date unparseable: the month\n// arrows assert that parse, so the first render threw.\nfunction initialFocus(): string {\n if (singleValue.value) return singleValue.value\n const start = rangeValue.value.start\n if (start && isValidISO(start)) return start\n const listed = multipleValues.value.find(isValidISO)\n if (listed) return listed\n // With nothing selected, the calendar opens on today, brought back inside the\n // allowed bounds.\n return clampISO(formatISO(new Date()), props.min, props.max)\n}\nconst focusedISO = ref(initialFocus())\nconst view = ref<'days' | 'months' | 'years'>('days')\n\nconst viewYear = computed(\n () => parseISO(focusedISO.value)?.getFullYear() ?? new Date().getFullYear(),\n)\nconst viewMonth0 = computed(() => parseISO(focusedISO.value)?.getMonth() ?? 0)\nconst monthLabel = computed(() => monthName(resolvedLocale.value, viewMonth0.value))\nconst gridLabel = computed(() => `${monthLabel.value} ${viewYear.value}`)\n\n// @ssr\n// Today's date is only read once the component is mounted, hence on the client: the\n// server has no way to know it, and rendering it during setup would make the two\n// markups differ and break hydration.\nconst today = ref<string | null>(null)\nonMounted(() => {\n today.value = formatISO(new Date())\n})\n\nconst isDisabledDate = computed(() => resolveMatcher(props.disabledDates))\n\nconst eventsByDate = computed(() => {\n const map = new Map<string, DatePickerEvent[]>()\n for (const ev of props.events ?? []) {\n const list = map.get(ev.date) ?? []\n list.push(ev)\n map.set(ev.date, list)\n }\n return map\n})\n\nconst hoverISO = ref<string | null>(null)\nfunction orderRange(a: string, b: string): DatePickerRange {\n return compareISO(a, b) <= 0 ? { start: a, end: b } : { start: b, end: a }\n}\nconst effectiveRange = computed<DatePickerRange>(() => {\n if (props.selection !== 'range') return { start: null, end: null }\n const r = rangeValue.value\n if (r.start && r.end) return orderRange(r.start, r.end)\n // A start is set but the end is still pending: the range is previewed up to\n // whichever day the pointer or the focus is currently on.\n const preview = hoverISO.value ?? focusedISO.value\n if (r.start && preview) return orderRange(r.start, preview)\n return { start: r.start, end: r.end }\n})\n\nfunction isSelected(iso: string): boolean {\n if (props.selection === 'single') return isSameISO(iso, singleValue.value)\n if (props.selection === 'multiple') return multipleValues.value.includes(iso)\n // In range selection, the two ends of the period count as selected — including the\n // provisional end shown during the preview.\n return isSameISO(iso, effectiveRange.value.start) || isSameISO(iso, effectiveRange.value.end)\n}\n/**\n * Whether a day falls inside the selected period, BOTH ends included.\n *\n * The inclusiveness is a contract with the stylesheet, not a detail: `[data-in-range]` is\n * what draws the band's pseudo-element, and the two end rules only round a corner of one\n * that already exists. Narrowing this to the days strictly between would leave each end\n * with nothing to cap and silently square off every range.\n */\nfunction isInRange(iso: string): boolean {\n const { start, end } = effectiveRange.value\n return !!start && !!end && compareISO(iso, start) >= 0 && compareISO(iso, end) <= 0\n}\n\ntype DayCell = {\n iso: string\n day: number\n kind: 'empty' | 'static' | 'button'\n inMonth: boolean\n disabled: boolean\n selected: boolean\n rangeStart: boolean\n rangeEnd: boolean\n inRange: boolean\n today: boolean\n events: DatePickerEvent[]\n /** The events drawn as dots under the number, three at most. */\n dots: DatePickerEvent[]\n}\n\n/**\n * The 42 squares of the month on display, rebuilt only when the MONTH changes. The two\n * computeds are split on purpose: a range being previewed changes `hoverISO` on every\n * `pointerenter`, and that has to repaint the decoration below without building 42 dates\n * again. `viewYear` and `viewMonth0` are numbers, so moving the focus inside the month\n * leaves them — and this — untouched.\n */\nconst grid = computed(() =>\n buildMonthGrid(viewYear.value, viewMonth0.value, resolvedFirstDay.value),\n)\n\nconst NO_EVENTS: DatePickerEvent[] = []\n\nconst days = computed<DayCell[]>(() =>\n grid.value.map((cell) => {\n const inMonth = cell.adjacent === null\n // Making the neighbouring days clickable implies showing them: a day nobody can\n // see cannot be clicked.\n const show = inMonth || props.showAdjacentDays || props.selectAdjacentDays\n const selectable = inMonth || props.selectAdjacentDays\n const disabled = !isDateAllowed(cell.iso, props.min, props.max, isDisabledDate.value)\n const kind: DayCell['kind'] = !show ? 'empty' : selectable ? 'button' : 'static'\n const events = eventsByDate.value.get(cell.iso) ?? NO_EVENTS\n return {\n iso: cell.iso,\n day: cell.day,\n kind,\n inMonth,\n disabled,\n selected: kind === 'button' && !disabled && isSelected(cell.iso),\n rangeStart: props.selection === 'range' && isSameISO(cell.iso, effectiveRange.value.start),\n rangeEnd: props.selection === 'range' && isSameISO(cell.iso, effectiveRange.value.end),\n inRange: props.selection === 'range' && isInRange(cell.iso),\n today: isSameISO(cell.iso, today.value),\n events,\n dots: events.length > 3 ? events.slice(0, 3) : events,\n }\n }),\n)\n\n/** What the `#day` slot receives for a square: the same object for both kinds of cell. */\nfunction daySlotProps(cell: DayCell): DatePickerDaySlotProps {\n return {\n iso: cell.iso,\n day: cell.day,\n inMonth: cell.inMonth,\n disabled: cell.disabled,\n selected: cell.selected,\n today: cell.today,\n inRange: cell.inRange,\n events: cell.events,\n }\n}\nconst weeks = computed(() => {\n const rows: DayCell[][] = []\n for (let i = 0; i < days.value.length; i += 7) rows.push(days.value.slice(i, i + 7))\n return rows\n})\n\nfunction monthHasSelectable(year: number, month0: number): boolean {\n const first = isoOf(year, month0, 1)\n const last = isoOf(year, month0, daysInMonth(year, month0))\n return (\n (!props.max || compareISO(first, props.max) <= 0) &&\n (!props.min || compareISO(last, props.min) >= 0)\n )\n}\n// Derived from the month on display, not from the focused day, so an arrow key moving the\n// focus inside the month does not recompute them.\nconst canPrevMonth = computed(() =>\n viewMonth0.value === 0\n ? monthHasSelectable(viewYear.value - 1, 11)\n : monthHasSelectable(viewYear.value, viewMonth0.value - 1),\n)\nconst canNextMonth = computed(() =>\n viewMonth0.value === 11\n ? monthHasSelectable(viewYear.value + 1, 0)\n : monthHasSelectable(viewYear.value, viewMonth0.value + 1),\n)\nconst canPrevYear = computed(\n () => !props.min || compareISO(isoOf(viewYear.value - 1, 11, 31), props.min) >= 0,\n)\nconst canNextYear = computed(\n () => !props.max || compareISO(isoOf(viewYear.value + 1, 0, 1), props.max) <= 0,\n)\n\n// @a11y\n// Moves the real DOM focus onto a day cell. The grid keeps exactly one cell in the\n// tab order, so navigating means focusing another one.\nconst dayId = (iso: string) => `${gridLabelId}-d-${iso}`\nfunction focusDay(iso: string, options?: FocusOptions) {\n nextTick(() => document.getElementById(dayId(iso))?.focus(options))\n}\n\nfunction goTo(iso: string, moveFocus = false) {\n // Every move through the calendar comes here, so one guard covers the arrows, the\n // month and year cells and the keyboard's own steps. Only `disabled` stops it:\n // `readonly` leaves the reader free to look around.\n if (props.disabled) return\n focusedISO.value = clampISO(iso, props.min, props.max)\n if (moveFocus && view.value === 'days') focusDay(focusedISO.value)\n}\nfunction stepMonth(delta: number) {\n goTo(addMonths(focusedISO.value, delta))\n}\nfunction stepYear(delta: number) {\n goTo(addMonths(focusedISO.value, delta * 12))\n}\n\n// @a11y @core — changing view has to carry the focus onto the cell the new view\n// opens on. Without that move the focus would stay on a button the view has just\n// removed from the document, and the keyboard would have nowhere to go.\nfunction toggleView(target: 'months' | 'years') {\n const next = view.value === target ? 'days' : target\n view.value = next\n if (next === 'months') {\n focusedMonth.value = viewMonth0.value\n nextTick(() => monthCellEl(viewMonth0.value)?.focus())\n } else if (next === 'years') {\n focusedYear.value = viewYear.value\n nextTick(() => {\n const cell = yearCellEl(viewYear.value)\n // Called optionally because jsdom does not implement scrollIntoView (the same\n // guard as VTimeInput's list). Centring the year is a nicety; the focus call\n // below is not, so it must not be taken down with it.\n cell?.scrollIntoView?.({ block: 'center' })\n cell?.focus()\n })\n } else if (view.value === 'days') {\n focusDay(focusedISO.value)\n }\n}\n\nfunction selectDay(cell: DayCell) {\n // The single choke point of the selection, so the two states are refused here rather\n // than in each of the routes that lead to it — a click, Enter and Space all pass\n // through. Navigation is deliberately NOT guarded by `readonly`: a calendar one may\n // read is a calendar one may leaf through.\n if (props.disabled || props.readonly) return\n if (cell.kind !== 'button' || cell.disabled) return\n focusedISO.value = cell.iso\n let next: DatePickerValue\n if (props.selection === 'single') {\n next = cell.iso\n } else if (props.selection === 'multiple') {\n next = toggleValue(multipleValues.value, cell.iso).sort(compareISO)\n } else {\n // Range selection reads three clicks: the first sets the start, the second the\n // end (reordered if it comes before the start), and the third starts a new\n // period.\n const r = rangeValue.value\n next = !r.start || r.end ? { start: cell.iso, end: null } : orderRange(r.start, cell.iso)\n }\n model.value = next\n // TRAP: emit what was just computed, never `model.value` read back. Under a parent\n // `v-model`, `defineModel` does not update its local copy on write — it waits for the\n // parent to re-render — so the read would hand `select` the PREVIOUS value.\n emit('select', next)\n}\n\n// @keyboard @a11y\n// The keyboard of the days view. The table turning a key into a step is pure and\n// lives in `./keyboard`; what stays here is the date that step is applied to, and\n// the focus move that follows.\nfunction onDaysKeydown(event: KeyboardEvent) {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n const cell = days.value.find((c) => c.iso === focusedISO.value)\n if (cell) selectDay(cell)\n return\n }\n const d = parseISO(focusedISO.value)!\n // How far the focused day sits from the start of its week, which is exactly what\n // Home and End have to step back and forward by.\n const offset = (d.getDay() - resolvedFirstDay.value + 7) % 7\n const step = dayStep(event.key, event.shiftKey, offset)\n if (!step) return\n event.preventDefault()\n goTo(\n 'days' in step\n ? addDays(focusedISO.value, step.days)\n : addMonths(focusedISO.value, step.months),\n true,\n )\n}\n\n/**\n * Leaving the months or the years view for the days of the month chosen, keeping the day of\n * the month where the new month has one — the 31st becoming the 30th, say.\n */\nfunction chooseYearMonth(year: number, month0: number) {\n const day = Math.min(parseISO(focusedISO.value)!.getDate(), daysInMonth(year, month0))\n goTo(isoOf(year, month0, day))\n view.value = 'days'\n focusDay(focusedISO.value)\n}\n\n// @keyboard @a11y\n/**\n * The keyboard of the months and the years views, which differ only in what their cells\n * hold: Enter or Space chooses the focused cell, and the arrows walk the list of cells a row\n * or a column at a time, stopping at either end.\n */\nfunction onViewKeydown(\n event: KeyboardEvent,\n cells: readonly number[],\n focused: Ref<number>,\n cellEl: (value: number) => HTMLElement | null,\n choose: (value: number) => void,\n) {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n choose(focused.value)\n return\n }\n const delta = gridDelta(event.key)\n if (delta === undefined) return\n event.preventDefault()\n const next = clamp(cells.indexOf(focused.value) + delta, 0, cells.length - 1)\n focused.value = cells[next] ?? focused.value\n cellEl(focused.value)?.focus()\n}\n\n// The months view, opened from the month button in the header.\nconst MONTHS = Array.from({ length: 12 }, (_, i) => i)\nconst focusedMonth = ref(viewMonth0.value)\nconst monthCellEl = (i: number) =>\n document.getElementById(`${gridLabelId}-m-${i}`) as HTMLElement | null\nfunction monthSelectable(i: number) {\n return monthHasSelectable(viewYear.value, i)\n}\nfunction chooseMonth(i: number) {\n if (monthSelectable(i)) chooseYearMonth(viewYear.value, i)\n}\nconst onMonthsKeydown = (event: KeyboardEvent) =>\n onViewKeydown(event, MONTHS, focusedMonth, monthCellEl, chooseMonth)\n\n// @a11y\n/*\n * Both pickers are a `role=\"grid\"`, and a grid owns ROWS, not cells: a gridcell\n * placed straight under the grid fails aria-required-children and\n * aria-required-parent at the same time. The cells are therefore cut into rows of\n * PICKER_COLUMNS, matching the `grid-template-columns` of the stylesheet — the row\n * element itself is `display: contents`, so the CSS grid never sees it.\n *\n * Keyboard navigation is unaffected by this extra level: it moves by index and\n * refocuses cells through their ids, never by walking the DOM.\n */\nconst chunk = <T,>(list: T[]) =>\n Array.from({ length: Math.ceil(list.length / PICKER_COLUMNS) }, (_, r) =>\n list.slice(r * PICKER_COLUMNS, r * PICKER_COLUMNS + PICKER_COLUMNS),\n )\n\nconst monthRows = computed(() => chunk(monthLabels.value.map((name, i) => ({ name, i }))))\n\n// The years view, opened from the year button in the header.\nconst yearRange = computed(() => {\n /*\n * `min` and `max` come straight from the consumer, and this is the ONLY place\n * where they are turned into a Date instead of being compared as ISO text —\n * `compareISO`, `isWithin` and `clampISO` all tolerate a malformed bound. A value\n * that is not a valid ISO date therefore has to fall back to the open range here:\n * asserting the parse would throw and take the whole render down the moment the\n * years view is opened.\n */\n const minY = parseISO(props.min)?.getFullYear() ?? viewYear.value - 100\n const maxY = parseISO(props.max)?.getFullYear() ?? viewYear.value + 100\n const list: number[] = []\n for (let y = minY; y <= maxY; y++) list.push(y)\n return list\n})\nconst yearRows = computed(() => chunk(yearRange.value))\nconst focusedYear = ref(viewYear.value)\nconst yearCellEl = (y: number) =>\n document.getElementById(`${gridLabelId}-y-${y}`) as HTMLElement | null\nconst chooseYear = (y: number) => chooseYearMonth(y, viewMonth0.value)\nconst onYearsKeydown = (event: KeyboardEvent) =>\n onViewKeydown(event, yearRange.value, focusedYear, yearCellEl, chooseYear)\n\n// Follows a selection changed from the outside: when the leading value lands in\n// another month, the calendar moves to it rather than leaving the reader in front of\n// a grid where nothing is selected.\nwatch(\n () => [singleValue.value, rangeValue.value.start, multipleValues.value[0]],\n () => {\n const primary = singleValue.value ?? rangeValue.value.start ?? multipleValues.value[0]\n if (primary && isValidISO(primary)) {\n const d = parseISO(primary)!\n if (d.getFullYear() !== viewYear.value || d.getMonth() !== viewMonth0.value) {\n focusedISO.value = primary\n }\n }\n },\n)\n\n// @a11y\n/**\n * Brings the focus into the grid, on the day the calendar is currently showing. This\n * is what VDateInput calls when it opens its panel.\n */\nfunction focus(options?: FocusOptions) {\n view.value = 'days'\n focusDay(focusedISO.value, options)\n}\n\n// @core\n/*\n * Puts the calendar back the way it opens: the days view, on the selected date (today\n * failing that), with no range preview pending. It moves no focus and announces nothing,\n * a panel reopening not being something the reader did.\n *\n * TRAP — a panel's content stays MOUNTED while the panel is closed, so without this the\n * months or years view a reader left open is what the next opening shows — and a field\n * that opens its panel on focus never calls `focus()`, the one place that reset the view.\n */\nfunction reset() {\n view.value = 'days'\n hoverISO.value = null\n focusedISO.value = initialFocus()\n}\n\ndefineExpose({\n /** Brings the focus into the grid, onto the day the calendar is showing. */\n focus,\n /**\n * Returns to the days view, on the selected date or today, without moving the focus.\n * VDateInput calls it each time its panel opens and closes.\n */\n reset,\n})\n</script>\n\n<template>\n <div\n class=\"v-date-picker\"\n role=\"group\"\n :aria-label=\"ariaLabel\"\n :data-view=\"view\"\n :data-selection=\"selection\"\n :data-disabled=\"disabled ? '' : undefined\"\n :data-readonly=\"readonly ? '' : undefined\"\n @pointerleave=\"hoverISO = null\"\n >\n <!-- The header: the month and the year, each between two chevrons that step it,\n and each opening its own picker view when clicked -->\n <div class=\"v-date-picker-header\">\n <div class=\"v-date-picker-nav\">\n <VIconButton\n :label=\"m.datePicker.previousMonth\"\n size=\"sm\"\n :disabled=\"disabled || !canPrevMonth\"\n @click=\"stepMonth(-1)\"\n >\n <VIcon :name=\"chevronLeftIcon\" mirrored />\n </VIconButton>\n <VButton\n variant=\"ghost\"\n tone=\"neutral\"\n size=\"sm\"\n class=\"v-date-picker-view-toggle\"\n :disabled=\"disabled\"\n :aria-expanded=\"view === 'months'\"\n :aria-label=\"monthLabel\"\n @click=\"toggleView('months')\"\n >\n {{ monthLabels[viewMonth0] }}\n <VIcon\n :name=\"view === 'months' ? arrowDropUpIcon : arrowDropDownIcon\"\n aria-hidden=\"true\"\n />\n </VButton>\n <VIconButton\n :label=\"m.datePicker.nextMonth\"\n size=\"sm\"\n :disabled=\"disabled || !canNextMonth\"\n @click=\"stepMonth(1)\"\n >\n <VIcon :name=\"chevronRightIcon\" mirrored />\n </VIconButton>\n </div>\n\n <div class=\"v-date-picker-nav\">\n <VIconButton\n :label=\"m.datePicker.previousYear\"\n size=\"sm\"\n :disabled=\"disabled || !canPrevYear\"\n @click=\"stepYear(-1)\"\n >\n <VIcon :name=\"chevronLeftIcon\" mirrored />\n </VIconButton>\n <VButton\n variant=\"ghost\"\n tone=\"neutral\"\n size=\"sm\"\n class=\"v-date-picker-view-toggle\"\n :disabled=\"disabled\"\n :aria-expanded=\"view === 'years'\"\n @click=\"toggleView('years')\"\n >\n {{ viewYear }}\n <VIcon\n :name=\"view === 'years' ? arrowDropUpIcon : arrowDropDownIcon\"\n aria-hidden=\"true\"\n />\n </VButton>\n <VIconButton\n :label=\"m.datePicker.nextYear\"\n size=\"sm\"\n :disabled=\"disabled || !canNextYear\"\n @click=\"stepYear(1)\"\n >\n <VIcon :name=\"chevronRightIcon\" mirrored />\n </VIconButton>\n </div>\n </div>\n\n <!-- Days view -->\n <div\n v-show=\"view === 'days'\"\n class=\"v-date-picker-grid\"\n role=\"grid\"\n :aria-label=\"gridLabel\"\n :aria-multiselectable=\"selection === 'multiple' ? 'true' : undefined\"\n @keydown=\"onDaysKeydown\"\n >\n <div class=\"v-date-picker-weekdays\" role=\"row\">\n <span\n v-for=\"(w, i) in weekdays\"\n :key=\"w\"\n class=\"v-date-picker-weekday\"\n role=\"columnheader\"\n :aria-label=\"weekdaysLong[i]\"\n >{{ w }}</span\n >\n </div>\n <div v-for=\"(week, wi) in weeks\" :key=\"wi\" class=\"v-date-picker-week\" role=\"row\">\n <div\n v-for=\"cell in week\"\n :key=\"cell.iso\"\n class=\"v-date-picker-cell\"\n role=\"gridcell\"\n :aria-selected=\"cell.kind === 'button' ? cell.selected : undefined\"\n :data-in-range=\"cell.inRange ? '' : undefined\"\n :data-range-start=\"cell.rangeStart ? '' : undefined\"\n :data-range-end=\"cell.rangeEnd ? '' : undefined\"\n >\n <button\n v-if=\"cell.kind === 'button'\"\n :id=\"dayId(cell.iso)\"\n type=\"button\"\n class=\"v-date-picker-day\"\n :tabindex=\"cell.iso === focusedISO ? 0 : -1\"\n :data-outside=\"!cell.inMonth ? '' : undefined\"\n :data-selected=\"cell.selected ? '' : undefined\"\n :data-today=\"cell.today ? '' : undefined\"\n :data-unavailable=\"cell.disabled ? '' : undefined\"\n :disabled=\"disabled\"\n :aria-disabled=\"cell.disabled || readonly ? 'true' : undefined\"\n :aria-current=\"cell.today ? 'date' : undefined\"\n @click=\"selectDay(cell)\"\n @pointerenter=\"hoverISO = cell.iso\"\n @focus=\"hoverISO = cell.iso\"\n >\n <slot name=\"day\" v-bind=\"daySlotProps(cell)\">\n <span class=\"v-date-picker-day-num\">{{ cell.day }}</span>\n </slot>\n <span v-if=\"cell.dots.length\" class=\"v-date-picker-dots\" aria-hidden=\"true\">\n <span\n v-for=\"(ev, ei) in cell.dots\"\n :key=\"ei\"\n class=\"v-date-picker-dot\"\n :style=\"ev.color ? { '--date-picker-dot-color': ev.color } : undefined\"\n />\n </span>\n </button>\n <!-- A day of a neighbouring month that cannot be selected. It renders the\n very same slot as the clickable days: were it left with the bare\n number, custom content taking several lines would apply to this month's\n days only, and the numbers would stop lining up from one cell to the\n next. The slot receives `inMonth`, which is how it can still tell the\n two apart. -->\n <span\n v-else-if=\"cell.kind === 'static'\"\n class=\"v-date-picker-day v-date-picker-day--static\"\n :data-disabled=\"cell.disabled ? '' : undefined\"\n >\n <slot name=\"day\" v-bind=\"daySlotProps(cell)\">\n <span class=\"v-date-picker-day-num\">{{ cell.day }}</span>\n </slot>\n </span>\n </div>\n </div>\n </div>\n\n <!-- Months view -->\n <div\n v-if=\"view === 'months'\"\n class=\"v-date-picker-view\"\n role=\"grid\"\n :aria-label=\"m.datePicker.monthPicker\"\n @keydown=\"onMonthsKeydown\"\n >\n <div v-for=\"(row, r) in monthRows\" :key=\"r\" class=\"v-date-picker-view-row\" role=\"row\">\n <button\n v-for=\"{ name, i } in row\"\n :id=\"`${gridLabelId}-m-${i}`\"\n :key=\"name\"\n type=\"button\"\n class=\"v-date-picker-view-cell\"\n role=\"gridcell\"\n :tabindex=\"i === focusedMonth ? 0 : -1\"\n :data-selected=\"i === viewMonth0 ? '' : undefined\"\n :aria-selected=\"i === viewMonth0 ? 'true' : undefined\"\n :disabled=\"disabled || !monthSelectable(i)\"\n @click=\"chooseMonth(i)\"\n >\n {{ name }}\n </button>\n </div>\n </div>\n\n <!-- Years view -->\n <div\n v-if=\"view === 'years'\"\n class=\"v-date-picker-view v-date-picker-view--years\"\n role=\"grid\"\n :aria-label=\"m.datePicker.yearPicker\"\n @keydown=\"onYearsKeydown\"\n >\n <div v-for=\"(row, r) in yearRows\" :key=\"r\" class=\"v-date-picker-view-row\" role=\"row\">\n <button\n v-for=\"y in row\"\n :id=\"`${gridLabelId}-y-${y}`\"\n :key=\"y\"\n type=\"button\"\n class=\"v-date-picker-view-cell\"\n role=\"gridcell\"\n :tabindex=\"y === focusedYear ? 0 : -1\"\n :data-selected=\"y === viewYear ? '' : undefined\"\n :aria-selected=\"y === viewYear ? 'true' : undefined\"\n :disabled=\"disabled\"\n @click=\"chooseYear(y)\"\n >\n {{ y }}\n </button>\n </div>\n </div>\n\n <div v-if=\"$slots.footer\" class=\"v-date-picker-footer\">\n <slot name=\"footer\" />\n </div>\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n .v-date-picker {\n /* The consumer sets the size of the day disc through its token; the cell around it —\n the hover area and the width of the column — grows to follow, and never falls below\n the size the cell token sets. */\n --date-picker-cell: max(\n var(--vectis-control-size-date-picker-cell),\n calc(var(--vectis-control-size-date-picker-day) + var(--vectis-space-1))\n );\n display: inline-flex;\n flex-direction: column;\n gap: var(--vectis-space-2);\n padding: var(--vectis-space-3);\n font-family: var(--vectis-text-family);\n color: var(--vectis-color-text);\n }\n\n /* The calendar is a flex column, so every block stretches to its full width by\n default. The days grid then fills that width through its 1fr columns, and never\n goes below the seven cells its own floor guarantees. */\n .v-date-picker-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--vectis-space-2);\n }\n\n .v-date-picker-nav {\n display: flex;\n align-items: center;\n }\n\n /* A minimum width holds this button steady, so the chevrons on either side do not\n shift as the month or year label changes length. */\n .v-date-picker-view-toggle {\n min-inline-size: var(--vectis-control-size-date-picker-nav-min);\n /* The semibold is state emphasis on the grid's main landmark, not a type role. */\n font-weight: var(--vectis-font-weight-semibold);\n text-transform: capitalize;\n }\n\n /* The days grid can never be narrower than seven cells. Above that floor it takes\n whatever width the calendar has — set by the header — and the 1fr columns share\n it out equally. */\n .v-date-picker-grid {\n min-inline-size: calc(7 * var(--date-picker-cell));\n }\n\n .v-date-picker-weekdays,\n .v-date-picker-week {\n display: grid;\n grid-template-columns: repeat(7, 1fr);\n }\n\n .v-date-picker-weekday {\n display: flex;\n align-items: center;\n justify-content: center;\n height: var(--vectis-control-height-sm);\n /* A column micro-header, which takes the overline type role. The casing stays\n `capitalize`, the calendar convention, rather than the full capitals the\n VTypography overline variant would apply. */\n font-size: var(--vectis-text-overline-size);\n font-weight: var(--vectis-text-overline-weight);\n letter-spacing: var(--vectis-text-overline-tracking);\n color: var(--vectis-color-text-muted);\n text-transform: capitalize;\n }\n\n .v-date-picker-cell {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n height: var(--date-picker-cell);\n }\n\n /* The band joining the days of a selected range: a tinted background laid behind\n the day, at the HEIGHT of the disc rather than of the whole cell. Its vertical\n inset is half the gap between cell and disc, expressed in `%` so it follows the\n real width of a 1fr column whatever the calendar measures.\n\n At either end the band stops exactly at the edge of the disc — hence the inset on\n the outer side — and that corner is rounded with the pill radius, which a box\n this height caps at half its height, i.e. precisely the disc's own radius, so it\n cannot overshoot.\n\n TRAP — the two cap rules below only shape a pseudo-element that `[data-in-range]`\n has already created, so they depend on `isInRange` counting BOTH ends of the period\n as inside it. Make it exclusive and there is no `::before` to cap: both rounded ends\n of every range vanish, leaving a band that stops square one cell short at each side,\n with nothing in the console. The last rule is the single-day case, where the two caps\n would meet and draw a disc behind the disc. */\n .v-date-picker-cell[data-in-range]::before {\n content: '';\n position: absolute;\n inset-block: calc((100% - var(--vectis-control-size-date-picker-day)) / 2);\n inset-inline: 0;\n background: var(--vectis-color-accent-surface);\n z-index: 0;\n }\n .v-date-picker-cell[data-range-start]::before {\n inset-inline-start: calc((100% - var(--vectis-control-size-date-picker-day)) / 2);\n border-start-start-radius: var(--vectis-radius-pill);\n border-end-start-radius: var(--vectis-radius-pill);\n }\n .v-date-picker-cell[data-range-end]::before {\n inset-inline-end: calc((100% - var(--vectis-control-size-date-picker-day)) / 2);\n border-start-end-radius: var(--vectis-radius-pill);\n border-end-end-radius: var(--vectis-radius-pill);\n }\n .v-date-picker-cell[data-range-start][data-range-end]::before {\n content: none;\n }\n\n .v-date-picker-day {\n position: relative;\n z-index: 1;\n display: inline-flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n inline-size: var(--vectis-control-size-date-picker-day);\n block-size: var(--vectis-control-size-date-picker-day);\n padding: 0;\n border: none;\n border-radius: var(--vectis-radius-pill);\n background: transparent;\n color: inherit;\n font: inherit;\n font-size: var(--vectis-text-body-md-size);\n cursor: pointer;\n transition:\n background-color var(--vectis-duration-fast) var(--vectis-ease-default),\n color var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n\n /* Hover belongs to the days one can actually click: not the disabled ones, not the\n already selected ones, and not the neighbouring days rendered as plain spans. */\n .v-date-picker-day:hover:not([aria-disabled='true']):not([data-selected]):not(\n .v-date-picker-day--static\n ) {\n background: var(--vectis-color-surface-muted);\n }\n\n .v-date-picker-day[data-outside] {\n color: var(--vectis-color-text-subtle);\n }\n\n /* The semibold in the two rules below marks a state — today, and the selection —\n and is not a typographic role, which is why it reads a font token directly. */\n .v-date-picker-day[data-today]:not([data-selected]) {\n box-shadow: inset 0 0 0 1px var(--vectis-color-accent-border);\n color: var(--vectis-color-accent-text);\n font-weight: var(--vectis-font-weight-semibold);\n }\n\n .v-date-picker-day[data-selected] {\n background: var(--vectis-color-accent);\n color: var(--vectis-color-text-on-accent);\n font-weight: var(--vectis-font-weight-semibold);\n }\n\n /* The strike-through says the DATE is unavailable — outside the bounds, or listed in\n `disabledDates`. It hangs on its own attribute rather than on `aria-disabled`, which\n a read-only calendar also carries on every day: nothing can be chosen there, but the\n dates themselves are perfectly available and striking them all out would say the\n opposite. The hover rule below still reads `aria-disabled`, so neither highlights. */\n .v-date-picker-day[data-unavailable] {\n color: var(--vectis-color-text-subtle);\n text-decoration: line-through;\n cursor: not-allowed;\n }\n\n .v-date-picker[data-readonly] .v-date-picker-day:not([data-unavailable]) {\n cursor: default;\n }\n\n /* A disabled calendar greys out through the colour tokens and never through opacity,\n the selection included: left in the accent colour it would go on looking live. */\n .v-date-picker-day:disabled {\n color: var(--vectis-color-text-subtle);\n cursor: not-allowed;\n }\n\n .v-date-picker[data-disabled] .v-date-picker-day[data-selected] {\n background: var(--vectis-color-surface-muted);\n color: var(--vectis-color-text-subtle);\n }\n\n .v-date-picker-day--static {\n color: var(--vectis-color-text-subtle);\n cursor: default;\n }\n\n /* A neighbouring day that falls outside the bounds, or is disabled, is struck\n through like any other unavailable date. */\n .v-date-picker-day--static[data-disabled] {\n text-decoration: line-through;\n cursor: not-allowed;\n }\n\n .v-date-picker-day:focus-visible {\n outline: var(--vectis-focus-ring-width) solid var(--vectis-focus-ring-color);\n outline-offset: var(--vectis-focus-ring-offset);\n }\n\n .v-date-picker-day-num {\n line-height: var(--vectis-text-control-leading);\n }\n\n .v-date-picker-dots {\n position: absolute;\n inset-block-end: calc(var(--vectis-space-1) * 0.5);\n display: flex;\n gap: 2px;\n }\n .v-date-picker-dot {\n inline-size: var(--vectis-control-size-date-picker-dot);\n block-size: var(--vectis-control-size-date-picker-dot);\n border-radius: var(--vectis-radius-pill);\n background: var(--date-picker-dot-color, var(--vectis-color-accent));\n }\n .v-date-picker-day[data-selected] .v-date-picker-dot {\n background: var(--vectis-color-text-on-accent);\n }\n\n /* The months and years views. They fill the calendar's width exactly like the days\n grid does: stretched by the flex column, then shared out by 1fr columns. */\n .v-date-picker-view {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: var(--vectis-space-1);\n min-inline-size: calc(7 * var(--date-picker-cell));\n }\n /* The rows ARIA requires inside a grid, made invisible to the layout: with\n `display: contents` the cells remain direct grid items of `.v-date-picker-view`,\n so the columns line up as if the rows were not there. */\n .v-date-picker-view-row {\n display: contents;\n }\n\n .v-date-picker-view--years {\n max-block-size: calc(6 * var(--date-picker-cell));\n overflow-y: auto;\n }\n\n .v-date-picker-view-cell {\n display: flex;\n align-items: center;\n justify-content: center;\n block-size: var(--vectis-control-height-lg);\n border: none;\n border-radius: var(--vectis-radius-pill);\n background: transparent;\n color: inherit;\n font: inherit;\n font-size: var(--vectis-text-body-md-size);\n text-transform: capitalize;\n cursor: pointer;\n transition: background-color var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n .v-date-picker-view-cell:hover:not(:disabled):not([data-selected]) {\n background: var(--vectis-color-surface-muted);\n }\n .v-date-picker-view-cell[data-selected] {\n background: var(--vectis-color-accent);\n color: var(--vectis-color-text-on-accent);\n /* Again state emphasis, not a type role. */\n font-weight: var(--vectis-font-weight-semibold);\n }\n .v-date-picker-view-cell:disabled {\n color: var(--vectis-color-text-subtle);\n cursor: not-allowed;\n }\n .v-date-picker-view-cell:focus-visible {\n outline: var(--vectis-focus-ring-width) solid var(--vectis-focus-ring-color);\n outline-offset: calc(-1 * var(--vectis-focus-ring-width));\n }\n\n .v-date-picker-footer {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: var(--vectis-space-2);\n padding-block-start: var(--vectis-space-2);\n border-block-start: 1px solid var(--vectis-color-border);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-date-picker-day,\n .v-date-picker-view-cell {\n transition: none;\n }\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4KA,IAAM,IAAQ,GAuBR,IAAQ,GAA4B,GAAA,YAAkB,GAEtD,KAAO,GAmBP,IAAc,GAAM,GAIpB,IAAI,EAAY,GAGhB,KAAY,QAAmB,EAAM,SAAS,EAAE,MAAM,WAAW,KAAK,GACtE,IAAiB,QAAwB,EAAM,MAAM,GAarD,IAAmB,QACjB,EAAM,kBAAkB,GAAkB,EAAe,KAAK,CACtE,GACM,KAAW,QAAe,GAAa,EAAe,OAAO,EAAiB,OAAO,OAAO,CAAC,GAC7F,KAAe,QACnB,GAAa,EAAe,OAAO,EAAiB,OAAO,MAAM,CACnE,GACM,KAAc,QAAe,GAAkB,EAAe,KAAK,CAAC,GAEpE,IAAc,QAClB,EAAM,cAAc,YAAY,OAAO,EAAM,SAAU,YAAY,EAAW,EAAM,KAAK,IACrF,EAAM,QACN,IACN,GACM,IAAa,QAEf,EAAM,cAAc,WACpB,EAAM,SACN,OAAO,EAAM,SAAU,YACvB,CAAC,MAAM,QAAQ,EAAM,KAAK,IAEnB,EAAM,QAER;GAAE,OAAO;GAAM,KAAK;EAAK,CACjC,GACK,IAAiB,QACrB,EAAM,cAAc,cAAc,MAAM,QAAQ,EAAM,KAAK,IAAI,EAAM,QAAQ,CAAC,CAChF;EASA,SAAS,KAAuB;GAC9B,IAAI,EAAY,OAAO,OAAO,EAAY;GAC1C,IAAM,IAAQ,EAAW,MAAM;GAM/B,OALI,KAAS,EAAW,CAAK,IAAU,IACxB,EAAe,MAAM,KAAK,CACrC,KAGG,GAAS,mBAAU,IAAI,KAAK,CAAC,GAAG,EAAM,KAAK,EAAM,GAAG;EAC7D;EACA,IAAM,IAAa,EAAI,GAAa,CAAC,GAC/B,IAAO,EAAiC,MAAM,GAE9C,IAAW,QACT,EAAS,EAAW,KAAK,CAAC,EAAE,YAAY,sBAAK,IAAI,KAAK,EAAA,CAAE,YAAY,CAC5E,GACM,IAAa,QAAe,EAAS,EAAW,KAAK,CAAC,EAAE,SAAS,KAAK,CAAC,GACvE,KAAa,QAAe,GAAU,EAAe,OAAO,EAAW,KAAK,CAAC,GAC7E,KAAY,QAAe,GAAG,GAAW,MAAM,GAAG,EAAS,OAAO,GAMlE,IAAQ,EAAmB,IAAI;EACrC,SAAgB;GACd,EAAM,QAAQ,mBAAU,IAAI,KAAK,CAAC;EACpC,CAAC;EAED,IAAM,KAAiB,QAAe,GAAe,EAAM,aAAa,CAAC,GAEnE,KAAe,QAAe;GAClC,IAAM,oBAAM,IAAI,IAA+B;GAC/C,KAAK,IAAM,KAAM,EAAM,UAAU,CAAC,GAAG;IACnC,IAAM,IAAO,EAAI,IAAI,EAAG,IAAI,KAAK,CAAC;IAElC,AADA,EAAK,KAAK,CAAE,GACZ,EAAI,IAAI,EAAG,MAAM,CAAI;GACvB;GACA,OAAO;EACT,CAAC,GAEK,IAAW,EAAmB,IAAI;EACxC,SAAS,EAAW,GAAW,GAA4B;GACzD,OAAO,EAAW,GAAG,CAAC,KAAK,IAAI;IAAE,OAAO;IAAG,KAAK;GAAE,IAAI;IAAE,OAAO;IAAG,KAAK;GAAE;EAC3E;EACA,IAAM,IAAiB,QAAgC;GACrD,IAAI,EAAM,cAAc,SAAS,OAAO;IAAE,OAAO;IAAM,KAAK;GAAK;GACjE,IAAM,IAAI,EAAW;GACrB,IAAI,EAAE,SAAS,EAAE,KAAK,OAAO,EAAW,EAAE,OAAO,EAAE,GAAG;GAGtD,IAAM,IAAU,EAAS,SAAS,EAAW;GAE7C,OADI,EAAE,SAAS,IAAgB,EAAW,EAAE,OAAO,CAAO,IACnD;IAAE,OAAO,EAAE;IAAO,KAAK,EAAE;GAAI;EACtC,CAAC;EAED,SAAS,GAAW,GAAsB;GAKxC,OAJI,EAAM,cAAc,WAAiB,EAAU,GAAK,EAAY,KAAK,IACrE,EAAM,cAAc,aAAmB,EAAe,MAAM,SAAS,CAAG,IAGrE,EAAU,GAAK,EAAe,MAAM,KAAK,KAAK,EAAU,GAAK,EAAe,MAAM,GAAG;EAC9F;EASA,SAAS,GAAU,GAAsB;GACvC,IAAM,EAAE,UAAO,WAAQ,EAAe;GACtC,OAAO,CAAC,CAAC,KAAS,CAAC,CAAC,KAAO,EAAW,GAAK,CAAK,KAAK,KAAK,EAAW,GAAK,CAAG,KAAK;EACpF;EAyBA,IAAM,KAAO,QACX,GAAe,EAAS,OAAO,EAAW,OAAO,EAAiB,KAAK,CACzE,GAEM,KAA+B,CAAC,GAEhC,IAAO,QACX,GAAK,MAAM,KAAK,MAAS;GACvB,IAAM,IAAU,EAAK,aAAa,MAG5B,IAAO,KAAW,EAAM,oBAAoB,EAAM,oBAClD,IAAa,KAAW,EAAM,oBAC9B,IAAW,CAAC,GAAc,EAAK,KAAK,EAAM,KAAK,EAAM,KAAK,GAAe,KAAK,GAC9E,IAAyB,IAAiB,IAAa,WAAW,WAAlC,SAChC,IAAS,GAAa,MAAM,IAAI,EAAK,GAAG,KAAK;GACnD,OAAO;IACL,KAAK,EAAK;IACV,KAAK,EAAK;IACV;IACA;IACA;IACA,UAAU,MAAS,YAAY,CAAC,KAAY,GAAW,EAAK,GAAG;IAC/D,YAAY,EAAM,cAAc,WAAW,EAAU,EAAK,KAAK,EAAe,MAAM,KAAK;IACzF,UAAU,EAAM,cAAc,WAAW,EAAU,EAAK,KAAK,EAAe,MAAM,GAAG;IACrF,SAAS,EAAM,cAAc,WAAW,GAAU,EAAK,GAAG;IAC1D,OAAO,EAAU,EAAK,KAAK,EAAM,KAAK;IACtC;IACA,MAAM,EAAO,SAAS,IAAI,EAAO,MAAM,GAAG,CAAC,IAAI;GACjD;EACF,CAAC,CACH;EAGA,SAAS,GAAa,GAAuC;GAC3D,OAAO;IACL,KAAK,EAAK;IACV,KAAK,EAAK;IACV,SAAS,EAAK;IACd,UAAU,EAAK;IACf,UAAU,EAAK;IACf,OAAO,EAAK;IACZ,SAAS,EAAK;IACd,QAAQ,EAAK;GACf;EACF;EACA,IAAM,KAAQ,QAAe;GAC3B,IAAM,IAAoB,CAAC;GAC3B,KAAK,IAAI,IAAI,GAAG,IAAI,EAAK,MAAM,QAAQ,KAAK,GAAG,EAAK,KAAK,EAAK,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC;GACnF,OAAO;EACT,CAAC;EAED,SAAS,EAAmB,GAAc,GAAyB;GACjE,IAAM,IAAQ,EAAM,GAAM,GAAQ,CAAC,GAC7B,IAAO,EAAM,GAAM,GAAQ,GAAY,GAAM,CAAM,CAAC;GAC1D,QACG,CAAC,EAAM,OAAO,EAAW,GAAO,EAAM,GAAG,KAAK,OAC9C,CAAC,EAAM,OAAO,EAAW,GAAM,EAAM,GAAG,KAAK;EAElD;EAGA,IAAM,KAAe,QACnB,EAAW,UAAU,IACjB,EAAmB,EAAS,QAAQ,GAAG,EAAE,IACzC,EAAmB,EAAS,OAAO,EAAW,QAAQ,CAAC,CAC7D,GACM,KAAe,QACnB,EAAW,UAAU,KACjB,EAAmB,EAAS,QAAQ,GAAG,CAAC,IACxC,EAAmB,EAAS,OAAO,EAAW,QAAQ,CAAC,CAC7D,GACM,KAAc,QACZ,CAAC,EAAM,OAAO,EAAW,EAAM,EAAS,QAAQ,GAAG,IAAI,EAAE,GAAG,EAAM,GAAG,KAAK,CAClF,GACM,KAAc,QACZ,CAAC,EAAM,OAAO,EAAW,EAAM,EAAS,QAAQ,GAAG,GAAG,CAAC,GAAG,EAAM,GAAG,KAAK,CAChF,GAKM,MAAS,MAAgB,GAAG,EAAY,KAAK;EACnD,SAAS,EAAS,GAAa,GAAwB;GACrD,QAAe,SAAS,eAAe,GAAM,CAAG,CAAC,CAAC,EAAE,MAAM,CAAO,CAAC;EACpE;EAEA,SAAS,EAAK,GAAa,IAAY,IAAO;GAIxC,EAAM,aACV,EAAW,QAAQ,GAAS,GAAK,EAAM,KAAK,EAAM,GAAG,GACjD,KAAa,EAAK,UAAU,UAAQ,EAAS,EAAW,KAAK;EACnE;EACA,SAAS,GAAU,GAAe;GAChC,EAAK,EAAU,EAAW,OAAO,CAAK,CAAC;EACzC;EACA,SAAS,GAAS,GAAe;GAC/B,EAAK,EAAU,EAAW,OAAO,IAAQ,EAAE,CAAC;EAC9C;EAKA,SAAS,GAAW,GAA4B;GAC9C,IAAM,IAAO,EAAK,UAAU,IAAS,SAAS;GAE9C,AADA,EAAK,QAAQ,GACT,MAAS,YACX,EAAa,QAAQ,EAAW,OAChC,QAAe,GAAY,EAAW,KAAK,CAAC,EAAE,MAAM,CAAC,KAC5C,MAAS,WAClB,EAAY,QAAQ,EAAS,OAC7B,QAAe;IACb,IAAM,IAAO,GAAW,EAAS,KAAK;IAKtC,AADA,GAAM,iBAAiB,EAAE,OAAO,SAAS,CAAC,GAC1C,GAAM,MAAM;GACd,CAAC,KACQ,EAAK,UAAU,UACxB,EAAS,EAAW,KAAK;EAE7B;EAEA,SAAS,GAAU,GAAe;GAMhC,IADI,EAAM,YAAY,EAAM,YACxB,EAAK,SAAS,YAAY,EAAK,UAAU;GAC7C,EAAW,QAAQ,EAAK;GACxB,IAAI;GACJ,IAAI,EAAM,cAAc,UACtB,IAAO,EAAK;QACP,IAAI,EAAM,cAAc,YAC7B,IAAO,GAAY,EAAe,OAAO,EAAK,GAAG,CAAC,CAAC,KAAK,CAAU;QAC7D;IAIL,IAAM,IAAI,EAAW;IACrB,IAAO,CAAC,EAAE,SAAS,EAAE,MAAM;KAAE,OAAO,EAAK;KAAK,KAAK;IAAK,IAAI,EAAW,EAAE,OAAO,EAAK,GAAG;GAC1F;GAKA,AAJA,EAAM,QAAQ,GAId,GAAK,UAAU,CAAI;EACrB;EAMA,SAAS,GAAc,GAAsB;GAC3C,IAAI,EAAM,QAAQ,WAAW,EAAM,QAAQ,KAAK;IAC9C,EAAM,eAAe;IACrB,IAAM,IAAO,EAAK,MAAM,MAAM,MAAM,EAAE,QAAQ,EAAW,KAAK;IAC9D,AAAI,KAAM,GAAU,CAAI;IACxB;GACF;GAIA,IAAM,KAHI,EAAS,EAAW,KAGd,CAAA,CAAE,OAAO,IAAI,EAAiB,QAAQ,KAAK,GACrD,IAAO,GAAQ,EAAM,KAAK,EAAM,UAAU,CAAM;GACjD,MACL,EAAM,eAAe,GACrB,EACE,UAAU,IACN,GAAQ,EAAW,OAAO,EAAK,IAAI,IACnC,EAAU,EAAW,OAAO,EAAK,MAAM,GAC3C,EACF;EACF;EAMA,SAAS,GAAgB,GAAc,GAAgB;GAIrD,AAFA,EAAK,EAAM,GAAM,GADL,KAAK,IAAI,EAAS,EAAW,KAAK,CAAC,CAAE,QAAQ,GAAG,GAAY,GAAM,CAAM,CAC3D,CAAG,CAAC,GAC7B,EAAK,QAAQ,QACb,EAAS,EAAW,KAAK;EAC3B;EAQA,SAAS,GACP,GACA,GACA,GACA,GACA,GACA;GACA,IAAI,EAAM,QAAQ,WAAW,EAAM,QAAQ,KAAK;IAE9C,AADA,EAAM,eAAe,GACrB,EAAO,EAAQ,KAAK;IACpB;GACF;GACA,IAAM,IAAQ,GAAU,EAAM,GAAG;GAC7B,MAAU,KAAA,MACd,EAAM,eAAe,GAErB,EAAQ,QAAQ,EADH,GAAM,EAAM,QAAQ,EAAQ,KAAK,IAAI,GAAO,GAAG,EAAM,SAAS,CACrD,MAAS,EAAQ,OACvC,EAAO,EAAQ,KAAK,CAAC,EAAE,MAAM;EAC/B;EAGA,IAAM,KAAS,MAAM,KAAK,EAAE,QAAQ,GAAG,IAAI,GAAG,MAAM,CAAC,GAC/C,IAAe,EAAI,EAAW,KAAK,GACnC,MAAe,MACnB,SAAS,eAAe,GAAG,EAAY,KAAK,GAAG;EACjD,SAAS,GAAgB,GAAW;GAClC,OAAO,EAAmB,EAAS,OAAO,CAAC;EAC7C;EACA,SAAS,GAAY,GAAW;GAC9B,AAAI,GAAgB,CAAC,KAAG,GAAgB,EAAS,OAAO,CAAC;EAC3D;EACA,IAAM,MAAmB,MACvB,GAAc,GAAO,IAAQ,GAAc,IAAa,EAAW,GAa/D,MAAa,MACjB,MAAM,KAAK,EAAE,QAAQ,KAAK,KAAK,EAAK,SAAA,CAAuB,EAAE,IAAI,GAAG,MAClE,EAAK,MAAM,IAAA,GAAoB,IAAA,IAAA,CAAmC,CACpE,GAEI,KAAY,QAAe,GAAM,GAAY,MAAM,KAAK,GAAM,OAAO;GAAE;GAAM;EAAE,EAAE,CAAC,CAAC,GAGnF,KAAY,QAAe;GAS/B,IAAM,IAAO,EAAS,EAAM,GAAG,CAAC,EAAE,YAAY,KAAK,EAAS,QAAQ,KAC9D,IAAO,EAAS,EAAM,GAAG,CAAC,EAAE,YAAY,KAAK,EAAS,QAAQ,KAC9D,IAAiB,CAAC;GACxB,KAAK,IAAI,IAAI,GAAM,KAAK,GAAM,KAAK,EAAK,KAAK,CAAC;GAC9C,OAAO;EACT,CAAC,GACK,KAAW,QAAe,GAAM,GAAU,KAAK,CAAC,GAChD,IAAc,EAAI,EAAS,KAAK,GAChC,MAAc,MAClB,SAAS,eAAe,GAAG,EAAY,KAAK,GAAG,GAC3C,KAAc,MAAc,GAAgB,GAAG,EAAW,KAAK,GAC/D,MAAkB,MACtB,GAAc,GAAO,GAAU,OAAO,GAAa,IAAY,CAAU;EAK3E,SACQ;GAAC,EAAY;GAAO,EAAW,MAAM;GAAO,EAAe,MAAM;EAAE,SACnE;GACJ,IAAM,IAAU,EAAY,SAAS,EAAW,MAAM,SAAS,EAAe,MAAM;GACpF,IAAI,KAAW,EAAW,CAAO,GAAG;IAClC,IAAM,IAAI,EAAS,CAAO;IAC1B,CAAI,EAAE,YAAY,MAAM,EAAS,SAAS,EAAE,SAAS,MAAM,EAAW,WACpE,EAAW,QAAQ;GAEvB;EACF,CACF;EAOA,SAAS,GAAM,GAAwB;GAErC,AADA,EAAK,QAAQ,QACb,EAAS,EAAW,OAAO,CAAO;EACpC;EAYA,SAAS,KAAQ;GAGf,AAFA,EAAK,QAAQ,QACb,EAAS,QAAQ,MACjB,EAAW,QAAQ,GAAa;EAClC;SAEA,EAAa;GAEX;GAKA;EACF,CAAC,mBAIC,EA0NM,OAAA;GAzNJ,OAAM;GACN,MAAK;GACJ,cAAY,EAAA,EAAA;GACZ,aAAW,EAAA;GACX,kBAAgB,EAAA;GAChB,iBAAe,EAAA,WAAQ,KAAQ,KAAA;GAC/B,iBAAe,EAAA,WAAQ,KAAQ,KAAA;GAC/B,gBAAY,AAAA,EAAA,QAAA,MAAE,EAAA,QAAQ;;GAIvB,EAqEM,OArEN,IAqEM,CApEJ,EAiCM,OAjCN,IAiCM;IAhCJ,EAOc,GAAA;KANX,OAAO,EAAA,CAAA,CAAC,CAAC,WAAW;KACrB,MAAK;KACJ,UAAU,EAAA,YAAQ,CAAK,GAAA;KACvB,SAAK,AAAA,EAAA,QAAA,MAAE,GAAS,EAAA;;sBAEyB,CAA1C,EAA0C,GAAA;MAAlC,MAAM,EAAA,CAAA;MAAiB,UAAA;;;;IAEjC,EAeU,GAAA;KAdR,SAAQ;KACR,MAAK;KACL,MAAK;KACL,OAAM;KACL,UAAU,EAAA;KACV,iBAAe,EAAA,UAAI;KACnB,cAAY,GAAA;KACZ,SAAK,AAAA,EAAA,QAAA,MAAE,GAAU,QAAA;;sBAEW,CAAA,GAAA,EAA1B,GAAA,MAAY,EAAA,MAAU,IAAI,KAC7B,CAAA,GAAA,EAGE,GAAA;MAFC,MAAM,EAAA,UAAI,WAAgB,EAAA,EAAA,IAAkB,EAAA,EAAA;MAC7C,eAAY;;;;;;;;IAGhB,EAOc,GAAA;KANX,OAAO,EAAA,CAAA,CAAC,CAAC,WAAW;KACrB,MAAK;KACJ,UAAU,EAAA,YAAQ,CAAK,GAAA;KACvB,SAAK,AAAA,EAAA,QAAA,MAAE,GAAS,CAAA;;sBAE0B,CAA3C,EAA2C,GAAA;MAAnC,MAAM,EAAA,EAAA;MAAkB,UAAA;;;;OAIpC,EAgCM,OAhCN,IAgCM;IA/BJ,EAOc,GAAA;KANX,OAAO,EAAA,CAAA,CAAC,CAAC,WAAW;KACrB,MAAK;KACJ,UAAU,EAAA,YAAQ,CAAK,GAAA;KACvB,SAAK,AAAA,EAAA,QAAA,MAAE,GAAQ,EAAA;;sBAE0B,CAA1C,EAA0C,GAAA;MAAlC,MAAM,EAAA,CAAA;MAAiB,UAAA;;;;IAEjC,EAcU,GAAA;KAbR,SAAQ;KACR,MAAK;KACL,MAAK;KACL,OAAM;KACL,UAAU,EAAA;KACV,iBAAe,EAAA,UAAI;KACnB,SAAK,AAAA,EAAA,QAAA,MAAE,GAAU,OAAA;;sBAEJ,CAAA,GAAA,EAAX,EAAA,KAAQ,IAAG,KACd,CAAA,GAAA,EAGE,GAAA;MAFC,MAAM,EAAA,UAAI,UAAe,EAAA,EAAA,IAAkB,EAAA,EAAA;MAC5C,eAAY;;;;IAGhB,EAOc,GAAA;KANX,OAAO,EAAA,CAAA,CAAC,CAAC,WAAW;KACrB,MAAK;KACJ,UAAU,EAAA,YAAQ,CAAK,GAAA;KACvB,SAAK,AAAA,EAAA,QAAA,MAAE,GAAQ,CAAA;;sBAE2B,CAA3C,EAA2C,GAAA;MAAnC,MAAM,EAAA,EAAA;MAAkB,UAAA;;;;;MAMtC,EA2EM,OAAA;IAzEJ,OAAM;IACN,MAAK;IACJ,cAAY,GAAA;IACZ,wBAAsB,EAAA,cAAS,aAAA,SAA2B,KAAA;IAC1D,WAAS;OAEV,EASM,OATN,IASM,EAAA,EAAA,EAAA,GARJ,EAOC,GAAA,MAAA,EANkB,GAAA,QAAT,GAAG,YADb,EAOC,QAAA;IALE,KAAK;IACN,OAAM;IACN,MAAK;IACJ,cAAY,GAAA,MAAa;QACtB,CAAC,GAAA,GAAA,EAAA,sBAGT,EAwDM,GAAA,MAAA,EAxDoB,GAAA,QAAb,GAAM,YAAnB,EAwDM,OAAA;IAxD4B,KAAK;IAAI,OAAM;IAAqB,MAAK;eACzE,EAsDM,GAAA,MAAA,EArDW,IAAR,YADT,EAsDM,OAAA;IApDH,KAAK,EAAK;IACX,OAAM;IACN,MAAK;IACJ,iBAAe,EAAK,SAAI,WAAgB,EAAK,WAAW,KAAA;IACxD,iBAAe,EAAK,UAAO,KAAQ,KAAA;IACnC,oBAAkB,EAAK,aAAU,KAAQ,KAAA;IACzC,kBAAgB,EAAK,WAAQ,KAAQ,KAAA;OAG9B,EAAK,SAAI,YAAA,EAAA,GADjB,EA4BS,UAAA;;IA1BN,IAAI,GAAM,EAAK,GAAG;IACnB,MAAK;IACL,OAAM;IACL,UAAU,EAAK,QAAQ,EAAA,QAAU,IAAA;IACjC,gBAAe,EAAK,UAAe,KAAA,IAAR;IAC3B,iBAAe,EAAK,WAAQ,KAAQ,KAAA;IACpC,cAAY,EAAK,QAAK,KAAQ,KAAA;IAC9B,oBAAkB,EAAK,WAAQ,KAAQ,KAAA;IACvC,UAAU,EAAA;IACV,iBAAe,EAAK,YAAY,EAAA,WAAQ,SAAY,KAAA;IACpD,gBAAc,EAAK,QAAK,SAAY,KAAA;IACpC,UAAK,MAAE,GAAU,CAAI;IACrB,iBAAY,MAAE,EAAA,QAAW,EAAK;IAC9B,UAAK,MAAE,EAAA,QAAW,EAAK;OAExB,EAEO,EAAA,QAAA,OAFP,GAEO,EAAA,SAAA,GAAA,GAFkB,GAAa,CAAI,CAAA,SAEnC,CADL,EAAyD,QAAzD,IAAyD,EAAlB,EAAK,GAAG,GAAA,CAAA,CAAA,CAAA,GAErC,EAAK,KAAK,UAAA,EAAA,GAAtB,EAOO,QAPP,IAOO,EAAA,EAAA,EAAA,GANL,EAKE,GAAA,MAAA,EAJmB,EAAK,OAAhB,GAAI,YADd,EAKE,QAAA;IAHC,KAAK;IACN,OAAM;IACL,OAAK,GAAE,EAAG,QAAK,EAAA,2BAAgC,EAAG,MAAK,IAAK,KAAA,CAAS;oDAW/D,EAAK,SAAI,YAAA,EAAA,GADtB,EAQO,QAAA;;IANL,OAAM;IACL,iBAAe,EAAK,WAAQ,KAAQ,KAAA;OAErC,EAEO,EAAA,QAAA,OAFP,GAEO,EAAA,SAAA,GAAA,GAFkB,GAAa,CAAI,CAAA,SAEnC,CADL,EAAyD,QAAzD,IAAyD,EAAlB,EAAK,GAAG,GAAA,CAAA,CAAA,CAAA,CAAA,GAAA,GAAA,EAAA,KAAA,EAAA,IAAA,EAAA,CAAA,GAAA,GAAA,EAAA,uCArE/C,EAAA,UAAI,MAAA,CAAA,CAAA;GA8EN,EAAA,UAAI,YAAA,EAAA,GADZ,EAwBM,OAAA;;IAtBJ,OAAM;IACN,MAAK;IACJ,cAAY,EAAA,CAAA,CAAC,CAAC,WAAW;IACzB,WAAS;eAEV,EAgBM,GAAA,MAAA,EAhBkB,GAAA,QAAX,GAAK,YAAlB,EAgBM,OAAA;IAhB8B,KAAK;IAAG,OAAM;IAAyB,MAAK;eAC9E,EAcS,GAAA,MAAA,EAbe,IAAG,EAAhB,SAAM,iBADjB,EAcS,UAAA;IAZN,IAAE,GAAK,EAAA,CAAA,EAAW,KAAM;IACxB,KAAK;IACN,MAAK;IACL,OAAM;IACN,MAAK;IACJ,UAAU,MAAM,EAAA,QAAY,IAAA;IAC5B,iBAAe,MAAM,EAAA,QAAU,KAAQ,KAAA;IACvC,iBAAe,MAAM,EAAA,QAAU,SAAY,KAAA;IAC3C,UAAU,EAAA,YAAQ,CAAK,GAAgB,CAAC;IACxC,UAAK,MAAE,GAAY,CAAC;QAElB,CAAI,GAAA,GAAA,EAAA;GAOL,EAAA,UAAI,WAAA,EAAA,GADZ,EAwBM,OAAA;;IAtBJ,OAAM;IACN,MAAK;IACJ,cAAY,EAAA,CAAA,CAAC,CAAC,WAAW;IACzB,WAAS;eAEV,EAgBM,GAAA,MAAA,EAhBkB,GAAA,QAAX,GAAK,YAAlB,EAgBM,OAAA;IAhB6B,KAAK;IAAG,OAAM;IAAyB,MAAK;eAC7E,EAcS,GAAA,MAAA,EAbK,IAAL,YADT,EAcS,UAAA;IAZN,IAAE,GAAK,EAAA,CAAA,EAAW,KAAM;IACxB,KAAK;IACN,MAAK;IACL,OAAM;IACN,MAAK;IACJ,UAAU,MAAM,EAAA,QAAW,IAAA;IAC3B,iBAAe,MAAM,EAAA,QAAQ,KAAQ,KAAA;IACrC,iBAAe,MAAM,EAAA,QAAQ,SAAY,KAAA;IACzC,UAAU,EAAA;IACV,UAAK,MAAE,EAAW,CAAC;QAEjB,CAAC,GAAA,GAAA,EAAA;GAKCA,EAAAA,OAAO,UAAA,EAAA,GAAlB,EAEM,OAFN,IAEM,CADJ,EAAsB,EAAA,QAAA,QAAA,CAAA,CAAA,KAAA,EAAA,IAAA,EAAA"}
1
+ {"version":3,"file":"VDatePicker.vue_vue_type_script_setup_true_lang.js","names":["$slots"],"sources":["../../../src/components/VDatePicker/VDatePicker.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @a11y @keyboard @core\n/**\n * A calendar shown directly in the page, as a grid of days, with a month view and a\n * year view behind it. It holds ALL the date, view and keyboard logic of the design\n * system; VDateInput does no more than dress it in a text field and a popover.\n *\n * The platform offers no accessible date grid to build on — `<input type=\"date\">`\n * can be neither styled nor composed — so the JavaScript here implements the ARIA\n * \"grid\" pattern by hand: a single cell in the tab order at a time, arrow and\n * page keys to move between dates, and selection of one date, a range or a list.\n * None of that can be expressed in HTML and CSS alone.\n *\n * Every date is handled in local time as an ISO `YYYY-MM-DD` string (see\n * `utils/date`), which is what keeps the server and the browser in agreement.\n */\n\nimport { computed, inject, nextTick, onMounted, ref, useId, watch, watchEffect } from 'vue'\nimport type { Ref } from 'vue'\n\nimport VButton from '../VButton/VButton.vue'\nimport VIcon from '../VIcon/VIcon.vue'\nimport { arrow_drop_down as arrowDropDownIcon } from '../VIcon/icons/arrow_drop_down'\nimport { arrow_drop_up as arrowDropUpIcon } from '../VIcon/icons/arrow_drop_up'\nimport { chevron_left as chevronLeftIcon } from '../VIcon/icons/chevron_left'\nimport { chevron_right as chevronRightIcon } from '../VIcon/icons/chevron_right'\nimport VIconButton from '../VIconButton/VIconButton.vue'\nimport {\n addDays,\n addMonths,\n buildMonthGrid,\n clampISO,\n compareISO,\n daysInMonth,\n firstDayOfWeekFor,\n formatISO,\n isDateAllowed,\n isoOf,\n isSameISO,\n isValidISO,\n parseISO,\n weekdayNames,\n} from '../../utils/date'\nimport { monthName, monthNames, monthNamesCompact, monthYearName } from './names'\n\nimport { PICKER_COLUMNS, dayStep, gridDelta } from './keyboard'\n\nimport { toggleValue } from '../../utils/array'\nimport { isDev } from '../../utils/env'\nimport { hostWarnsKey } from '../../utils/hostWarns'\nimport { resolveMatcher } from '../../utils/matcher'\nimport { clamp } from '../../utils/number'\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useMessages, useResolvedLocale } from '../../i18n/state'\n\n/** What a click selects: one date, a period between two, or a list of dates. */\nexport type DatePickerSelection = 'single' | 'range' | 'multiple'\n\n/**\n * A period between two dates, the value of a `range` selection. Either bound may be\n * null: between the first and the second click, a range has a start and no end yet.\n */\nexport interface DatePickerRange {\n /** The first day of the period, as an ISO `YYYY-MM-DD` string. */\n start: string | null\n /** The last day of the period, as an ISO `YYYY-MM-DD` string. */\n end: string | null\n}\n\n/** Something happening on a given day, shown as a coloured dot under its number. */\nexport interface DatePickerEvent {\n /** The day it falls on, as an ISO `YYYY-MM-DD` string. */\n date: string\n /** The colour of the dot, as any CSS colour. It is the accent colour by default. */\n color?: string\n /** A description of the event, spoken as part of the day's accessible name. */\n label?: string\n}\n\n/**\n * Which dates cannot be selected, given either as a list of ISO strings or as a\n * function answering that question for a date.\n */\nexport type DatePickerMatcher = string[] | ((iso: string) => boolean)\n\n/** The shape of the v-model, which follows whichever `selection` is in use. */\nexport type DatePickerValue = string | null | DatePickerRange | string[]\n\n/** Everything the `#day` slot is told about the day it draws. */\nexport interface DatePickerDaySlotProps {\n /** The day, as an ISO `YYYY-MM-DD` string. */\n iso: string\n /** The day of the month. */\n day: number\n /** Whether it belongs to the month on display rather than to a neighbouring one. */\n inMonth: boolean\n /** Whether it cannot be chosen: outside the bounds, or excluded by `disabledDates`. */\n disabled: boolean\n /** Whether it is selected. */\n selected: boolean\n /** Whether it is today. */\n today: boolean\n /** Whether it falls inside the selected period, both ends included. */\n inRange: boolean\n /** The events that fall on it. */\n events: DatePickerEvent[]\n}\n\ninterface DatePickerProps {\n /**\n * What the reader is picking: a single date, a period between two dates, or any\n * number of separate dates. It determines the shape of the v-model.\n */\n selection?: DatePickerSelection\n /**\n * A BCP 47 locale, which decides the month and day names and the first day of the\n * week. It TAKES PRECEDENCE over the design system's global locale (`setLocale`)\n * and falls back to it, which is why it has no literal default here: `undefined`\n * has to stay recognizable for the global locale to have its chance.\n */\n locale?: string\n /**\n * Forces the day the weeks start on (0 for Sunday through 6 for Saturday). Left\n * out, the locale decides.\n */\n firstDayOfWeek?: number\n /**\n * The earliest selectable date, as an ISO string. Neither navigation nor selection\n * goes back beyond it.\n */\n min?: string\n /**\n * The latest selectable date, as an ISO string. Neither navigation nor selection\n * goes past it.\n */\n max?: string\n /**\n * Dates that cannot be chosen, given as a list of ISO strings or as a function.\n * They stay visible, struck through, and can still be reached with the keyboard.\n */\n disabledDates?: DatePickerMatcher\n /**\n * Also fills the empty corners of the grid with the greyed days of the neighbouring\n * months. It is off by default.\n */\n showAdjacentDays?: boolean\n /**\n * Lets those neighbouring days be clicked, which moves the calendar to their month.\n * A clickable day has to be visible, so this implies showing them.\n */\n selectAdjacentDays?: boolean\n /** The events to mark, as up to three coloured dots under the day they fall on. */\n events?: DatePickerEvent[]\n /**\n * Makes the whole calendar unusable: no date can be chosen, no month reached, and\n * everything greys out through the colour tokens.\n */\n disabled?: boolean\n /**\n * Shows what is selected without letting it be changed. The calendar can still be\n * read and walked through (another month, another year), which is what separates it\n * from `disabled`.\n */\n readonly?: boolean\n /**\n * The accessible name of the whole picker, its header and its grid together. A range\n * shown as two calendars side by side needs one each, or a screen reader announces the\n * same group twice. It falls back to the dictionary, and a consumer `aria-label` wins.\n */\n label?: string\n}\n\nconst props = withDefaults(defineProps<DatePickerProps>(), {\n selection: 'single',\n locale: undefined,\n firstDayOfWeek: undefined,\n min: undefined,\n max: undefined,\n disabledDates: undefined,\n showAdjacentDays: false,\n selectAdjacentDays: false,\n events: undefined,\n disabled: false,\n readonly: false,\n label: undefined,\n})\n\n/**\n * What is selected, and its SHAPE follows `selection`: an ISO `YYYY-MM-DD` string for\n * `single`, a `{ start, end }` pair for `range`, an array of strings for `multiple`. Nothing\n * is selected to begin with.\n *\n * Every date is a plain local-time string, never a `Date`, so the value a consumer receives\n * cannot shift a day across time zones.\n */\nconst model = defineModel<DatePickerValue>({ default: null })\n\nconst emit = defineEmits<{\n /**\n * Emitted every time a date is chosen, carrying the complete value as it now\n * stands. VDateInput listens to it to close its panel on a single selection.\n */\n select: [value: DatePickerValue]\n}>()\n\ndefineSlots<{\n /**\n * Replaces the content of a day cell, to show a price or an availability under the\n * number for instance. It receives everything known about that day, including\n * whether it belongs to the displayed month.\n */\n day?(props: DatePickerDaySlotProps): unknown\n /** The strip under the grid, for actions such as Close or Save, or for preset dates. */\n footer?(): unknown\n}>()\n\nconst gridLabelId = useId()\n\n// The navigation labels have no prop of their own: the dictionary is the single\n// place to change them, globally or per language — see `src/i18n/`.\nconst m = useMessages()\n// @a11y\n// A roleless box cannot carry an accessible name (axe: aria-prohibited-attr),\n// so the root is a named group: the VCarousel viewport arrangement.\nconst ariaLabel = useAriaLabel(() => props.label ?? m.value.datePicker.label)\nconst resolvedLocale = useResolvedLocale(() => props.locale)\n\n// @devwarn\n// Silent inside a host that forwards these props and reports on them itself (utils/hostWarns).\nif (isDev && !inject(hostWarnsKey, false)) {\n watchEffect(() => {\n if (props.min && props.max && compareISO(props.min, props.max) > 0)\n console.warn(\n `[VDatePicker] min \"${props.min}\" falls after max \"${props.max}\", so no date can be chosen.`,\n )\n })\n}\n\nconst resolvedFirstDay = computed(\n () => props.firstDayOfWeek ?? firstDayOfWeekFor(resolvedLocale.value),\n)\nconst weekdays = computed(() => weekdayNames(resolvedLocale.value, resolvedFirstDay.value, 'short'))\nconst weekdaysLong = computed(() =>\n weekdayNames(resolvedLocale.value, resolvedFirstDay.value, 'long'),\n)\nconst monthLabels = computed(() => monthNamesCompact(resolvedLocale.value))\n/** The full names the compact cells are spoken with: \"Jan.\" is not a word to hear. */\nconst monthNamesLong = computed(() => monthNames(resolvedLocale.value))\n\nconst singleValue = computed(() =>\n props.selection === 'single' && typeof model.value === 'string' && isValidISO(model.value)\n ? model.value\n : null,\n)\nconst rangeValue = computed<DatePickerRange>(() => {\n if (\n props.selection === 'range' &&\n model.value &&\n typeof model.value === 'object' &&\n !Array.isArray(model.value)\n ) {\n return model.value as DatePickerRange\n }\n return { start: null, end: null }\n})\nconst multipleValues = computed<string[]>(() =>\n props.selection === 'multiple' && Array.isArray(model.value) ? model.value : [],\n)\n\n// `focusedISO` is the single source of truth for the view: the month on display is\n// derived from it, never stored separately, so the two cannot drift apart.\n//\n// TRAP — a range start or a list entry is validated HERE, the way the single value is\n// validated upstream. Those two reach this component exactly as the consumer wrote them,\n// and a malformed one (`{ start: 'foo' }`) made the focused date unparseable: the month\n// arrows assert that parse, so the first render threw.\nfunction initialFocus(): string {\n if (singleValue.value) return singleValue.value\n const start = rangeValue.value.start\n if (start && isValidISO(start)) return start\n const listed = multipleValues.value.find(isValidISO)\n if (listed) return listed\n // With nothing selected, the calendar opens on today, brought back inside the\n // allowed bounds.\n readTheClock = true\n return clampISO(formatISO(new Date()), props.min, props.max)\n}\n/** Whether the month on display was read from the clock at setup: see `renderEpoch`. */\nlet readTheClock = false\nconst focusedISO = ref(initialFocus())\nconst view = ref<'days' | 'months' | 'years'>('days')\n\nconst viewYear = computed(\n () => parseISO(focusedISO.value)?.getFullYear() ?? new Date().getFullYear(),\n)\nconst viewMonth0 = computed(() => parseISO(focusedISO.value)?.getMonth() ?? 0)\nconst monthLabel = computed(() => monthName(resolvedLocale.value, viewMonth0.value))\nconst gridLabel = computed(() =>\n monthYearName(resolvedLocale.value, viewYear.value, viewMonth0.value),\n)\n\n// @ssr\n// Today's date is only read once the component is mounted, hence on the client: the\n// server has no way to know it, and rendering it during setup would make the two\n// markups differ and break hydration.\nconst today = ref<string | null>(null)\n\n// @ssr\n/*\n * TRAP — with nothing selected, the month on display is read from the clock at setup, on\n * the server and again in the browser, and the two can disagree: a page prerendered in\n * September and opened in October, or a server a timezone behind its visitor on the last\n * evening of a month. Hydration then patches the TEXT and keeps the server's ATTRIBUTES, so\n * the month button said \"Oct.\" on screen and \"September\" to a screen reader, and the day ids\n * `focusDay` looks up named days that were not there.\n *\n * The header and the grid are therefore keyed on `renderEpoch`, which is bumped once, on\n * mount, whenever the month came from the clock: both are then built again from the\n * browser's own state. Nothing on the page can say whether the server agreed (the grid's\n * own title IS patched, the month button's is not), and rebuilding an empty picker once\n * costs less than asking. A picker opened on a value is never rebuilt.\n */\nconst renderEpoch = ref(0)\nonMounted(() => {\n today.value = formatISO(new Date())\n if (readTheClock) renderEpoch.value++\n})\n\nconst isDisabledDate = computed(() => resolveMatcher(props.disabledDates))\n\nconst eventsByDate = computed(() => {\n const map = new Map<string, DatePickerEvent[]>()\n for (const ev of props.events ?? []) {\n const list = map.get(ev.date) ?? []\n list.push(ev)\n map.set(ev.date, list)\n }\n return map\n})\n\nconst hoverISO = ref<string | null>(null)\nfunction orderRange(a: string, b: string): DatePickerRange {\n return compareISO(a, b) <= 0 ? { start: a, end: b } : { start: b, end: a }\n}\nconst effectiveRange = computed<DatePickerRange>(() => {\n if (props.selection !== 'range') return { start: null, end: null }\n const r = rangeValue.value\n if (r.start && r.end) return orderRange(r.start, r.end)\n // A start is set but the end is still pending: the range is previewed up to\n // whichever day the pointer or the focus is currently on.\n const preview = hoverISO.value ?? focusedISO.value\n if (r.start && preview) return orderRange(r.start, preview)\n return { start: r.start, end: r.end }\n})\n\n/**\n * Whether a day is part of the COMMITTED value, which is what `aria-selected` says: the\n * end a range preview is drawing is not selected yet, and announcing every day the focus\n * walks over as \"selected\" would say so.\n */\nfunction isCommitted(iso: string): boolean {\n if (props.selection !== 'range') return isSelected(iso)\n return isSameISO(iso, rangeValue.value.start) || isSameISO(iso, rangeValue.value.end)\n}\n\nfunction isSelected(iso: string): boolean {\n if (props.selection === 'single') return isSameISO(iso, singleValue.value)\n if (props.selection === 'multiple') return multipleValues.value.includes(iso)\n // In range selection, the two ends of the period count as selected — including the\n // provisional end shown during the preview.\n return isSameISO(iso, effectiveRange.value.start) || isSameISO(iso, effectiveRange.value.end)\n}\n/**\n * Whether a day falls inside the selected period, BOTH ends included.\n *\n * The inclusiveness is a contract with the stylesheet, not a detail: `[data-in-range]` is\n * what draws the band's pseudo-element, and the two end rules only round a corner of one\n * that already exists. Narrowing this to the days strictly between would leave each end\n * with nothing to cap and silently square off every range.\n */\nfunction isInRange(iso: string): boolean {\n const { start, end } = effectiveRange.value\n return !!start && !!end && compareISO(iso, start) >= 0 && compareISO(iso, end) <= 0\n}\n\ntype DayCell = {\n iso: string\n day: number\n kind: 'empty' | 'static' | 'button'\n inMonth: boolean\n disabled: boolean\n selected: boolean\n /** Selected in the value itself, the preview left out: what `aria-selected` reports. */\n committed: boolean\n rangeStart: boolean\n rangeEnd: boolean\n inRange: boolean\n today: boolean\n events: DatePickerEvent[]\n /** The events drawn as dots under the number, three at most. */\n dots: DatePickerEvent[]\n /** The labels of its events, joined, for the day's accessible name. */\n eventText: string\n}\n\n/**\n * The 42 squares of the month on display, rebuilt only when the MONTH changes. The two\n * computeds are split on purpose: a range being previewed changes `hoverISO` on every\n * `pointerenter`, and that has to repaint the decoration below without building 42 dates\n * again. `viewYear` and `viewMonth0` are numbers, so moving the focus inside the month\n * leaves them — and this — untouched.\n */\nconst grid = computed(() =>\n buildMonthGrid(viewYear.value, viewMonth0.value, resolvedFirstDay.value),\n)\n\nconst NO_EVENTS: DatePickerEvent[] = []\n\nconst days = computed<DayCell[]>(() =>\n grid.value.map((cell) => {\n const inMonth = cell.adjacent === null\n // Making the neighbouring days clickable implies showing them: a day nobody can\n // see cannot be clicked.\n const show = inMonth || props.showAdjacentDays || props.selectAdjacentDays\n const selectable = inMonth || props.selectAdjacentDays\n const disabled = !isDateAllowed(cell.iso, props.min, props.max, isDisabledDate.value)\n const kind: DayCell['kind'] = !show ? 'empty' : selectable ? 'button' : 'static'\n const events = eventsByDate.value.get(cell.iso) ?? NO_EVENTS\n return {\n iso: cell.iso,\n day: cell.day,\n kind,\n inMonth,\n disabled,\n selected: kind === 'button' && !disabled && isSelected(cell.iso),\n committed: kind === 'button' && !disabled && isCommitted(cell.iso),\n rangeStart: props.selection === 'range' && isSameISO(cell.iso, effectiveRange.value.start),\n rangeEnd: props.selection === 'range' && isSameISO(cell.iso, effectiveRange.value.end),\n inRange: props.selection === 'range' && isInRange(cell.iso),\n today: isSameISO(cell.iso, today.value),\n events,\n dots: events.length > 3 ? events.slice(0, 3) : events,\n eventText: events\n .map((ev) => ev.label)\n .filter(Boolean)\n .join(', '),\n }\n }),\n)\n\n/** What the `#day` slot receives for a square: the same object for both kinds of cell. */\nfunction daySlotProps(cell: DayCell): DatePickerDaySlotProps {\n return {\n iso: cell.iso,\n day: cell.day,\n inMonth: cell.inMonth,\n disabled: cell.disabled,\n selected: cell.selected,\n today: cell.today,\n inRange: cell.inRange,\n events: cell.events,\n }\n}\nconst weeks = computed(() => {\n const rows: DayCell[][] = []\n for (let i = 0; i < days.value.length; i += 7) rows.push(days.value.slice(i, i + 7))\n return rows\n})\n\nfunction monthHasSelectable(year: number, month0: number): boolean {\n const first = isoOf(year, month0, 1)\n const last = isoOf(year, month0, daysInMonth(year, month0))\n return (\n (!props.max || compareISO(first, props.max) <= 0) &&\n (!props.min || compareISO(last, props.min) >= 0)\n )\n}\n// Derived from the month on display, not from the focused day, so an arrow key moving the\n// focus inside the month does not recompute them.\nconst canPrevMonth = computed(() =>\n viewMonth0.value === 0\n ? monthHasSelectable(viewYear.value - 1, 11)\n : monthHasSelectable(viewYear.value, viewMonth0.value - 1),\n)\nconst canNextMonth = computed(() =>\n viewMonth0.value === 11\n ? monthHasSelectable(viewYear.value + 1, 0)\n : monthHasSelectable(viewYear.value, viewMonth0.value + 1),\n)\nconst canPrevYear = computed(\n () => !props.min || compareISO(isoOf(viewYear.value - 1, 11, 31), props.min) >= 0,\n)\nconst canNextYear = computed(\n () => !props.max || compareISO(isoOf(viewYear.value + 1, 0, 1), props.max) <= 0,\n)\n\n// @a11y\n// Moves the real DOM focus onto a day cell. The grid keeps exactly one cell in the\n// tab order, so navigating means focusing another one.\nconst dayId = (iso: string) => `${gridLabelId}-d-${iso}`\nfunction focusDay(iso: string, options?: FocusOptions) {\n nextTick(() => document.getElementById(dayId(iso))?.focus(options))\n}\n\nfunction goTo(iso: string, moveFocus = false) {\n // Every move through the calendar comes here, so one guard covers the arrows, the\n // month and year cells and the keyboard's own steps. Only `disabled` stops it:\n // `readonly` leaves the reader free to look around.\n if (props.disabled) return\n focusedISO.value = clampISO(iso, props.min, props.max)\n if (moveFocus && view.value === 'days') focusDay(focusedISO.value)\n}\nfunction stepMonth(delta: number) {\n goTo(addMonths(focusedISO.value, delta))\n}\nfunction stepYear(delta: number) {\n goTo(addMonths(focusedISO.value, delta * 12))\n}\n\n// @a11y @core\n// Changing view has to carry the focus onto the cell the new view\n// opens on. Without that move the focus would stay on a button the view has just\n// removed from the document, and the keyboard would have nowhere to go.\nfunction toggleView(target: 'months' | 'years') {\n const next = view.value === target ? 'days' : target\n view.value = next\n if (next === 'months') {\n focusedMonth.value = viewMonth0.value\n nextTick(() => monthCellEl(viewMonth0.value)?.focus())\n } else if (next === 'years') {\n focusedYear.value = viewYear.value\n nextTick(() => {\n const cell = yearCellEl(viewYear.value)\n // Called optionally because jsdom does not implement scrollIntoView (the same\n // guard as VTimeInput's list). Centring the year is a nicety; the focus call\n // below is not, so it must not be taken down with it.\n cell?.scrollIntoView?.({ block: 'center' })\n cell?.focus()\n })\n } else if (view.value === 'days') {\n focusDay(focusedISO.value)\n }\n}\n\nfunction selectDay(cell: DayCell) {\n // The single choke point of the selection, so the two states are refused here rather\n // than in each of the routes that lead to it — a click, Enter and Space all pass\n // through. Navigation is deliberately NOT guarded by `readonly`: a calendar one may\n // read is a calendar one may leaf through.\n if (props.disabled || props.readonly) return\n if (cell.kind !== 'button' || cell.disabled) return\n focusedISO.value = cell.iso\n let next: DatePickerValue\n if (props.selection === 'single') {\n next = cell.iso\n } else if (props.selection === 'multiple') {\n next = toggleValue(multipleValues.value, cell.iso).sort(compareISO)\n } else {\n // Range selection reads three clicks: the first sets the start, the second the\n // end (reordered if it comes before the start), and the third starts a new\n // period.\n const r = rangeValue.value\n next = !r.start || r.end ? { start: cell.iso, end: null } : orderRange(r.start, cell.iso)\n }\n lastWritten = JSON.stringify(next)\n model.value = next\n // TRAP: emit what was just computed, never `model.value` read back. Under a parent\n // `v-model`, `defineModel` does not update its local copy on write — it waits for the\n // parent to re-render — so the read would hand `select` the PREVIOUS value.\n emit('select', next)\n}\n\n// @keyboard @a11y\n// The keyboard of the days view. The table turning a key into a step is pure and\n// lives in `./keyboard`; what stays here is the date that step is applied to, and\n// the focus move that follows.\nfunction onDaysKeydown(event: KeyboardEvent) {\n // A key held with a modifier is the browser's or the system's: Alt+Left is Back.\n if (event.altKey || event.ctrlKey || event.metaKey) return\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n const cell = days.value.find((c) => c.iso === focusedISO.value)\n if (cell) selectDay(cell)\n return\n }\n const d = parseISO(focusedISO.value)!\n // How far the focused day sits from the start of its week, which is exactly what\n // Home and End have to step back and forward by.\n const offset = (d.getDay() - resolvedFirstDay.value + 7) % 7\n const step = dayStep(event.key, event.shiftKey, offset)\n if (!step) return\n event.preventDefault()\n goTo(\n 'days' in step\n ? addDays(focusedISO.value, step.days)\n : addMonths(focusedISO.value, step.months),\n true,\n )\n}\n\n/**\n * Leaving the months or the years view for the days of the month chosen, keeping the day of\n * the month where the new month has one — the 31st becoming the 30th, say.\n */\nfunction chooseYearMonth(year: number, month0: number) {\n const day = Math.min(parseISO(focusedISO.value)!.getDate(), daysInMonth(year, month0))\n goTo(isoOf(year, month0, day))\n view.value = 'days'\n focusDay(focusedISO.value)\n}\n\n// @keyboard @a11y\n/**\n * The keyboard of the months and the years views, which differ only in what their cells\n * hold: Enter or Space chooses the focused cell, and the arrows walk the list of cells a row\n * or a column at a time, stopping at either end.\n */\nfunction onViewKeydown(\n event: KeyboardEvent,\n cells: readonly number[],\n focused: Ref<number>,\n cellEl: (value: number) => HTMLElement | null,\n choose: (value: number) => void,\n selectable: (value: number) => boolean = () => true,\n) {\n if (event.altKey || event.ctrlKey || event.metaKey) return\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n choose(focused.value)\n return\n }\n const delta = gridDelta(event.key)\n if (delta === undefined) return\n event.preventDefault()\n // A cell the bounds rule out is a DISABLED button, which cannot take the focus: landing\n // on it would move the tab stop where the focus cannot follow. The walk goes on the same\n // way round to the next cell that can be chosen, and holds still when there is none.\n let next = clamp(cells.indexOf(focused.value) + delta, 0, cells.length - 1)\n while (!selectable(cells[next]!) && next + delta >= 0 && next + delta < cells.length)\n next += delta\n if (!selectable(cells[next]!)) return\n focused.value = cells[next]!\n cellEl(focused.value)?.focus()\n}\n\n// The months view, opened from the month button in the header.\nconst MONTHS = Array.from({ length: 12 }, (_, i) => i)\nconst focusedMonth = ref(viewMonth0.value)\nconst monthCellEl = (i: number) =>\n document.getElementById(`${gridLabelId}-m-${i}`) as HTMLElement | null\nfunction monthSelectable(i: number) {\n return monthHasSelectable(viewYear.value, i)\n}\nfunction chooseMonth(i: number) {\n if (monthSelectable(i)) chooseYearMonth(viewYear.value, i)\n}\nconst onMonthsKeydown = (event: KeyboardEvent) =>\n onViewKeydown(event, MONTHS, focusedMonth, monthCellEl, chooseMonth, monthSelectable)\n\n// @a11y\n/*\n * Both pickers are a `role=\"grid\"`, and a grid owns ROWS, not cells: a gridcell\n * placed straight under the grid fails aria-required-children and\n * aria-required-parent at the same time. The cells are therefore cut into rows of\n * PICKER_COLUMNS, matching the `grid-template-columns` of the stylesheet — the row\n * element itself is `display: contents`, so the CSS grid never sees it.\n *\n * Keyboard navigation is unaffected by this extra level: it moves by index and\n * refocuses cells through their ids, never by walking the DOM.\n */\nconst chunk = <T,>(list: T[]) =>\n Array.from({ length: Math.ceil(list.length / PICKER_COLUMNS) }, (_, r) =>\n list.slice(r * PICKER_COLUMNS, r * PICKER_COLUMNS + PICKER_COLUMNS),\n )\n\nconst monthRows = computed(() => chunk(monthLabels.value.map((name, i) => ({ name, i }))))\n\n// The years view, opened from the year button in the header.\nconst yearRange = computed(() => {\n /*\n * `min` and `max` come straight from the consumer, and this is the ONLY place\n * where they are turned into a Date instead of being compared as ISO text —\n * `compareISO`, `isWithin` and `clampISO` all tolerate a malformed bound. A value\n * that is not a valid ISO date therefore has to fall back to the open range here:\n * asserting the parse would throw and take the whole render down the moment the\n * years view is opened.\n */\n const minY = parseISO(props.min)?.getFullYear() ?? viewYear.value - 100\n const maxY = parseISO(props.max)?.getFullYear() ?? viewYear.value + 100\n const list: number[] = []\n for (let y = minY; y <= maxY; y++) list.push(y)\n return list\n})\nconst yearRows = computed(() => chunk(yearRange.value))\nconst focusedYear = ref(viewYear.value)\nconst yearCellEl = (y: number) =>\n document.getElementById(`${gridLabelId}-y-${y}`) as HTMLElement | null\nconst chooseYear = (y: number) => chooseYearMonth(y, viewMonth0.value)\nconst onYearsKeydown = (event: KeyboardEvent) =>\n onViewKeydown(event, yearRange.value, focusedYear, yearCellEl, chooseYear)\n\n// Follows a selection changed from the outside: when the leading value lands in\n// another month, the calendar moves to it rather than leaving the reader in front of\n// a grid where nothing is selected.\n//\n// TRAP — only from the OUTSIDE. The picker's own writes change the leading value too:\n// unticking the earliest date of a list makes the next one lead, and following it would\n// throw the reader into another month and drop the focus on `<body>`, the day they were\n// on having left the document. `lastWritten` is the value `selectDay` just wrote, and a\n// model that still reads the same was not changed by anyone else. It is compared as TEXT:\n// a parent v-model hands back a reactive proxy of the array, never the array written.\nlet lastWritten: string | undefined\nwatch(\n () => [singleValue.value, rangeValue.value.start, multipleValues.value[0]],\n () => {\n if (lastWritten !== undefined && JSON.stringify(model.value) === lastWritten) return\n const primary = singleValue.value ?? rangeValue.value.start ?? multipleValues.value[0]\n if (primary && isValidISO(primary)) {\n const d = parseISO(primary)!\n if (d.getFullYear() !== viewYear.value || d.getMonth() !== viewMonth0.value) {\n focusedISO.value = primary\n }\n }\n },\n)\n\n// @a11y\n/**\n * Brings the focus into the grid, on the day the calendar is currently showing. This\n * is what VDateInput calls when it opens its panel.\n */\nfunction focus(options?: FocusOptions) {\n view.value = 'days'\n focusDay(focusedISO.value, options)\n}\n\n// @core\n/*\n * Puts the calendar back the way it opens: the days view, on the selected date (today\n * failing that), with no range preview pending. It moves no focus and announces nothing,\n * a panel reopening not being something the reader did.\n *\n * TRAP — a panel's content stays MOUNTED while the panel is closed, so without this the\n * months or years view a reader left open is what the next opening shows — and a field\n * that opens its panel on focus never calls `focus()`, the one place that reset the view.\n */\nfunction reset() {\n view.value = 'days'\n hoverISO.value = null\n focusedISO.value = initialFocus()\n}\n\ndefineExpose({\n /** Brings the focus into the grid, onto the day the calendar is showing. */\n focus,\n /**\n * Returns to the days view, on the selected date or today, without moving the focus.\n * VDateInput calls it each time its panel opens and closes.\n */\n reset,\n})\n</script>\n\n<template>\n <div\n class=\"v-date-picker\"\n role=\"group\"\n :aria-label=\"ariaLabel\"\n :data-view=\"view\"\n :data-selection=\"selection\"\n :data-disabled=\"disabled ? '' : undefined\"\n :data-readonly=\"readonly ? '' : undefined\"\n @pointerleave=\"hoverISO = null\"\n >\n <!-- The header: the month and the year, each between two chevrons that step it,\n and each opening its own picker view when clicked -->\n <div :key=\"`header-${renderEpoch}`\" class=\"v-date-picker-header\">\n <div class=\"v-date-picker-nav\">\n <VIconButton\n :label=\"m.datePicker.previousMonth\"\n size=\"sm\"\n :disabled=\"disabled || !canPrevMonth\"\n @click=\"stepMonth(-1)\"\n >\n <VIcon :name=\"chevronLeftIcon\" mirrored />\n </VIconButton>\n <VButton\n variant=\"ghost\"\n tone=\"neutral\"\n size=\"sm\"\n class=\"v-date-picker-view-toggle\"\n :disabled=\"disabled\"\n :aria-expanded=\"view === 'months'\"\n :aria-label=\"monthLabel\"\n @click=\"toggleView('months')\"\n >\n {{ monthLabels[viewMonth0] }}\n <VIcon\n :name=\"view === 'months' ? arrowDropUpIcon : arrowDropDownIcon\"\n aria-hidden=\"true\"\n />\n </VButton>\n <VIconButton\n :label=\"m.datePicker.nextMonth\"\n size=\"sm\"\n :disabled=\"disabled || !canNextMonth\"\n @click=\"stepMonth(1)\"\n >\n <VIcon :name=\"chevronRightIcon\" mirrored />\n </VIconButton>\n </div>\n\n <div class=\"v-date-picker-nav\">\n <VIconButton\n :label=\"m.datePicker.previousYear\"\n size=\"sm\"\n :disabled=\"disabled || !canPrevYear\"\n @click=\"stepYear(-1)\"\n >\n <VIcon :name=\"chevronLeftIcon\" mirrored />\n </VIconButton>\n <VButton\n variant=\"ghost\"\n tone=\"neutral\"\n size=\"sm\"\n class=\"v-date-picker-view-toggle\"\n :disabled=\"disabled\"\n :aria-expanded=\"view === 'years'\"\n @click=\"toggleView('years')\"\n >\n {{ viewYear }}\n <VIcon\n :name=\"view === 'years' ? arrowDropUpIcon : arrowDropDownIcon\"\n aria-hidden=\"true\"\n />\n </VButton>\n <VIconButton\n :label=\"m.datePicker.nextYear\"\n size=\"sm\"\n :disabled=\"disabled || !canNextYear\"\n @click=\"stepYear(1)\"\n >\n <VIcon :name=\"chevronRightIcon\" mirrored />\n </VIconButton>\n </div>\n </div>\n\n <!-- Days view -->\n <div\n v-show=\"view === 'days'\"\n :key=\"`days-${renderEpoch}`\"\n class=\"v-date-picker-grid\"\n role=\"grid\"\n :aria-label=\"gridLabel\"\n :aria-multiselectable=\"selection === 'multiple' ? 'true' : undefined\"\n @keydown=\"onDaysKeydown\"\n >\n <div class=\"v-date-picker-weekdays\" role=\"row\">\n <span\n v-for=\"(w, i) in weekdays\"\n :key=\"w\"\n class=\"v-date-picker-weekday\"\n role=\"columnheader\"\n :aria-label=\"weekdaysLong[i]\"\n >{{ w }}</span\n >\n </div>\n <div v-for=\"(week, wi) in weeks\" :key=\"wi\" class=\"v-date-picker-week\" role=\"row\">\n <div\n v-for=\"cell in week\"\n :key=\"cell.iso\"\n class=\"v-date-picker-cell\"\n role=\"gridcell\"\n :aria-selected=\"cell.kind === 'button' ? cell.committed : undefined\"\n :data-in-range=\"cell.inRange ? '' : undefined\"\n :data-range-start=\"cell.rangeStart ? '' : undefined\"\n :data-range-end=\"cell.rangeEnd ? '' : undefined\"\n >\n <button\n v-if=\"cell.kind === 'button'\"\n :id=\"dayId(cell.iso)\"\n type=\"button\"\n class=\"v-date-picker-day\"\n :tabindex=\"cell.iso === focusedISO ? 0 : -1\"\n :data-outside=\"!cell.inMonth ? '' : undefined\"\n :data-selected=\"cell.selected ? '' : undefined\"\n :data-today=\"cell.today ? '' : undefined\"\n :data-unavailable=\"cell.disabled ? '' : undefined\"\n :disabled=\"disabled\"\n :aria-disabled=\"cell.disabled || readonly ? 'true' : undefined\"\n :aria-current=\"cell.today ? 'date' : undefined\"\n @click=\"selectDay(cell)\"\n @pointerenter=\"hoverISO = cell.iso\"\n @focus=\"hoverISO = cell.iso\"\n >\n <slot name=\"day\" v-bind=\"daySlotProps(cell)\">\n <span class=\"v-date-picker-day-num\">{{ cell.day }}</span>\n </slot>\n <!-- The dots are hidden from assistive technology, so what they stand for is\n spoken here, as part of the day's name. -->\n <span v-if=\"cell.eventText\" class=\"v-visually-hidden\">, {{ cell.eventText }}</span>\n <span v-if=\"cell.dots.length\" class=\"v-date-picker-dots\" aria-hidden=\"true\">\n <span\n v-for=\"(ev, ei) in cell.dots\"\n :key=\"ei\"\n class=\"v-date-picker-dot\"\n :style=\"ev.color ? { '--date-picker-dot-color': ev.color } : undefined\"\n />\n </span>\n </button>\n <!-- A day of a neighbouring month that cannot be selected. It renders the\n very same slot as the clickable days: were it left with the bare\n number, custom content taking several lines would apply to this month's\n days only, and the numbers would stop lining up from one cell to the\n next. The slot receives `inMonth`, which is how it can still tell the\n two apart. -->\n <span\n v-else-if=\"cell.kind === 'static'\"\n class=\"v-date-picker-day v-date-picker-day--static\"\n :data-disabled=\"cell.disabled ? '' : undefined\"\n >\n <slot name=\"day\" v-bind=\"daySlotProps(cell)\">\n <span class=\"v-date-picker-day-num\">{{ cell.day }}</span>\n </slot>\n </span>\n </div>\n </div>\n </div>\n\n <!-- Months view -->\n <div\n v-if=\"view === 'months'\"\n class=\"v-date-picker-view\"\n role=\"grid\"\n :aria-label=\"m.datePicker.monthPicker\"\n @keydown=\"onMonthsKeydown\"\n >\n <div v-for=\"(row, r) in monthRows\" :key=\"r\" class=\"v-date-picker-view-row\" role=\"row\">\n <button\n v-for=\"{ name, i } in row\"\n :id=\"`${gridLabelId}-m-${i}`\"\n :key=\"i\"\n type=\"button\"\n class=\"v-date-picker-view-cell\"\n role=\"gridcell\"\n :tabindex=\"i === focusedMonth ? 0 : -1\"\n :data-selected=\"i === viewMonth0 ? '' : undefined\"\n :aria-selected=\"i === viewMonth0 ? 'true' : undefined\"\n :aria-label=\"monthNamesLong[i]\"\n :disabled=\"disabled || !monthSelectable(i)\"\n @click=\"chooseMonth(i)\"\n >\n {{ name }}\n </button>\n </div>\n </div>\n\n <!-- Years view -->\n <div\n v-if=\"view === 'years'\"\n class=\"v-date-picker-view v-date-picker-view--years\"\n role=\"grid\"\n :aria-label=\"m.datePicker.yearPicker\"\n @keydown=\"onYearsKeydown\"\n >\n <div v-for=\"(row, r) in yearRows\" :key=\"r\" class=\"v-date-picker-view-row\" role=\"row\">\n <button\n v-for=\"y in row\"\n :id=\"`${gridLabelId}-y-${y}`\"\n :key=\"y\"\n type=\"button\"\n class=\"v-date-picker-view-cell\"\n role=\"gridcell\"\n :tabindex=\"y === focusedYear ? 0 : -1\"\n :data-selected=\"y === viewYear ? '' : undefined\"\n :aria-selected=\"y === viewYear ? 'true' : undefined\"\n :disabled=\"disabled\"\n @click=\"chooseYear(y)\"\n >\n {{ y }}\n </button>\n </div>\n </div>\n\n <div v-if=\"$slots.footer\" class=\"v-date-picker-footer\">\n <slot name=\"footer\" />\n </div>\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n .v-date-picker {\n /* The consumer sets the size of the day disc through its token; the cell around it —\n the hover area and the width of the column — grows to follow, and never falls below\n the size the cell token sets. */\n --date-picker-cell: max(\n var(--vectis-control-size-date-picker-cell),\n calc(var(--vectis-control-size-date-picker-day) + var(--vectis-space-1))\n );\n display: inline-flex;\n flex-direction: column;\n gap: var(--vectis-space-2);\n padding: var(--vectis-space-3);\n font-family: var(--vectis-text-family);\n color: var(--vectis-color-text);\n }\n\n /* The calendar is a flex column, so every block stretches to its full width by\n default. The days grid then fills that width through its 1fr columns, and never\n goes below the seven cells its own floor guarantees. */\n .v-date-picker-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--vectis-space-2);\n }\n\n .v-date-picker-nav {\n display: flex;\n align-items: center;\n }\n\n /* A minimum width holds this button steady, so the chevrons on either side do not\n shift as the month or year label changes length. */\n /* Qualified by an attribute the button always renders: `.v-button` sets its own\n `font-weight` at (0,1,0), and a tie between the two sheets would leave the weight to\n whichever the consumer's bundler put last. */\n .v-date-picker-view-toggle[data-size] {\n min-inline-size: var(--vectis-control-size-date-picker-nav-min);\n /* The semibold is state emphasis on the grid's main landmark, not a type role. */\n font-weight: var(--vectis-font-weight-semibold);\n text-transform: capitalize;\n }\n\n /* The days grid can never be narrower than seven cells. Above that floor it takes\n whatever width the calendar has — set by the header — and the 1fr columns share\n it out equally. */\n .v-date-picker-grid {\n min-inline-size: calc(7 * var(--date-picker-cell));\n }\n\n .v-date-picker-weekdays,\n .v-date-picker-week {\n display: grid;\n grid-template-columns: repeat(7, 1fr);\n }\n\n .v-date-picker-weekday {\n display: flex;\n align-items: center;\n justify-content: center;\n height: var(--vectis-control-height-sm);\n /* A column micro-header, which takes the overline type role. The casing stays\n `capitalize`, the calendar convention, rather than the full capitals the\n VTypography overline variant would apply. */\n font-size: var(--vectis-text-overline-size);\n font-weight: var(--vectis-text-overline-weight);\n letter-spacing: var(--vectis-text-overline-tracking);\n color: var(--vectis-color-text-muted);\n text-transform: capitalize;\n }\n\n .v-date-picker-cell {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n height: var(--date-picker-cell);\n }\n\n /* The band joining the days of a selected range: a tinted background laid behind\n the day, at the HEIGHT of the disc rather than of the whole cell. Its vertical\n inset is half the gap between cell and disc, expressed in `%` so it follows the\n real width of a 1fr column whatever the calendar measures.\n\n At either end the band stops exactly at the edge of the disc — hence the inset on\n the outer side — and that corner is rounded with the pill radius, which a box\n this height caps at half its height, i.e. precisely the disc's own radius, so it\n cannot overshoot.\n\n TRAP — the two cap rules below only shape a pseudo-element that `[data-in-range]`\n has already created, so they depend on `isInRange` counting BOTH ends of the period\n as inside it. Make it exclusive and there is no `::before` to cap: both rounded ends\n of every range vanish, leaving a band that stops square one cell short at each side,\n with nothing in the console. The last rule is the single-day case, where the two caps\n would meet and draw a disc behind the disc. */\n .v-date-picker-cell[data-in-range]::before {\n content: '';\n position: absolute;\n inset-block: calc((100% - var(--vectis-control-size-date-picker-day)) / 2);\n inset-inline: 0;\n background: var(--vectis-color-accent-surface);\n z-index: 0;\n }\n .v-date-picker-cell[data-range-start]::before {\n inset-inline-start: calc((100% - var(--vectis-control-size-date-picker-day)) / 2);\n border-start-start-radius: var(--vectis-radius-pill);\n border-end-start-radius: var(--vectis-radius-pill);\n }\n .v-date-picker-cell[data-range-end]::before {\n inset-inline-end: calc((100% - var(--vectis-control-size-date-picker-day)) / 2);\n border-start-end-radius: var(--vectis-radius-pill);\n border-end-end-radius: var(--vectis-radius-pill);\n }\n .v-date-picker-cell[data-range-start][data-range-end]::before {\n content: none;\n }\n\n .v-date-picker-day {\n position: relative;\n z-index: 1;\n display: inline-flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n inline-size: var(--vectis-control-size-date-picker-day);\n block-size: var(--vectis-control-size-date-picker-day);\n padding: 0;\n border: none;\n border-radius: var(--vectis-radius-pill);\n background: transparent;\n color: inherit;\n font: inherit;\n font-size: var(--vectis-text-body-md-size);\n cursor: pointer;\n transition:\n background-color var(--vectis-duration-fast) var(--vectis-ease-default),\n color var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n\n /* Hover belongs to the days one can actually click: not the disabled ones, not the\n already selected ones, and not the neighbouring days rendered as plain spans. */\n .v-date-picker-day:hover:not(:disabled):not([aria-disabled='true']):not([data-selected]):not(\n .v-date-picker-day--static\n ) {\n background: var(--vectis-color-surface-muted);\n }\n\n .v-date-picker-day[data-outside] {\n color: var(--vectis-color-text-subtle);\n }\n\n /* The semibold in the two rules below marks a state — today, and the selection —\n and is not a typographic role, which is why it reads a font token directly. */\n .v-date-picker-day[data-today]:not([data-selected]) {\n box-shadow: inset 0 0 0 1px var(--vectis-color-accent-border);\n color: var(--vectis-color-accent-text);\n font-weight: var(--vectis-font-weight-semibold);\n }\n\n .v-date-picker-day[data-selected] {\n background: var(--vectis-color-accent);\n color: var(--vectis-color-text-on-accent);\n font-weight: var(--vectis-font-weight-semibold);\n }\n\n /* The strike-through says the DATE is unavailable — outside the bounds, or listed in\n `disabledDates`. It hangs on its own attribute rather than on `aria-disabled`, which\n a read-only calendar also carries on every day: nothing can be chosen there, but the\n dates themselves are perfectly available and striking them all out would say the\n opposite. The hover rule below still reads `aria-disabled`, so neither highlights. */\n .v-date-picker-day[data-unavailable] {\n color: var(--vectis-color-text-subtle);\n text-decoration: line-through;\n cursor: not-allowed;\n }\n\n .v-date-picker[data-readonly] .v-date-picker-day:not([data-unavailable]) {\n cursor: default;\n }\n\n /* A disabled calendar greys out through the colour tokens and never through opacity,\n the selection included: left in the accent colour it would go on looking live. */\n .v-date-picker-day:disabled {\n color: var(--vectis-color-text-subtle);\n cursor: not-allowed;\n }\n\n .v-date-picker[data-disabled] .v-date-picker-day[data-selected] {\n background: var(--vectis-color-surface-muted);\n color: var(--vectis-color-text-subtle);\n }\n\n .v-date-picker-day--static {\n color: var(--vectis-color-text-subtle);\n cursor: default;\n }\n\n /* A neighbouring day that falls outside the bounds, or is disabled, is struck\n through like any other unavailable date. */\n .v-date-picker-day--static[data-disabled] {\n text-decoration: line-through;\n cursor: not-allowed;\n }\n\n .v-date-picker-day:focus-visible {\n outline: var(--vectis-focus-ring-width) solid var(--vectis-focus-ring-color);\n outline-offset: var(--vectis-focus-ring-offset);\n }\n\n .v-date-picker-day-num {\n line-height: var(--vectis-text-control-leading);\n }\n\n .v-date-picker-dots {\n position: absolute;\n /* Half a dot, below them and between them: the spacing scale has no step that small. */\n inset-block-end: calc(var(--vectis-control-size-date-picker-dot) / 2);\n display: flex;\n gap: calc(var(--vectis-control-size-date-picker-dot) / 2);\n }\n .v-date-picker-dot {\n inline-size: var(--vectis-control-size-date-picker-dot);\n block-size: var(--vectis-control-size-date-picker-dot);\n border-radius: var(--vectis-radius-pill);\n background: var(--date-picker-dot-color, var(--vectis-color-accent));\n }\n .v-date-picker-day[data-selected] .v-date-picker-dot {\n background: var(--vectis-color-text-on-accent);\n }\n\n /* The months and years views. They fill the calendar's width exactly like the days\n grid does: stretched by the flex column, then shared out by 1fr columns. */\n .v-date-picker-view {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: var(--vectis-space-1);\n min-inline-size: calc(7 * var(--date-picker-cell));\n }\n /* The rows ARIA requires inside a grid, made invisible to the layout: with\n `display: contents` the cells remain direct grid items of `.v-date-picker-view`,\n so the columns line up as if the rows were not there. */\n .v-date-picker-view-row {\n display: contents;\n }\n\n .v-date-picker-view--years {\n max-block-size: calc(6 * var(--date-picker-cell));\n overflow-y: auto;\n }\n\n .v-date-picker-view-cell {\n display: flex;\n align-items: center;\n justify-content: center;\n block-size: var(--vectis-control-height-lg);\n border: none;\n border-radius: var(--vectis-radius-pill);\n background: transparent;\n color: inherit;\n font: inherit;\n font-size: var(--vectis-text-body-md-size);\n text-transform: capitalize;\n cursor: pointer;\n transition: background-color var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n .v-date-picker-view-cell:hover:not(:disabled):not([data-selected]) {\n background: var(--vectis-color-surface-muted);\n }\n .v-date-picker-view-cell[data-selected] {\n background: var(--vectis-color-accent);\n color: var(--vectis-color-text-on-accent);\n /* Again state emphasis, not a type role. */\n font-weight: var(--vectis-font-weight-semibold);\n }\n .v-date-picker-view-cell:disabled {\n color: var(--vectis-color-text-subtle);\n cursor: not-allowed;\n }\n .v-date-picker-view-cell:focus-visible {\n outline: var(--vectis-focus-ring-width) solid var(--vectis-focus-ring-color);\n outline-offset: calc(-1 * var(--vectis-focus-ring-width));\n }\n\n .v-date-picker-footer {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: var(--vectis-space-2);\n padding-block-start: var(--vectis-space-2);\n border-block-start: 1px solid var(--vectis-color-border);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-date-picker-day,\n .v-date-picker-view-cell {\n transition: none;\n }\n }\n}\n</style>\n"],"mappings":"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"}
@@ -34,7 +34,7 @@ export type DayStep = {
34
34
  };
35
35
  /**
36
36
  * The step a key produces in the days view, given the key itself, whether Shift is
37
- * held, and how far the focused date sits from the start of its week — the last
37
+ * held, and how far the focused date sits from the start of its week: the last
38
38
  * being what Home and End need in order to land on the right day. Returning
39
39
  * `undefined` means the key is none of this table's business, and the event must be
40
40
  * left alone.
@@ -49,8 +49,8 @@ export declare function dayStep(key: string, shiftKey: boolean, weekdayOffset: n
49
49
  * a flat index over a grid `PICKER_COLUMNS` wide. `undefined` again means the key is
50
50
  * not this table's business.
51
51
  *
52
- * Home and End are deliberately absent: both views are bounded — twelve months, a
53
- * year range fixed by `min` and `max` — and the component clamps whatever comes out,
52
+ * Home and End are deliberately absent: both views are bounded: twelve months, a
53
+ * year range fixed by `min` and `max`, and the component clamps whatever comes out,
54
54
  * so there is no wrapping behaviour left to define.
55
55
  */
56
56
  export declare function gridDelta(key: string): number | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"keyboard.js","names":[],"sources":["../../../src/components/VDatePicker/keyboard.ts"],"sourcesContent":["// @keyboard @core\n/**\n * The pure half of VDatePicker's keyboard: it answers the single question \"how far\n * does this key move?\", and does nothing else. Actually moving the focus, calling\n * `preventDefault` and keeping the result inside the `min`/`max` bounds all stay in\n * the component, where the reactive state lives.\n *\n * It sits in VDatePicker's own folder rather than in `utils/` because it has exactly\n * one consumer, which fails the admission rule for shared code, and because\n * VDatePicker owns the contract (the same reasoning as `VHotkeys/platform.ts` and\n * `VCombobox/infiniteScroll.ts`). Being pure is also what makes this logic testable\n * without mounting anything: the handlers in the component only ever move DOM focus,\n * and jsdom lays nothing out to observe.\n *\n * One number has to be shared rather than repeated: `PICKER_COLUMNS` both cuts the\n * months and years grid into rows and defines what a vertical arrow steps over. Were\n * those two written as separate literals, widening the picker to four columns would\n * leave the arrows moving three cells, with no error anywhere to point at it.\n */\n\n/**\n * How many columns the months and years pickers are laid out in. It drives BOTH the\n * cutting of those grids into rows and the distance a vertical arrow travels: these\n * are the same number, and have to stay so.\n */\nexport const PICKER_COLUMNS = 3\n\nconst DAYS_PER_WEEK = 7\n\n/**\n * How far a key moves in the days view. It comes in two units because a month is not\n * a fixed number of days: `utils/date` provides one helper for each, and the caller\n * picks by looking at which shape it was handed.\n */\nexport type DayStep = { days: number } | { months: number }\n\n/**\n * The step a key produces in the days view, given the key itself, whether Shift is\n * held, and how far the focused date sits from the start of its week — the last\n * being what Home and End need in order to land on the right day. Returning\n * `undefined` means the key is none of this table's business, and the event must be\n * left alone.\n *\n * `weekdayOffset` is passed in rather than worked out here, because it depends on\n * which day the week starts on in the current locale, and resolving that belongs to\n * `utils/date`, not to a keyboard table.\n */\nexport function dayStep(\n key: string,\n shiftKey: boolean,\n weekdayOffset: number,\n): DayStep | undefined {\n switch (key) {\n case 'ArrowRight':\n return { days: 1 }\n case 'ArrowLeft':\n return { days: -1 }\n case 'ArrowDown':\n return { days: DAYS_PER_WEEK }\n case 'ArrowUp':\n return { days: -DAYS_PER_WEEK }\n case 'Home':\n // Negating an offset of zero yields `-0`, and the `|| 0` normalizes it back.\n // `addDays` would not care either way, but a pure function should not hand out\n // a value that `Object.is` reports as different from the zero every caller\n // means.\n return { days: -weekdayOffset || 0 }\n case 'End':\n return { days: DAYS_PER_WEEK - 1 - weekdayOffset }\n case 'PageUp':\n return { months: shiftKey ? -12 : -1 }\n case 'PageDown':\n return { months: shiftKey ? 12 : 1 }\n default:\n return undefined\n }\n}\n\n/**\n * The step a key produces in the months and years views, expressed as a movement of\n * a flat index over a grid `PICKER_COLUMNS` wide. `undefined` again means the key is\n * not this table's business.\n *\n * Home and End are deliberately absent: both views are bounded — twelve months, a\n * year range fixed by `min` and `max` — and the component clamps whatever comes out,\n * so there is no wrapping behaviour left to define.\n */\nexport function gridDelta(key: string): number | undefined {\n switch (key) {\n case 'ArrowRight':\n return 1\n case 'ArrowLeft':\n return -1\n case 'ArrowDown':\n return PICKER_COLUMNS\n case 'ArrowUp':\n return -PICKER_COLUMNS\n default:\n return undefined\n }\n}\n"],"mappings":"AA+CA,SAAgB,EACd,GACA,GACA,GACqB;CACrB,QAAQ,GAAR;EACE,KAAK,cACH,OAAO,EAAE,MAAM,EAAE;EACnB,KAAK,aACH,OAAO,EAAE,MAAM,GAAG;EACpB,KAAK,aACH,OAAO,EAAE,MAAM,EAAc;EAC/B,KAAK,WACH,OAAO,EAAE,MAAM,GAAe;EAChC,KAAK,QAKH,OAAO,EAAE,MAAM,CAAC,KAAiB,EAAE;EACrC,KAAK,OACH,OAAO,EAAE,MAAM,IAAoB,EAAc;EACnD,KAAK,UACH,OAAO,EAAE,QAAQ,IAAW,MAAM,GAAG;EACvC,KAAK,YACH,OAAO,EAAE,QAAQ,IAAW,KAAK,EAAE;EACrC,SACE;CACJ;AACF;AAWA,SAAgB,EAAU,GAAiC;CACzD,QAAQ,GAAR;EACE,KAAK,cACH,OAAO;EACT,KAAK,aACH,OAAO;EACT,KAAK,aACH,OAAA;EACF,KAAK,WACH,OAAO;EACT,SACE;CACJ;AACF"}
1
+ {"version":3,"file":"keyboard.js","names":[],"sources":["../../../src/components/VDatePicker/keyboard.ts"],"sourcesContent":["// @keyboard @core\n/**\n * The pure half of VDatePicker's keyboard: it answers the single question \"how far\n * does this key move?\", and does nothing else. Actually moving the focus, calling\n * `preventDefault` and keeping the result inside the `min`/`max` bounds all stay in\n * the component, where the reactive state lives.\n *\n * It sits in VDatePicker's own folder rather than in `utils/` because it has exactly\n * one consumer, which fails the admission rule for shared code, and because\n * VDatePicker owns the contract (the same reasoning as `VHotkeys/platform.ts` and\n * `VCombobox/infiniteScroll.ts`). Being pure is also what makes this logic testable\n * without mounting anything: the handlers in the component only ever move DOM focus,\n * and jsdom lays nothing out to observe.\n *\n * One number has to be shared rather than repeated: `PICKER_COLUMNS` both cuts the\n * months and years grid into rows and defines what a vertical arrow steps over. Were\n * those two written as separate literals, widening the picker to four columns would\n * leave the arrows moving three cells, with no error anywhere to point at it.\n */\n\n/**\n * How many columns the months and years pickers are laid out in. It drives BOTH the\n * cutting of those grids into rows and the distance a vertical arrow travels: these\n * are the same number, and have to stay so.\n */\nexport const PICKER_COLUMNS = 3\n\nconst DAYS_PER_WEEK = 7\n\n/**\n * How far a key moves in the days view. It comes in two units because a month is not\n * a fixed number of days: `utils/date` provides one helper for each, and the caller\n * picks by looking at which shape it was handed.\n */\nexport type DayStep = { days: number } | { months: number }\n\n/**\n * The step a key produces in the days view, given the key itself, whether Shift is\n * held, and how far the focused date sits from the start of its week: the last\n * being what Home and End need in order to land on the right day. Returning\n * `undefined` means the key is none of this table's business, and the event must be\n * left alone.\n *\n * `weekdayOffset` is passed in rather than worked out here, because it depends on\n * which day the week starts on in the current locale, and resolving that belongs to\n * `utils/date`, not to a keyboard table.\n */\nexport function dayStep(\n key: string,\n shiftKey: boolean,\n weekdayOffset: number,\n): DayStep | undefined {\n switch (key) {\n case 'ArrowRight':\n return { days: 1 }\n case 'ArrowLeft':\n return { days: -1 }\n case 'ArrowDown':\n return { days: DAYS_PER_WEEK }\n case 'ArrowUp':\n return { days: -DAYS_PER_WEEK }\n case 'Home':\n // Negating an offset of zero yields `-0`, and the `|| 0` normalizes it back.\n // `addDays` would not care either way, but a pure function should not hand out\n // a value that `Object.is` reports as different from the zero every caller\n // means.\n return { days: -weekdayOffset || 0 }\n case 'End':\n return { days: DAYS_PER_WEEK - 1 - weekdayOffset }\n case 'PageUp':\n return { months: shiftKey ? -12 : -1 }\n case 'PageDown':\n return { months: shiftKey ? 12 : 1 }\n default:\n return undefined\n }\n}\n\n/**\n * The step a key produces in the months and years views, expressed as a movement of\n * a flat index over a grid `PICKER_COLUMNS` wide. `undefined` again means the key is\n * not this table's business.\n *\n * Home and End are deliberately absent: both views are bounded: twelve months, a\n * year range fixed by `min` and `max`, and the component clamps whatever comes out,\n * so there is no wrapping behaviour left to define.\n */\nexport function gridDelta(key: string): number | undefined {\n switch (key) {\n case 'ArrowRight':\n return 1\n case 'ArrowLeft':\n return -1\n case 'ArrowDown':\n return PICKER_COLUMNS\n case 'ArrowUp':\n return -PICKER_COLUMNS\n default:\n return undefined\n }\n}\n"],"mappings":"AA+CA,SAAgB,EACd,GACA,GACA,GACqB;CACrB,QAAQ,GAAR;EACE,KAAK,cACH,OAAO,EAAE,MAAM,EAAE;EACnB,KAAK,aACH,OAAO,EAAE,MAAM,GAAG;EACpB,KAAK,aACH,OAAO,EAAE,MAAM,EAAc;EAC/B,KAAK,WACH,OAAO,EAAE,MAAM,GAAe;EAChC,KAAK,QAKH,OAAO,EAAE,MAAM,CAAC,KAAiB,EAAE;EACrC,KAAK,OACH,OAAO,EAAE,MAAM,IAAoB,EAAc;EACnD,KAAK,UACH,OAAO,EAAE,QAAQ,IAAW,MAAM,GAAG;EACvC,KAAK,YACH,OAAO,EAAE,QAAQ,IAAW,KAAK,EAAE;EACrC,SACE;CACJ;AACF;AAWA,SAAgB,EAAU,GAAiC;CACzD,QAAQ,GAAR;EACE,KAAK,cACH,OAAO;EACT,KAAK,aACH,OAAO;EACT,KAAK,aACH,OAAA;EACF,KAAK,WACH,OAAO;EACT,SACE;CACJ;AACF"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * The names of the months, as VDatePicker writes them in its header, its months view and
3
+ * the title of its grid.
4
+ *
5
+ * It sits in the component's folder rather than in `utils/date.ts`: there is one consumer,
6
+ * and `utils/date.ts` is in the import closure of every VCalendar component, which would
7
+ * pay for rules only the picker needs, the `VTimeInput/search.ts` argument.
8
+ *
9
+ * Every name is read on a REFERENCE date pinned to `timeZone: 'UTC'`, so a label never
10
+ * depends on the rendering machine's zone and the server agrees with the browser.
11
+ */
12
+ /** The full names of the twelve months, in January-to-December order. */
13
+ export declare function monthNames(locale: string): string[];
14
+ /**
15
+ * Month names shortened for the picker's narrow cells: a name of four characters or
16
+ * fewer is kept whole ("May", "June", "July"), a longer one is cut to three
17
+ * characters followed by a dot ("January" becomes "Jan."). The name is spread with
18
+ * `[...n]` rather than indexed, so that an accented or non-Latin character counts as
19
+ * one character and is never cut in half.
20
+ *
21
+ * TRAP: the cut is not safe everywhere. Vietnamese writes every month "Tháng N", so all
22
+ * twelve come out "Thá.", and Estonian, Czech, Lithuanian or Greek lose a pair; the months
23
+ * view then shows identical cells. When the cut repeats itself, the language's own short
24
+ * names are used instead, which CLDR keeps distinct.
25
+ */
26
+ export declare function monthNamesCompact(locale: string): string[];
27
+ /** The full name of one month, 0 being January. */
28
+ export declare function monthName(locale: string, month0: number): string;
29
+ /**
30
+ * A month and its year written the way the language writes them together: "June 2026",
31
+ * "juin 2026", but "2026年6月" in Japanese and "2026. június" in Hungarian, where gluing the
32
+ * two with a space gets the order wrong. The digits are Latin, as on the year button.
33
+ */
34
+ export declare function monthYearName(locale: string, year: number, month0: number): string;
@@ -0,0 +1,42 @@
1
+ import { memo as e } from "../../utils/memo.js";
2
+ //#region src/components/VDatePicker/names.ts
3
+ function t(e) {
4
+ let t = new Intl.DateTimeFormat(e, n);
5
+ return Array.from({ length: 12 }, (e, n) => t.format(Date.UTC(2021, n, 1)));
6
+ }
7
+ var n = {
8
+ month: "long",
9
+ calendar: "gregory",
10
+ timeZone: "UTC"
11
+ };
12
+ function r(e) {
13
+ let r = t(e).map((e) => {
14
+ let t = [...e];
15
+ return t.length <= 4 ? e : t.slice(0, 3).join("") + ".";
16
+ });
17
+ if (new Set(r).size === 12) return r;
18
+ let i = new Intl.DateTimeFormat(e, {
19
+ ...n,
20
+ month: "short"
21
+ });
22
+ return Array.from({ length: 12 }, (e, t) => i.format(Date.UTC(2021, t, 1)));
23
+ }
24
+ var i = /* @__PURE__ */ new Map();
25
+ function a(t, n) {
26
+ return e(i, `${t}|${JSON.stringify(n)}`, () => new Intl.DateTimeFormat(t, n));
27
+ }
28
+ function o(e, t) {
29
+ return a(e, n).format(Date.UTC(2021, t, 1));
30
+ }
31
+ function s(e, t, r) {
32
+ let i = new Date(Date.UTC(2021, r, 1));
33
+ return i.setUTCFullYear(t), a(e, {
34
+ ...n,
35
+ year: "numeric",
36
+ numberingSystem: "latn"
37
+ }).format(i);
38
+ }
39
+ //#endregion
40
+ export { o as monthName, t as monthNames, r as monthNamesCompact, s as monthYearName };
41
+
42
+ //# sourceMappingURL=names.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"names.js","names":[],"sources":["../../../src/components/VDatePicker/names.ts"],"sourcesContent":["// @core\n/**\n * The names of the months, as VDatePicker writes them in its header, its months view and\n * the title of its grid.\n *\n * It sits in the component's folder rather than in `utils/date.ts`: there is one consumer,\n * and `utils/date.ts` is in the import closure of every VCalendar component, which would\n * pay for rules only the picker needs, the `VTimeInput/search.ts` argument.\n *\n * Every name is read on a REFERENCE date pinned to `timeZone: 'UTC'`, so a label never\n * depends on the rendering machine's zone and the server agrees with the browser.\n */\n\nimport { memo } from '../../utils/memo'\n\n/** The full names of the twelve months, in January-to-December order. */\nexport function monthNames(locale: string): string[] {\n const fmt = new Intl.DateTimeFormat(locale, MONTH_LONG)\n return Array.from({ length: 12 }, (_, i) => fmt.format(Date.UTC(2021, i, 1)))\n}\n\n/**\n * The options every month name is read with. `calendar: 'gregory'` is not optional: the\n * grid is Gregorian, and a locale whose default calendar is another one (fa-IR, or any tag\n * carrying `-u-ca-islamic`) would otherwise title a January grid with the month of ITS\n * calendar that happens to hold the 1st, \"Dey\" in Persian.\n */\nconst MONTH_LONG = { month: 'long', calendar: 'gregory', timeZone: 'UTC' } as const\n\n/**\n * Month names shortened for the picker's narrow cells: a name of four characters or\n * fewer is kept whole (\"May\", \"June\", \"July\"), a longer one is cut to three\n * characters followed by a dot (\"January\" becomes \"Jan.\"). The name is spread with\n * `[...n]` rather than indexed, so that an accented or non-Latin character counts as\n * one character and is never cut in half.\n *\n * TRAP: the cut is not safe everywhere. Vietnamese writes every month \"Tháng N\", so all\n * twelve come out \"Thá.\", and Estonian, Czech, Lithuanian or Greek lose a pair; the months\n * view then shows identical cells. When the cut repeats itself, the language's own short\n * names are used instead, which CLDR keeps distinct.\n */\nexport function monthNamesCompact(locale: string): string[] {\n const cut = monthNames(locale).map((n) => {\n const chars = [...n]\n return chars.length <= 4 ? n : chars.slice(0, 3).join('') + '.'\n })\n if (new Set(cut).size === 12) return cut\n const fmt = new Intl.DateTimeFormat(locale, { ...MONTH_LONG, month: 'short' })\n return Array.from({ length: 12 }, (_, i) => fmt.format(Date.UTC(2021, i, 1)))\n}\n\n/**\n * One formatter kept per locale and set of options, for the lifetime of the module: the\n * two functions below are asked one month at a time, and building an `Intl` formatter\n * costs far more than using one.\n */\nconst formatters = new Map<string, Intl.DateTimeFormat>()\n\nfunction formatterFor(locale: string, options: Intl.DateTimeFormatOptions): Intl.DateTimeFormat {\n return memo(\n formatters,\n `${locale}|${JSON.stringify(options)}`,\n () => new Intl.DateTimeFormat(locale, options),\n )\n}\n\n/** The full name of one month, 0 being January. */\nexport function monthName(locale: string, month0: number): string {\n return formatterFor(locale, MONTH_LONG).format(Date.UTC(2021, month0, 1))\n}\n\n/**\n * A month and its year written the way the language writes them together: \"June 2026\",\n * \"juin 2026\", but \"2026年6月\" in Japanese and \"2026. június\" in Hungarian, where gluing the\n * two with a space gets the order wrong. The digits are Latin, as on the year button.\n */\nexport function monthYearName(locale: string, year: number, month0: number): string {\n const at = new Date(Date.UTC(2021, month0, 1))\n at.setUTCFullYear(year)\n return formatterFor(locale, {\n ...MONTH_LONG,\n year: 'numeric',\n numberingSystem: 'latn',\n }).format(at)\n}\n"],"mappings":";;AAgBA,SAAgB,EAAW,GAA0B;CACnD,IAAM,IAAM,IAAI,KAAK,eAAe,GAAQ,CAAU;CACtD,OAAO,MAAM,KAAK,EAAE,QAAQ,GAAG,IAAI,GAAG,MAAM,EAAI,OAAO,KAAK,IAAI,MAAM,GAAG,CAAC,CAAC,CAAC;AAC9E;AAQA,IAAM,IAAa;CAAE,OAAO;CAAQ,UAAU;CAAW,UAAU;AAAM;AAczE,SAAgB,EAAkB,GAA0B;CAC1D,IAAM,IAAM,EAAW,CAAM,CAAC,CAAC,KAAK,MAAM;EACxC,IAAM,IAAQ,CAAC,GAAG,CAAC;EACnB,OAAO,EAAM,UAAU,IAAI,IAAI,EAAM,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI;CAC9D,CAAC;CACD,IAAI,IAAI,IAAI,CAAG,CAAC,CAAC,SAAS,IAAI,OAAO;CACrC,IAAM,IAAM,IAAI,KAAK,eAAe,GAAQ;EAAE,GAAG;EAAY,OAAO;CAAQ,CAAC;CAC7E,OAAO,MAAM,KAAK,EAAE,QAAQ,GAAG,IAAI,GAAG,MAAM,EAAI,OAAO,KAAK,IAAI,MAAM,GAAG,CAAC,CAAC,CAAC;AAC9E;AAOA,IAAM,oBAAa,IAAI,IAAiC;AAExD,SAAS,EAAa,GAAgB,GAA0D;CAC9F,OAAO,EACL,GACA,GAAG,EAAO,GAAG,KAAK,UAAU,CAAO,WAC7B,IAAI,KAAK,eAAe,GAAQ,CAAO,CAC/C;AACF;AAGA,SAAgB,EAAU,GAAgB,GAAwB;CAChE,OAAO,EAAa,GAAQ,CAAU,CAAC,CAAC,OAAO,KAAK,IAAI,MAAM,GAAQ,CAAC,CAAC;AAC1E;AAOA,SAAgB,EAAc,GAAgB,GAAc,GAAwB;CAClF,IAAM,IAAK,IAAI,KAAK,KAAK,IAAI,MAAM,GAAQ,CAAC,CAAC;CAE7C,OADA,EAAG,eAAe,CAAI,GACf,EAAa,GAAQ;EAC1B,GAAG;EACH,MAAM;EACN,iBAAiB;CACnB,CAAC,CAAC,CAAC,OAAO,CAAE;AACd"}
@@ -1,2 +1,2 @@
1
1
  @layer vectis.reset, vectis.tokens, vectis.components, vectis.utilities;
2
- @layer vectis.components{.v-dialog{--dialog-width:var(--vectis-control-size-dialog-width);inline-size:var(--dialog-width);max-inline-size:calc(100dvi - 2 * var(--vectis-space-4));max-block-size:calc(100dvb - 2 * var(--vectis-space-4));border-radius:var(--vectis-radius-overlay);background:var(--vectis-color-surface-overlay);color:var(--vectis-color-text);box-shadow:var(--vectis-shadow-xl);font-family:var(--vectis-text-family);border:none;flex-direction:column;margin:auto;padding:0;display:flex;overflow:hidden}.v-dialog:not([open]){display:none}.v-dialog:focus-visible{outline:none}.v-dialog-scroll{flex-direction:column;flex:auto;min-block-size:0;display:flex;overflow-y:auto;container-type:scroll-state}.v-dialog-edge{background:0 0;flex:none;block-size:1px;position:sticky}.v-dialog-edge--top{margin-block-end:-1px;inset-block-start:0}.v-dialog-edge--bottom{margin-block-start:-1px;inset-block-end:0}.v-dialog-header{justify-content:space-between;align-items:flex-start;gap:var(--vectis-space-4);padding:var(--vectis-space-6) var(--vectis-space-6) var(--vectis-space-3);flex:none;display:flex}.v-dialog-titles{flex-direction:column;min-inline-size:0;display:flex}.v-dialog-header-actions{align-items:center;gap:var(--vectis-space-1);margin-block-start:calc(-1 * var(--vectis-space-1));margin-inline-end:calc(-1 * var(--vectis-space-2));display:flex}.v-dialog-body{padding:var(--vectis-space-1) var(--vectis-space-6) var(--vectis-space-3);font-size:var(--vectis-text-body-md-size);line-height:var(--vectis-text-body-md-leading);flex:1 0 auto}.v-dialog-footer{justify-content:flex-end;align-items:center;gap:var(--vectis-space-3);padding:var(--vectis-space-3) var(--vectis-space-6) var(--vectis-space-6);flex-wrap:wrap;flex:none;display:flex}@container scroll-state(scrollable:top){.v-dialog-edge--top{background:var(--vectis-color-border)}}@container scroll-state(scrollable:bottom){.v-dialog-edge--bottom{background:var(--vectis-color-border)}}.v-dialog{transition:opacity var(--vectis-duration-base) var(--vectis-ease-default), transform var(--vectis-duration-base) var(--vectis-ease-default)}@starting-style{.v-dialog[open]{opacity:0;transform:scale(.97)}}.v-dialog::backdrop{background:var(--vectis-color-backdrop);transition:opacity var(--vectis-duration-base) var(--vectis-ease-default)}@starting-style{.v-dialog[open]::backdrop{opacity:0}}@media (prefers-reduced-motion:reduce){.v-dialog,.v-dialog::backdrop{transition:none}}}
2
+ @layer vectis.components{.v-dialog{--dialog-width:var(--vectis-control-size-dialog-width);inline-size:var(--dialog-width);max-inline-size:calc(100dvi - 2 * var(--vectis-space-4));max-block-size:calc(100dvb - 2 * var(--vectis-space-4));border-radius:var(--vectis-radius-overlay);background:var(--vectis-color-surface-overlay);color:var(--vectis-color-text);box-shadow:var(--vectis-shadow-xl);font-family:var(--vectis-text-family);border:none;flex-direction:column;margin:auto;padding:0;display:flex;overflow:hidden}.v-dialog:not([open]){display:none}.v-dialog:focus-visible{outline:none}.v-dialog-scroll{overscroll-behavior:contain;flex-direction:column;flex:auto;min-block-size:0;display:flex;overflow-y:auto;container-type:scroll-state}.v-dialog-edge{background:0 0;flex:none;block-size:1px;position:sticky}.v-dialog-edge--top{margin-block-end:-1px;inset-block-start:0}.v-dialog-edge--bottom{margin-block-start:-1px;inset-block-end:0}.v-dialog-header{justify-content:space-between;align-items:flex-start;gap:var(--vectis-space-4);padding:var(--vectis-space-6) var(--vectis-space-6) var(--vectis-space-3);flex:none;display:flex}.v-dialog-titles{flex-direction:column;min-inline-size:0;display:flex}.v-dialog-header-actions{align-items:center;gap:var(--vectis-space-1);margin-block-start:calc(-1 * var(--vectis-space-1));margin-inline-end:calc(-1 * var(--vectis-space-2));display:flex}.v-dialog-body{padding:var(--vectis-space-1) var(--vectis-space-6) var(--vectis-space-3);font-size:var(--vectis-text-body-md-size);line-height:var(--vectis-text-body-md-leading);flex:1 0 auto}.v-dialog-footer{justify-content:flex-end;align-items:center;gap:var(--vectis-space-3);padding:var(--vectis-space-3) var(--vectis-space-6) var(--vectis-space-6);flex-wrap:wrap;flex:none;display:flex}@container scroll-state(scrollable:top){.v-dialog-edge--top{background:var(--vectis-color-border)}}@container scroll-state(scrollable:bottom){.v-dialog-edge--bottom{background:var(--vectis-color-border)}}.v-dialog{transition:opacity var(--vectis-duration-base) var(--vectis-ease-default), transform var(--vectis-duration-base) var(--vectis-ease-default)}@starting-style{.v-dialog[open]{opacity:0;transform:scale(.97)}}.v-dialog::backdrop{background:var(--vectis-color-backdrop);transition:opacity var(--vectis-duration-base) var(--vectis-ease-default)}@starting-style{.v-dialog[open]::backdrop{opacity:0}}@media (prefers-reduced-motion:reduce){.v-dialog,.v-dialog::backdrop{transition:none}}@media (forced-colors:active){.v-dialog{outline:1px solid canvastext}}}
@@ -16,8 +16,8 @@ interface DialogProps {
16
16
  width?: number | string;
17
17
  /**
18
18
  * What kind of dialog this is. `alertdialog` is for one that must be answered
19
- * explicitly, and it makes screen readers announce it more insistently — see
20
- * VDialogAlert, which is exactly that.
19
+ * explicitly, and it makes screen readers announce it more insistently. VDialogAlert is
20
+ * exactly that.
21
21
  */
22
22
  role?: DialogRole;
23
23
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"VDialog.js","names":[],"sources":["../../../src/components/VDialog/VDialog.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @core\n/**\n * A modal dialog: it takes over the page until the reader answers it.\n *\n * Almost everything that makes a modal correct comes free with the native `<dialog>`\n * element opened as a modal — it is drawn above the whole page, the background is\n * dimmed and made unusable, the focus is trapped inside it and handed back to the\n * trigger on closing, and whether a click outside or Escape dismisses it is declared\n * with an attribute rather than coded.\n *\n * The ONLY behavioural JavaScript is the bridge between `v-model:open` and the two\n * methods the platform offers no declarative equivalent for: opening as a modal, and\n * closing.\n */\n\nimport { computed, nextTick, onMounted, ref, useAttrs, useId, watch } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { close as closeIcon } from '../VIcon/icons/close'\nimport VIconButton from '../VIconButton/VIconButton.vue'\nimport VTypography from '../VTypography/VTypography.vue'\nimport { useMessages } from '../../i18n/state'\nimport { cssSize } from '../../utils/css'\n\n/** How assistive technology announces the dialog. */\nexport type DialogRole = 'dialog' | 'alertdialog'\n\ninterface DialogProps {\n /**\n * The title of the dialog, which also names it for assistive technology. It is\n * ignored when the `#header` slot replaces the whole header.\n */\n title?: string\n /** A line under the title, explaining what the dialog is asking. */\n subtitle?: string\n /**\n * How wide the dialog is: a number is read as pixels, a string as any CSS length. Left\n * out, it takes the `--vectis-control-size-dialog-width` token, 400px by default. It is\n * never allowed to exceed the width of the viewport.\n */\n width?: number | string\n /**\n * What kind of dialog this is. `alertdialog` is for one that must be answered\n * explicitly, and it makes screen readers announce it more insistently — see\n * VDialogAlert, which is exactly that.\n */\n role?: DialogRole\n /**\n * Takes the close cross out of the header, leaving the reader with Escape, the\n * backdrop and whatever the footer offers.\n */\n hideClose?: boolean\n /** Stops a click outside the dialog from closing it. */\n persistentBackdrop?: boolean\n /**\n * Stops the Escape key from closing the dialog. Note that refusing Escape while the\n * backdrop still closes cannot be expressed natively, so both routes are then\n * allowed.\n */\n persistentEscape?: boolean\n /** What the close cross does, in words. It falls back to the design system dictionary. */\n closeLabel?: string\n}\n\nconst props = withDefaults(defineProps<DialogProps>(), {\n title: undefined,\n subtitle: undefined,\n width: undefined,\n role: 'dialog',\n hideClose: false,\n persistentBackdrop: false,\n persistentEscape: false,\n closeLabel: undefined,\n})\n\nconst m = useMessages()\nconst resolvedCloseLabel = computed(() => props.closeLabel ?? m.value.common.close)\n\n/**\n * Whether the dialog is showing. It starts closed, and it is BIDIRECTIONAL: the browser\n * writes back to it whenever the dialog closes on its own, through Escape or the backdrop,\n * so a consumer never has to reset it by hand.\n */\nconst open = defineModel<boolean>('open', { default: false })\n\n/** What the trigger has to carry: the click that opens the dialog, and the fact that it does. */\nexport type DialogTriggerProps = {\n onClick: () => void\n 'aria-haspopup': 'dialog'\n}\n\ndefineSlots<{\n /** The body of the dialog. This is the part that scrolls when there is too much of it. */\n default(): unknown\n /** Replaces the title and subtitle block with content of your own. */\n header?(): unknown\n /** Extra controls in the header, placed before the close cross: a menu, a full-screen toggle. */\n 'header-actions'?(): unknown\n /** The buttons at the foot of the dialog. */\n footer?(): unknown\n /**\n * The button that opens the dialog. Bind the `triggerProps` it receives onto it. It\n * stays rendered at all times, unlike the dialog itself.\n */\n trigger?(props: { triggerProps: DialogTriggerProps }): unknown\n}>()\n\ndefineOptions({ inheritAttrs: false })\n\nconst attrs = useAttrs()\nconst dialogEl = ref<HTMLDialogElement | null>(null)\nconst titleId = useId()\nconst subtitleId = useId()\n\n/**\n * Which dismissals the browser itself accepts, declared as an attribute rather than\n * handled in code: everything, Escape alone, or nothing.\n *\n * One combination cannot be expressed that way — a click outside allowed while Escape\n * is not — and it falls back to allowing both. Nothing in the design system asks for\n * it, and it would be a strange thing to want.\n */\nconst closedby = computed(() =>\n props.persistentBackdrop ? (props.persistentEscape ? 'none' : 'closerequest') : 'any',\n)\n\n// @fallback\n// The `closedby` attribute is newer than the type definitions shipped with\n// TypeScript, so writing it directly in the template would be reported as an unknown\n// attribute. Passing it inside a bound object goes through the same path as any\n// forwarded attribute, which is not checked element by element. Vue still merges the\n// `class` and `style` it may contain with the static ones below.\nconst rootAttrs = computed(() => ({ ...attrs, closedby: closedby.value }))\n\n// The dialog and its content only exist while it is open, which also spares the page\n// whatever heavy thing it contains. Every opening therefore builds a BRAND NEW\n// element, so it is always opened as a modal from a clean slate, and closing removes\n// it entirely — nothing is left behind to swallow clicks, and reopening cannot race\n// with a closing that is still finishing. The trigger, by contrast, stays rendered at\n// all times.\nconst rendered = ref(open.value)\n\n/**\n * Settles once the dialog opened by the latest change of `open` is actually showing. The\n * opening waits for the element to be rendered, so it is always a tick behind the model.\n */\nlet opening: Promise<void> = Promise.resolve()\n\nfunction show(): Promise<void> {\n open.value = true\n // The watcher below only runs when the scheduler flushes, so `opening` is read from a\n // tick later: read at once, it would still be the promise of the previous opening.\n return nextTick(() => opening)\n}\n\nfunction requestClose() {\n // Closing the element is enough: the browser then fires its own close event, which\n // is what puts the model back in step below.\n dialogEl.value?.close()\n}\n\nconst triggerProps = computed<DialogTriggerProps>(() => ({\n onClick: show,\n 'aria-haspopup': 'dialog',\n}))\n\n// The `<dialog>` element is asymmetric in a way that shapes this whole bridge: it\n// announces every closing with an event, but announces nothing at all when it opens —\n// where a popover reports both. So the two directions are not written the same way:\n//\n// - opening: render the element, then, once Vue has actually put it in the document,\n// open it as a modal;\n// - closing: whatever closed it — the cross, our own call, Escape, a click outside —\n// the browser's close event is what puts the model back in step, and only then is\n// the element removed.\nwatch(open, (value) => {\n if (value) {\n rendered.value = true\n // the brand new <dialog> has to exist before it can be opened\n opening = nextTick(() => dialogEl.value?.showModal())\n } else {\n dialogEl.value?.close()\n rendered.value = false\n }\n})\n\n// @ssr\nonMounted(() => {\n // A watcher does not run during the server render, so a dialog asked to be open from\n // the start would never be opened. The element is already there — the flag above was\n // initialized from the model — it just has to be told to show itself.\n if (open.value) dialogEl.value?.showModal()\n})\n\n// The browser's own close event, whatever caused it, is what brings the model back in\n// step with reality.\nfunction onClose() {\n open.value = false\n}\n\ndefineExpose({\n /**\n * Opens the dialog, exactly as setting `open` does. The opening lands on the next tick,\n * once the element has been rendered: `el` is still null right after the call, and the\n * promise returned settles once the dialog is showing.\n */\n show,\n /**\n * Closes the dialog. It closes unconditionally, `persistentEscape` and\n * `persistentBackdrop` governing only the two routes the reader can take.\n */\n close: requestClose,\n /** The `<dialog>` element. It is null while closed: each opening builds a fresh one. */\n el: dialogEl,\n})\n</script>\n\n<template>\n <slot name=\"trigger\" :trigger-props=\"triggerProps\" />\n <dialog\n v-if=\"rendered\"\n ref=\"dialogEl\"\n v-bind=\"rootAttrs\"\n class=\"v-dialog\"\n :style=\"{ '--dialog-width': cssSize(width) }\"\n :role=\"role === 'alertdialog' ? 'alertdialog' : undefined\"\n :aria-labelledby=\"title ? titleId : undefined\"\n :aria-describedby=\"subtitle ? subtitleId : undefined\"\n @close=\"onClose\"\n >\n <!--\n The header and the footer stay put while only the body scrolls, so the scrollbar\n is confined to the body and never runs along them.\n\n The lines that appear under the header and above the footer once the body is\n scrolled are drawn by two sentinels stuck INSIDE the scrolling area, and not by\n the header and footer themselves: a container query can only style what is inside\n the container it asks about, never a sibling of it.\n -->\n <header class=\"v-dialog-header\">\n <slot name=\"header\">\n <div class=\"v-dialog-titles\">\n <VTypography\n v-if=\"title\"\n :id=\"titleId\"\n as=\"h2\"\n variant=\"heading-3\"\n class=\"v-dialog-title\"\n >\n {{ title }}\n </VTypography>\n <VTypography\n v-if=\"subtitle\"\n :id=\"subtitleId\"\n variant=\"subtitle\"\n tone=\"muted\"\n class=\"v-dialog-subtitle\"\n >\n {{ subtitle }}\n </VTypography>\n </div>\n </slot>\n <div v-if=\"!hideClose || $slots['header-actions']\" class=\"v-dialog-header-actions\">\n <slot name=\"header-actions\" />\n <VIconButton\n v-if=\"!hideClose\"\n class=\"v-dialog-close\"\n :label=\"resolvedCloseLabel\"\n variant=\"ghost\"\n tone=\"neutral\"\n size=\"sm\"\n @click=\"requestClose\"\n >\n <VIcon :name=\"closeIcon\" />\n </VIconButton>\n </div>\n </header>\n <div class=\"v-dialog-scroll\">\n <span class=\"v-dialog-edge v-dialog-edge--top\" aria-hidden=\"true\" />\n <div class=\"v-dialog-body\">\n <slot />\n </div>\n <span class=\"v-dialog-edge v-dialog-edge--bottom\" aria-hidden=\"true\" />\n </div>\n <footer v-if=\"$slots.footer\" class=\"v-dialog-footer\">\n <slot name=\"footer\" />\n </footer>\n </dialog>\n</template>\n\n<style>\n@layer vectis.components {\n .v-dialog {\n /* The width comes from the prop, set inline, or from the token when there is none.\n Whatever it asks for, the dialog is never allowed past the viewport, margins included.\n\n TRAP — the token is declared ON the element rather than written as a `var()` fallback.\n A custom property inherits, and a dialog opened from inside another one is its DOM\n descendant: with a fallback, an alert confirming something in an 800px dialog would\n read that dialog's inline width and open 800px wide itself, with no error anywhere. */\n --dialog-width: var(--vectis-control-size-dialog-width);\n inline-size: var(--dialog-width);\n max-inline-size: calc(100dvi - 2 * var(--vectis-space-4));\n max-block-size: calc(100dvb - 2 * var(--vectis-space-4));\n /* This puts the dialog back in the middle of the screen. The browser centres a\n modal with an automatic margin, which the design system's own reset — where\n every element loses its margins — had removed; restoring it here works because\n the component layer is stronger than the reset one. */\n margin: auto;\n /* The header and footer stay put while only the body scrolls, and hiding the\n overflow is what keeps the content inside the rounded corners. */\n display: flex;\n flex-direction: column;\n overflow: hidden;\n padding: 0;\n border: none;\n border-radius: var(--vectis-radius-overlay);\n background: var(--vectis-color-surface-overlay);\n color: var(--vectis-color-text);\n box-shadow: var(--vectis-shadow-xl);\n font-family: var(--vectis-text-family);\n }\n\n /*\n * An indispensable guard. The browser hides a closed dialog with a rule of its own,\n * but any display we declare above beats it — so without this, a closed dialog would\n * sit in the page at the top left, swallowing clicks.\n *\n * It also covers the two moments where the element exists without being open yet: the\n * frame between rendering it and opening it, and the server-rendered markup. The\n * popovers have the very same guard.\n */\n .v-dialog:not([open]) {\n display: none;\n }\n\n /* Opening a modal puts the focus on the dialog itself. No ring is drawn around the\n whole thing for that: the focus a reader needs to see is the one on the controls\n inside. */\n .v-dialog:focus-visible {\n outline: none;\n }\n\n .v-dialog-scroll {\n /* The ONLY part that scrolls. It takes whatever room is left between the header\n and the footer, which is what keeps the scrollbar confined to it. The zero\n minimum is load-bearing: without it a flex item refuses to shrink below its\n content, and nothing would ever scroll. */\n flex: 1 1 auto;\n min-block-size: 0;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n /* This makes the box something its descendants can ask questions about — namely\n whether there is content hidden above or below. It adds no containment of size. */\n container-type: scroll-state;\n }\n\n /*\n * The two sentinels: hairlines stuck to the top and the bottom of the scrolling\n * area, and descendants of it, which is what allows them to ask about its scroll\n * state. Their negative margins mean they occupy no space at all. They are\n * transparent until the rules further down reveal them.\n */\n .v-dialog-edge {\n flex: none;\n block-size: 1px;\n position: sticky;\n background: transparent;\n }\n\n .v-dialog-edge--top {\n inset-block-start: 0;\n margin-block-end: -1px;\n }\n\n .v-dialog-edge--bottom {\n inset-block-end: 0;\n margin-block-start: -1px;\n }\n\n .v-dialog-header {\n flex: none; /* stays at the top, outside whatever scrolls */\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: var(--vectis-space-4);\n padding: var(--vectis-space-6) var(--vectis-space-6) var(--vectis-space-3);\n }\n\n .v-dialog-titles {\n display: flex;\n flex-direction: column;\n min-inline-size: 0;\n }\n\n /* The title and the subtitle are rendered by VTypography, which carries their type.\n Their classes remain as hooks, for a consumer's overrides and for the tests. */\n\n .v-dialog-header-actions {\n display: flex;\n align-items: center;\n gap: var(--vectis-space-1);\n /* The cross is a button, so it carries invisible padding of its own; pulling the\n row back by that amount is what makes the glyph line up with the header's edge\n rather than floating inside it. */\n margin-block-start: calc(-1 * var(--vectis-space-1));\n margin-inline-end: calc(-1 * var(--vectis-space-2));\n }\n\n .v-dialog-body {\n /* Short content is stretched to fill the space, so the footer stays at the bottom\n of the dialog rather than floating halfway up; long content keeps its natural\n height, overflows, and is what scrolls. */\n flex: 1 0 auto;\n padding: var(--vectis-space-1) var(--vectis-space-6) var(--vectis-space-3);\n font-size: var(--vectis-text-body-md-size);\n line-height: var(--vectis-text-body-md-leading);\n }\n\n .v-dialog-footer {\n flex: none; /* stays at the bottom, outside whatever scrolls */\n display: flex;\n align-items: center;\n justify-content: flex-end;\n flex-wrap: wrap;\n gap: var(--vectis-space-3);\n padding: var(--vectis-space-3) var(--vectis-space-6) var(--vectis-space-6);\n }\n\n /*\n * The lines only appear when they mean something. Asking the scrolling area whether\n * it can still be scrolled upwards tells us content is hidden ABOVE, so the line\n * under the header is shown; the same question downwards reveals the one above the\n * footer. In other words each line is drawn exactly when content is passing behind\n * the edge it marks.\n *\n * This kind of query is Chrome 133 and later for now. Where it is missing the\n * sentinels simply stay transparent, which is the intended fallback.\n */\n @container scroll-state(scrollable: top) {\n .v-dialog-edge--top {\n background: var(--vectis-color-border);\n }\n }\n\n @container scroll-state(scrollable: bottom) {\n .v-dialog-edge--bottom {\n background: var(--vectis-color-border);\n }\n }\n\n /*\n * The dialog animates on the way IN and not on the way out. Since it is removed from\n * the page the moment it closes, there is nothing left to animate out — that is the\n * price of the clean slate the lazy rendering buys, and it also spares the extra\n * declarations an exit animation would need.\n *\n * The starting values below are where a freshly rendered dialog begins, before\n * settling into its open state.\n */\n .v-dialog {\n transition:\n opacity var(--vectis-duration-base) var(--vectis-ease-default),\n transform var(--vectis-duration-base) var(--vectis-ease-default);\n }\n\n @starting-style {\n .v-dialog[open] {\n opacity: 0;\n transform: scale(0.97);\n }\n }\n\n .v-dialog::backdrop {\n background: var(--vectis-color-backdrop);\n transition: opacity var(--vectis-duration-base) var(--vectis-ease-default);\n }\n\n @starting-style {\n .v-dialog[open]::backdrop {\n opacity: 0;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-dialog,\n .v-dialog::backdrop {\n transition: none;\n }\n }\n}\n</style>\n"],"mappings":""}
1
+ {"version":3,"file":"VDialog.js","names":[],"sources":["../../../src/components/VDialog/VDialog.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @core\n/**\n * A modal dialog: it takes over the page until the reader answers it.\n *\n * Almost everything that makes a modal correct comes free with the native `<dialog>`\n * element opened as a modal — it is drawn above the whole page, the background is\n * dimmed and made unusable, the focus is trapped inside it and handed back to the\n * trigger on closing, and whether a click outside or Escape dismisses it is declared\n * with an attribute rather than coded.\n *\n * The ONLY behavioural JavaScript is the bridge between `v-model:open` and the two\n * methods the platform offers no declarative equivalent for: opening as a modal, and\n * closing.\n */\n\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, useAttrs, useId, watch } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { close as closeIcon } from '../VIcon/icons/close'\nimport VIconButton from '../VIconButton/VIconButton.vue'\nimport VTypography from '../VTypography/VTypography.vue'\nimport { useMessages } from '../../i18n/state'\nimport { cssSize } from '../../utils/css'\n\n/** How assistive technology announces the dialog. */\nexport type DialogRole = 'dialog' | 'alertdialog'\n\ninterface DialogProps {\n /**\n * The title of the dialog, which also names it for assistive technology. It is\n * ignored when the `#header` slot replaces the whole header.\n */\n title?: string\n /** A line under the title, explaining what the dialog is asking. */\n subtitle?: string\n /**\n * How wide the dialog is: a number is read as pixels, a string as any CSS length. Left\n * out, it takes the `--vectis-control-size-dialog-width` token, 400px by default. It is\n * never allowed to exceed the width of the viewport.\n */\n width?: number | string\n /**\n * What kind of dialog this is. `alertdialog` is for one that must be answered\n * explicitly, and it makes screen readers announce it more insistently. VDialogAlert is\n * exactly that.\n */\n role?: DialogRole\n /**\n * Takes the close cross out of the header, leaving the reader with Escape, the\n * backdrop and whatever the footer offers.\n */\n hideClose?: boolean\n /** Stops a click outside the dialog from closing it. */\n persistentBackdrop?: boolean\n /**\n * Stops the Escape key from closing the dialog. Note that refusing Escape while the\n * backdrop still closes cannot be expressed natively, so both routes are then\n * allowed.\n */\n persistentEscape?: boolean\n /** What the close cross does, in words. It falls back to the design system dictionary. */\n closeLabel?: string\n}\n\nconst props = withDefaults(defineProps<DialogProps>(), {\n title: undefined,\n subtitle: undefined,\n width: undefined,\n role: 'dialog',\n hideClose: false,\n persistentBackdrop: false,\n persistentEscape: false,\n closeLabel: undefined,\n})\n\nconst m = useMessages()\nconst resolvedCloseLabel = computed(() => props.closeLabel ?? m.value.common.close)\n\n/**\n * Whether the dialog is showing. It starts closed, and it is BIDIRECTIONAL: the browser\n * writes back to it whenever the dialog closes on its own, through Escape or the backdrop,\n * so a consumer never has to reset it by hand.\n */\nconst open = defineModel<boolean>('open', { default: false })\n\n/** What the trigger has to carry: the click that opens the dialog, and the fact that it does. */\nexport type DialogTriggerProps = {\n onClick: () => void\n 'aria-haspopup': 'dialog'\n}\n\ndefineSlots<{\n /** The body of the dialog. This is the part that scrolls when there is too much of it. */\n default(): unknown\n /** Replaces the title and subtitle block with content of your own. */\n header?(): unknown\n /** Extra controls in the header, placed before the close cross: a menu, a full-screen toggle. */\n 'header-actions'?(): unknown\n /** The buttons at the foot of the dialog. */\n footer?(): unknown\n /**\n * The button that opens the dialog. Bind the `triggerProps` it receives onto it. It\n * stays rendered at all times, unlike the dialog itself.\n */\n trigger?(props: { triggerProps: DialogTriggerProps }): unknown\n}>()\n\ndefineOptions({ inheritAttrs: false })\n\nconst attrs = useAttrs()\nconst dialogEl = ref<HTMLDialogElement | null>(null)\nconst titleId = useId()\nconst subtitleId = useId()\n\n/**\n * Which dismissals the browser itself accepts, declared as an attribute rather than\n * handled in code: everything, Escape alone, or nothing.\n *\n * One combination cannot be expressed that way — a click outside allowed while Escape\n * is not — and it falls back to allowing both. Nothing in the design system asks for\n * it, and it would be a strange thing to want.\n */\nconst closedby = computed(() =>\n props.persistentBackdrop ? (props.persistentEscape ? 'none' : 'closerequest') : 'any',\n)\n\n// @fallback\n// The `closedby` attribute is newer than the type definitions shipped with\n// TypeScript, so writing it directly in the template would be reported as an unknown\n// attribute. Passing it inside a bound object goes through the same path as any\n// forwarded attribute, which is not checked element by element. Vue still merges the\n// `class` and `style` it may contain with the static ones below.\nconst rootAttrs = computed(() => ({ ...attrs, closedby: closedby.value }))\n\n// The dialog and its content only exist while it is open, which also spares the page\n// whatever heavy thing it contains. Every opening therefore builds a BRAND NEW\n// element, so it is always opened as a modal from a clean slate, and closing removes\n// it entirely — nothing is left behind to swallow clicks, and reopening cannot race\n// with a closing that is still finishing. The trigger, by contrast, stays rendered at\n// all times.\nconst rendered = ref(open.value)\n\n/**\n * Settles once the dialog opened by the latest change of `open` is actually showing. The\n * opening waits for the element to be rendered, so it is always a tick behind the model.\n */\nlet opening: Promise<void> = Promise.resolve()\n\nfunction show(): Promise<void> {\n open.value = true\n // The watcher below only runs when the scheduler flushes, so `opening` is read from a\n // tick later: read at once, it would still be the promise of the previous opening.\n return nextTick(() => opening)\n}\n\nfunction requestClose() {\n // Closing the element is enough: the browser then fires its own close event, which\n // is what puts the model back in step below.\n dialogEl.value?.close()\n}\n\nconst triggerProps = computed<DialogTriggerProps>(() => ({\n onClick: show,\n 'aria-haspopup': 'dialog',\n}))\n\n// The `<dialog>` element is asymmetric in a way that shapes this whole bridge: it\n// announces every closing with an event, but announces nothing at all when it opens —\n// where a popover reports both. So the two directions are not written the same way:\n//\n// - opening: render the element, then, once Vue has actually put it in the document,\n// open it as a modal;\n// - closing: whatever closed it — the cross, our own call, Escape, a click outside —\n// the browser's close event is what puts the model back in step, and only then is\n// the element removed.\nwatch(open, (value) => {\n if (value) {\n rendered.value = true\n // the brand new <dialog> has to exist before it can be opened\n opening = nextTick(() => dialogEl.value?.showModal())\n } else {\n dialogEl.value?.close()\n rendered.value = false\n }\n})\n\n// @ssr\nonMounted(() => {\n // A watcher does not run during the server render, so a dialog asked to be open from\n // the start would never be opened. The element is already there — the flag above was\n // initialized from the model — it just has to be told to show itself.\n if (open.value) dialogEl.value?.showModal()\n})\n\n// The browser's own close event, whatever caused it, is what brings the model back in\n// step with reality.\n//\n// TRAP — only the element on screen may do it. A close event is queued as a TASK, so the\n// one fired by the element a quick close-and-reopen has just replaced arrives after the new\n// element exists, and without the check it closed the dialog that had just opened.\nfunction onClose(event: Event) {\n if (event.target !== dialogEl.value) return\n open.value = false\n}\n\n// @core\n// An open dialog removed with its parent (a `v-if`, a route change) runs no close steps,\n// so no close event would come: the model is handed back closed here, or it stayed `true`\n// and the dialog reopened by itself the next time its parent was shown.\nonBeforeUnmount(() => {\n if (open.value) open.value = false\n})\n\n// @fallback\n/*\n * `closedby` is what applies `persistentBackdrop` and `persistentEscape`, and Safari does\n * not implement it: there Escape always closes and the backdrop never does. The two halves\n * are rebuilt below, and ONLY where the attribute is unknown, so a browser that has it is\n * never second-guessed. The support is asked at event time: there is no DOM during setup.\n */\nconst closedbyUnsupported = () => !('closedBy' in HTMLDialogElement.prototype)\n\nfunction onCancel(event: Event) {\n if (closedbyUnsupported() && closedby.value === 'none') event.preventDefault()\n}\n\n/**\n * Whether a point lies outside the dialog's box, which is where the backdrop is: a click on\n * the `::backdrop` is dispatched to the dialog element itself.\n */\nfunction outsideBox(event: MouseEvent) {\n const box = dialogEl.value?.getBoundingClientRect()\n if (!box) return false\n return (\n event.clientX < box.left ||\n event.clientX > box.right ||\n event.clientY < box.top ||\n event.clientY > box.bottom\n )\n}\n\n// A press that STARTED inside and ended on the backdrop (a text selection dragged past the\n// edge) is not a click on the backdrop, so the press is remembered, not only the release.\nlet pressedOnBackdrop = false\nfunction onPointerdown(event: PointerEvent) {\n pressedOnBackdrop = event.target === dialogEl.value && outsideBox(event)\n}\nfunction onBackdropClick(event: MouseEvent) {\n const onBackdrop = pressedOnBackdrop && event.target === dialogEl.value && outsideBox(event)\n pressedOnBackdrop = false\n if (onBackdrop && closedbyUnsupported() && closedby.value === 'any') requestClose()\n}\n\ndefineExpose({\n /**\n * Opens the dialog, exactly as setting `open` does. The opening lands on the next tick,\n * once the element has been rendered: `el` is still null right after the call, and the\n * promise returned settles once the dialog is showing.\n */\n show,\n /**\n * Closes the dialog. It closes unconditionally, `persistentEscape` and\n * `persistentBackdrop` governing only the two routes the reader can take.\n */\n close: requestClose,\n /** The `<dialog>` element. It is null while closed: each opening builds a fresh one. */\n el: dialogEl,\n})\n</script>\n\n<template>\n <slot name=\"trigger\" :trigger-props=\"triggerProps\" />\n <dialog\n v-if=\"rendered\"\n ref=\"dialogEl\"\n :aria-labelledby=\"title ? titleId : undefined\"\n :aria-describedby=\"subtitle ? subtitleId : undefined\"\n v-bind=\"rootAttrs\"\n class=\"v-dialog\"\n :style=\"{ '--dialog-width': cssSize(width) }\"\n :role=\"role === 'alertdialog' ? 'alertdialog' : undefined\"\n @close=\"onClose\"\n @cancel=\"onCancel\"\n @pointerdown=\"onPointerdown\"\n @click=\"onBackdropClick\"\n >\n <!--\n The header and the footer stay put while only the body scrolls, so the scrollbar\n is confined to the body and never runs along them.\n\n The lines that appear under the header and above the footer once the body is\n scrolled are drawn by two sentinels stuck INSIDE the scrolling area, and not by\n the header and footer themselves: a container query can only style what is inside\n the container it asks about, never a sibling of it.\n -->\n <header class=\"v-dialog-header\">\n <slot name=\"header\">\n <div class=\"v-dialog-titles\">\n <VTypography\n v-if=\"title\"\n :id=\"titleId\"\n as=\"h2\"\n variant=\"heading-3\"\n class=\"v-dialog-title\"\n >\n {{ title }}\n </VTypography>\n <VTypography\n v-if=\"subtitle\"\n :id=\"subtitleId\"\n variant=\"subtitle\"\n tone=\"muted\"\n class=\"v-dialog-subtitle\"\n >\n {{ subtitle }}\n </VTypography>\n </div>\n </slot>\n <div v-if=\"!hideClose || $slots['header-actions']\" class=\"v-dialog-header-actions\">\n <slot name=\"header-actions\" />\n <VIconButton\n v-if=\"!hideClose\"\n class=\"v-dialog-close\"\n :label=\"resolvedCloseLabel\"\n variant=\"ghost\"\n tone=\"neutral\"\n size=\"sm\"\n @click=\"requestClose\"\n >\n <VIcon :name=\"closeIcon\" />\n </VIconButton>\n </div>\n </header>\n <div class=\"v-dialog-scroll\">\n <span class=\"v-dialog-edge v-dialog-edge--top\" aria-hidden=\"true\" />\n <div class=\"v-dialog-body\">\n <slot />\n </div>\n <span class=\"v-dialog-edge v-dialog-edge--bottom\" aria-hidden=\"true\" />\n </div>\n <footer v-if=\"$slots.footer\" class=\"v-dialog-footer\">\n <slot name=\"footer\" />\n </footer>\n </dialog>\n</template>\n\n<style>\n@layer vectis.components {\n .v-dialog {\n /* The width comes from the prop, set inline, or from the token when there is none.\n Whatever it asks for, the dialog is never allowed past the viewport, margins included.\n\n TRAP — the token is declared ON the element rather than written as a `var()` fallback.\n A custom property inherits, and a dialog opened from inside another one is its DOM\n descendant: with a fallback, an alert confirming something in an 800px dialog would\n read that dialog's inline width and open 800px wide itself, with no error anywhere. */\n --dialog-width: var(--vectis-control-size-dialog-width);\n inline-size: var(--dialog-width);\n max-inline-size: calc(100dvi - 2 * var(--vectis-space-4));\n max-block-size: calc(100dvb - 2 * var(--vectis-space-4));\n /* This puts the dialog back in the middle of the screen. The browser centres a\n modal with an automatic margin, which the design system's own reset — where\n every element loses its margins — had removed; restoring it here works because\n the component layer is stronger than the reset one. */\n margin: auto;\n /* The header and footer stay put while only the body scrolls, and hiding the\n overflow is what keeps the content inside the rounded corners. */\n display: flex;\n flex-direction: column;\n overflow: hidden;\n padding: 0;\n border: none;\n border-radius: var(--vectis-radius-overlay);\n background: var(--vectis-color-surface-overlay);\n color: var(--vectis-color-text);\n box-shadow: var(--vectis-shadow-xl);\n font-family: var(--vectis-text-family);\n }\n\n /*\n * An indispensable guard. The browser hides a closed dialog with a rule of its own,\n * but any display we declare above beats it — so without this, a closed dialog would\n * sit in the page at the top left, swallowing clicks.\n *\n * It also covers the two moments where the element exists without being open yet: the\n * frame between rendering it and opening it, and the server-rendered markup. The\n * popovers have the very same guard.\n */\n .v-dialog:not([open]) {\n display: none;\n }\n\n /* Opening a modal puts the focus on the dialog itself. No ring is drawn around the\n whole thing for that: the focus a reader needs to see is the one on the controls\n inside. */\n .v-dialog:focus-visible {\n outline: none;\n }\n\n .v-dialog-scroll {\n /* The ONLY part that scrolls. It takes whatever room is left between the header\n and the footer, which is what keeps the scrollbar confined to it. The zero\n minimum is load-bearing: without it a flex item refuses to shrink below its\n content, and nothing would ever scroll. */\n flex: 1 1 auto;\n min-block-size: 0;\n overflow-y: auto;\n /* A wheel reaching the end of the content stops there rather than scrolling the page\n behind the modal. */\n overscroll-behavior: contain;\n display: flex;\n flex-direction: column;\n /* This makes the box something its descendants can ask questions about — namely\n whether there is content hidden above or below. It adds no containment of size. */\n container-type: scroll-state;\n }\n\n /*\n * The two sentinels: hairlines stuck to the top and the bottom of the scrolling\n * area, and descendants of it, which is what allows them to ask about its scroll\n * state. Their negative margins mean they occupy no space at all. They are\n * transparent until the rules further down reveal them.\n */\n .v-dialog-edge {\n flex: none;\n block-size: 1px;\n position: sticky;\n background: transparent;\n }\n\n .v-dialog-edge--top {\n inset-block-start: 0;\n margin-block-end: -1px;\n }\n\n .v-dialog-edge--bottom {\n inset-block-end: 0;\n margin-block-start: -1px;\n }\n\n .v-dialog-header {\n flex: none; /* stays at the top, outside whatever scrolls */\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: var(--vectis-space-4);\n padding: var(--vectis-space-6) var(--vectis-space-6) var(--vectis-space-3);\n }\n\n .v-dialog-titles {\n display: flex;\n flex-direction: column;\n min-inline-size: 0;\n }\n\n /* The title and the subtitle are rendered by VTypography, which carries their type.\n Their classes remain as hooks, for a consumer's overrides and for the tests. */\n\n .v-dialog-header-actions {\n display: flex;\n align-items: center;\n gap: var(--vectis-space-1);\n /* The cross is a button, so it carries invisible padding of its own; pulling the\n row back by that amount is what makes the glyph line up with the header's edge\n rather than floating inside it. */\n margin-block-start: calc(-1 * var(--vectis-space-1));\n margin-inline-end: calc(-1 * var(--vectis-space-2));\n }\n\n .v-dialog-body {\n /* Short content is stretched to fill the space, so the footer stays at the bottom\n of the dialog rather than floating halfway up; long content keeps its natural\n height, overflows, and is what scrolls. */\n flex: 1 0 auto;\n padding: var(--vectis-space-1) var(--vectis-space-6) var(--vectis-space-3);\n font-size: var(--vectis-text-body-md-size);\n line-height: var(--vectis-text-body-md-leading);\n }\n\n .v-dialog-footer {\n flex: none; /* stays at the bottom, outside whatever scrolls */\n display: flex;\n align-items: center;\n justify-content: flex-end;\n flex-wrap: wrap;\n gap: var(--vectis-space-3);\n padding: var(--vectis-space-3) var(--vectis-space-6) var(--vectis-space-6);\n }\n\n /*\n * The lines only appear when they mean something. Asking the scrolling area whether\n * it can still be scrolled upwards tells us content is hidden ABOVE, so the line\n * under the header is shown; the same question downwards reveals the one above the\n * footer. In other words each line is drawn exactly when content is passing behind\n * the edge it marks.\n *\n * This kind of query is Chrome 133 and later for now. Where it is missing the\n * sentinels simply stay transparent, which is the intended fallback.\n */\n @container scroll-state(scrollable: top) {\n .v-dialog-edge--top {\n background: var(--vectis-color-border);\n }\n }\n\n @container scroll-state(scrollable: bottom) {\n .v-dialog-edge--bottom {\n background: var(--vectis-color-border);\n }\n }\n\n /*\n * The dialog animates on the way IN and not on the way out. Since it is removed from\n * the page the moment it closes, there is nothing left to animate out — that is the\n * price of the clean slate the lazy rendering buys, and it also spares the extra\n * declarations an exit animation would need.\n *\n * The starting values below are where a freshly rendered dialog begins, before\n * settling into its open state.\n */\n .v-dialog {\n transition:\n opacity var(--vectis-duration-base) var(--vectis-ease-default),\n transform var(--vectis-duration-base) var(--vectis-ease-default);\n }\n\n @starting-style {\n .v-dialog[open] {\n opacity: 0;\n transform: scale(0.97);\n }\n }\n\n .v-dialog::backdrop {\n background: var(--vectis-color-backdrop);\n transition: opacity var(--vectis-duration-base) var(--vectis-ease-default);\n }\n\n @starting-style {\n .v-dialog[open]::backdrop {\n opacity: 0;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-dialog,\n .v-dialog::backdrop {\n transition: none;\n }\n }\n\n /* Windows forced colors flattens the dialog's background to Canvas and drops its shadow,\n which were its only edge: it would float over the page with no boundary at all. An\n outline draws one without moving the layout by a pixel. */\n @media (forced-colors: active) {\n .v-dialog {\n outline: 1px solid CanvasText;\n }\n }\n}\n</style>\n"],"mappings":""}