vectis-ui 0.14.0 → 0.16.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 (442) hide show
  1. package/dist/components/VAccordion/VAccordion.css +1 -1
  2. package/dist/components/VAccordion/VAccordion.d.ts +0 -6
  3. package/dist/components/VAccordion/VAccordion.js.map +1 -1
  4. package/dist/components/VAccordion/VAccordion.vue_vue_type_script_setup_true_lang.js +3 -8
  5. package/dist/components/VAccordion/VAccordion.vue_vue_type_script_setup_true_lang.js.map +1 -1
  6. package/dist/components/VAccordion/VAccordionItem.js.map +1 -1
  7. package/dist/components/VAccordion/VAccordionItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  8. package/dist/components/VAccordion/context.js.map +1 -1
  9. package/dist/components/VAlert/VAlert.js.map +1 -1
  10. package/dist/components/VAlert/VAlert.vue_vue_type_script_setup_true_lang.js.map +1 -1
  11. package/dist/components/VAvatar/VAvatar.d.ts +0 -3
  12. package/dist/components/VAvatar/VAvatar.js.map +1 -1
  13. package/dist/components/VAvatar/VAvatar.vue_vue_type_script_setup_true_lang.js +21 -27
  14. package/dist/components/VAvatar/VAvatar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  15. package/dist/components/VAvatar/VAvatarGroup.d.ts +0 -6
  16. package/dist/components/VAvatar/VAvatarGroup.js.map +1 -1
  17. package/dist/components/VAvatar/VAvatarGroup.vue_vue_type_script_setup_true_lang.js +5 -19
  18. package/dist/components/VAvatar/VAvatarGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  19. package/dist/components/VAvatar/context.d.ts +0 -1
  20. package/dist/components/VAvatar/context.js.map +1 -1
  21. package/dist/components/VBadge/VBadge.js.map +1 -1
  22. package/dist/components/VBadge/VBadge.vue_vue_type_script_setup_true_lang.js +1 -1
  23. package/dist/components/VBadge/VBadge.vue_vue_type_script_setup_true_lang.js.map +1 -1
  24. package/dist/components/VBreadcrumb/VBreadcrumb.js.map +1 -1
  25. package/dist/components/VBreadcrumb/VBreadcrumb.vue_vue_type_script_setup_true_lang.js.map +1 -1
  26. package/dist/components/VButton/VButton.d.ts +0 -6
  27. package/dist/components/VButton/VButton.js.map +1 -1
  28. package/dist/components/VButton/VButton.vue_vue_type_script_setup_true_lang.js +11 -17
  29. package/dist/components/VButton/VButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
  30. package/dist/components/VButton/VButtonGroup.d.ts +0 -6
  31. package/dist/components/VButton/VButtonGroup.js.map +1 -1
  32. package/dist/components/VButton/VButtonGroup.vue_vue_type_script_setup_true_lang.js +0 -7
  33. package/dist/components/VButton/VButtonGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  34. package/dist/components/VButton/context.d.ts +0 -2
  35. package/dist/components/VButton/context.js.map +1 -1
  36. package/dist/components/VCalendar/VCalendar.js.map +1 -1
  37. package/dist/components/VCalendar/VCalendar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  38. package/dist/components/VCalendar/VCalendarEvent.js.map +1 -1
  39. package/dist/components/VCalendar/VCalendarEvent.vue_vue_type_script_setup_true_lang.js.map +1 -1
  40. package/dist/components/VCalendar/VCalendarMonth.js.map +1 -1
  41. package/dist/components/VCalendar/VCalendarMonth.vue_vue_type_script_setup_true_lang.js +5 -17
  42. package/dist/components/VCalendar/VCalendarMonth.vue_vue_type_script_setup_true_lang.js.map +1 -1
  43. package/dist/components/VCalendar/VCalendarTimeGrid.js.map +1 -1
  44. package/dist/components/VCalendar/VCalendarTimeGrid.vue_vue_type_script_setup_true_lang.js +19 -31
  45. package/dist/components/VCalendar/VCalendarTimeGrid.vue_vue_type_script_setup_true_lang.js.map +1 -1
  46. package/dist/components/VCalendar/VCalendarYear.js.map +1 -1
  47. package/dist/components/VCalendar/VCalendarYear.vue_vue_type_script_setup_true_lang.js.map +1 -1
  48. package/dist/components/VCalendar/color.js.map +1 -1
  49. package/dist/components/VCalendar/edgeStep.js +1 -5
  50. package/dist/components/VCalendar/edgeStep.js.map +1 -1
  51. package/dist/components/VCalendar/gesture.js +4 -12
  52. package/dist/components/VCalendar/gesture.js.map +1 -1
  53. package/dist/components/VCalendar/keyboard.js.map +1 -1
  54. package/dist/components/VCalendar/layout.js +8 -12
  55. package/dist/components/VCalendar/layout.js.map +1 -1
  56. package/dist/components/VCalendar/timeGrid.js +5 -5
  57. package/dist/components/VCalendar/timeGrid.js.map +1 -1
  58. package/dist/components/VCard/VCard.js.map +1 -1
  59. package/dist/components/VCard/VCard.vue_vue_type_script_setup_true_lang.js.map +1 -1
  60. package/dist/components/VCarousel/VCarousel.js.map +1 -1
  61. package/dist/components/VCarousel/VCarousel.vue_vue_type_script_setup_true_lang.js.map +1 -1
  62. package/dist/components/VCarousel/VCarouselItem.js.map +1 -1
  63. package/dist/components/VCarousel/VCarouselItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  64. package/dist/components/VCarousel/context.js.map +1 -1
  65. package/dist/components/VCheckbox/VCheckMark.js.map +1 -1
  66. package/dist/components/VCheckbox/VCheckMark.vue_vue_type_script_setup_true_lang.js.map +1 -1
  67. package/dist/components/VCheckbox/VCheckbox.js.map +1 -1
  68. package/dist/components/VCheckbox/VCheckbox.vue_vue_type_script_setup_true_lang.js.map +1 -1
  69. package/dist/components/VChip/VChip.d.ts +0 -3
  70. package/dist/components/VChip/VChip.js.map +1 -1
  71. package/dist/components/VChip/VChip.vue_vue_type_script_setup_true_lang.js +0 -6
  72. package/dist/components/VChip/VChip.vue_vue_type_script_setup_true_lang.js.map +1 -1
  73. package/dist/components/VColorInput/VColorInput.d.ts +0 -3
  74. package/dist/components/VColorInput/VColorInput.js.map +1 -1
  75. package/dist/components/VColorInput/VColorInput.vue_vue_type_script_setup_true_lang.js +3 -9
  76. package/dist/components/VColorInput/VColorInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
  77. package/dist/components/VColorPicker/VColorPicker.js.map +1 -1
  78. package/dist/components/VColorPicker/VColorPicker.vue_vue_type_script_setup_true_lang.js +1 -5
  79. package/dist/components/VColorPicker/VColorPicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
  80. package/dist/components/VColorPicker/color.js.map +1 -1
  81. package/dist/components/VCombobox/VCombobox.d.ts +0 -3
  82. package/dist/components/VCombobox/VCombobox.js.map +1 -1
  83. package/dist/components/VCombobox/VCombobox.vue_vue_type_script_setup_true_lang.js +100 -119
  84. package/dist/components/VCombobox/VCombobox.vue_vue_type_script_setup_true_lang.js.map +1 -1
  85. package/dist/components/VCommandPalette/VCommandPalette.js.map +1 -1
  86. package/dist/components/VCommandPalette/VCommandPalette.vue_vue_type_script_setup_true_lang.js +0 -1
  87. package/dist/components/VCommandPalette/VCommandPalette.vue_vue_type_script_setup_true_lang.js.map +1 -1
  88. package/dist/components/VCommandPalette/VCommandPaletteItem.js.map +1 -1
  89. package/dist/components/VCommandPalette/VCommandPaletteItem.vue_vue_type_script_setup_true_lang.js +1 -5
  90. package/dist/components/VCommandPalette/VCommandPaletteItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  91. package/dist/components/VContextMenu/VContextMenu.d.ts +0 -3
  92. package/dist/components/VContextMenu/VContextMenu.js.map +1 -1
  93. package/dist/components/VContextMenu/VContextMenu.vue_vue_type_script_setup_true_lang.js +3 -11
  94. package/dist/components/VContextMenu/VContextMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
  95. package/dist/components/VDataTable/VDataTable.css +1 -1
  96. package/dist/components/VDataTable/VDataTable.d.ts +0 -2
  97. package/dist/components/VDataTable/VDataTable.js.map +1 -1
  98. package/dist/components/VDataTable/VDataTable.vue_vue_type_script_setup_true_lang.js +69 -88
  99. package/dist/components/VDataTable/VDataTable.vue_vue_type_script_setup_true_lang.js.map +1 -1
  100. package/dist/components/VDateInput/VDateInput.d.ts +0 -3
  101. package/dist/components/VDateInput/VDateInput.js.map +1 -1
  102. package/dist/components/VDateInput/VDateInput.vue_vue_type_script_setup_true_lang.js +5 -10
  103. package/dist/components/VDateInput/VDateInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
  104. package/dist/components/VDateInput/mask.js.map +1 -1
  105. package/dist/components/VDatePicker/VDatePicker.js.map +1 -1
  106. package/dist/components/VDatePicker/VDatePicker.vue_vue_type_script_setup_true_lang.js +2 -1
  107. package/dist/components/VDatePicker/VDatePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
  108. package/dist/components/VDatePicker/keyboard.js.map +1 -1
  109. package/dist/components/VDatePicker/names.js.map +1 -1
  110. package/dist/components/VDialog/VDialog.js.map +1 -1
  111. package/dist/components/VDialog/VDialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
  112. package/dist/components/VDialog/VDialogAlert.js.map +1 -1
  113. package/dist/components/VDialog/VDialogAlert.vue_vue_type_script_setup_true_lang.js.map +1 -1
  114. package/dist/components/VDrawer/VDrawer.js.map +1 -1
  115. package/dist/components/VDrawer/VDrawer.vue_vue_type_script_setup_true_lang.js.map +1 -1
  116. package/dist/components/VEmptyState/VEmptyState.js.map +1 -1
  117. package/dist/components/VEmptyState/VEmptyState.vue_vue_type_script_setup_true_lang.js.map +1 -1
  118. package/dist/components/VField/VField.js.map +1 -1
  119. package/dist/components/VField/VField.vue_vue_type_script_setup_true_lang.js.map +1 -1
  120. package/dist/components/VField/VFieldAnnouncer.js.map +1 -1
  121. package/dist/components/VField/VFieldAnnouncer.vue_vue_type_script_setup_true_lang.js.map +1 -1
  122. package/dist/components/VField/VFieldMessage.js.map +1 -1
  123. package/dist/components/VField/VFieldMessage.vue_vue_type_script_setup_true_lang.js.map +1 -1
  124. package/dist/components/VFieldset/VFieldset.js.map +1 -1
  125. package/dist/components/VFieldset/VFieldset.vue_vue_type_script_setup_true_lang.js.map +1 -1
  126. package/dist/components/VFileInput/VFileInput.d.ts +0 -5
  127. package/dist/components/VFileInput/VFileInput.js.map +1 -1
  128. package/dist/components/VFileInput/VFileInput.vue_vue_type_script_setup_true_lang.js +54 -65
  129. package/dist/components/VFileInput/VFileInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
  130. package/dist/components/VFileInput/truncate.js.map +1 -1
  131. package/dist/components/VFilePicker/VFilePicker.js.map +1 -1
  132. package/dist/components/VFilePicker/VFilePicker.vue_vue_type_script_setup_true_lang.js +1 -1
  133. package/dist/components/VFilePicker/VFilePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
  134. package/dist/components/VFilePicker/fileKind.js.map +1 -1
  135. package/dist/components/VHotkeys/VHotkeys.d.ts +0 -3
  136. package/dist/components/VHotkeys/VHotkeys.js.map +1 -1
  137. package/dist/components/VHotkeys/VHotkeys.vue_vue_type_script_setup_true_lang.js +0 -6
  138. package/dist/components/VHotkeys/VHotkeys.vue_vue_type_script_setup_true_lang.js.map +1 -1
  139. package/dist/components/VHotkeys/platform.js +1 -1
  140. package/dist/components/VHotkeys/platform.js.map +1 -1
  141. package/dist/components/VHoverCard/VHoverCard.js.map +1 -1
  142. package/dist/components/VHoverCard/VHoverCard.vue_vue_type_script_setup_true_lang.js +2 -12
  143. package/dist/components/VHoverCard/VHoverCard.vue_vue_type_script_setup_true_lang.js.map +1 -1
  144. package/dist/components/VIcon/VIcon.js.map +1 -1
  145. package/dist/components/VIcon/VIcon.vue_vue_type_script_setup_true_lang.js.map +1 -1
  146. package/dist/components/VIcon/iconProps.js.map +1 -1
  147. package/dist/components/VIcon/icons/add.js.map +1 -1
  148. package/dist/components/VIcon/icons/arrow_downward.js.map +1 -1
  149. package/dist/components/VIcon/icons/arrow_downward_alt.js.map +1 -1
  150. package/dist/components/VIcon/icons/arrow_drop_down.js.map +1 -1
  151. package/dist/components/VIcon/icons/arrow_drop_up.js.map +1 -1
  152. package/dist/components/VIcon/icons/arrow_left_alt.js.map +1 -1
  153. package/dist/components/VIcon/icons/arrow_right_alt.js.map +1 -1
  154. package/dist/components/VIcon/icons/arrow_upward.js.map +1 -1
  155. package/dist/components/VIcon/icons/arrow_upward_alt.js.map +1 -1
  156. package/dist/components/VIcon/icons/attach_file.js.map +1 -1
  157. package/dist/components/VIcon/icons/audio_file.js.map +1 -1
  158. package/dist/components/VIcon/icons/calendar_today.js.map +1 -1
  159. package/dist/components/VIcon/icons/check.js.map +1 -1
  160. package/dist/components/VIcon/icons/check_circle.js.map +1 -1
  161. package/dist/components/VIcon/icons/chevron_left.js.map +1 -1
  162. package/dist/components/VIcon/icons/chevron_right.js.map +1 -1
  163. package/dist/components/VIcon/icons/close.js.map +1 -1
  164. package/dist/components/VIcon/icons/cloud_upload.js.map +1 -1
  165. package/dist/components/VIcon/icons/code.js.map +1 -1
  166. package/dist/components/VIcon/icons/colorize.js.map +1 -1
  167. package/dist/components/VIcon/icons/description.js.map +1 -1
  168. package/dist/components/VIcon/icons/error.js.map +1 -1
  169. package/dist/components/VIcon/icons/expand_less.js.map +1 -1
  170. package/dist/components/VIcon/icons/expand_more.js.map +1 -1
  171. package/dist/components/VIcon/icons/first_page.js.map +1 -1
  172. package/dist/components/VIcon/icons/folder_zip.js.map +1 -1
  173. package/dist/components/VIcon/icons/image.js.map +1 -1
  174. package/dist/components/VIcon/icons/inbox.js.map +1 -1
  175. package/dist/components/VIcon/icons/index.js.map +1 -1
  176. package/dist/components/VIcon/icons/info.js.map +1 -1
  177. package/dist/components/VIcon/icons/last_page.js.map +1 -1
  178. package/dist/components/VIcon/icons/more_horiz.js.map +1 -1
  179. package/dist/components/VIcon/icons/names.js.map +1 -1
  180. package/dist/components/VIcon/icons/notifications.js.map +1 -1
  181. package/dist/components/VIcon/icons/open_in_new.js.map +1 -1
  182. package/dist/components/VIcon/icons/picture_as_pdf.js.map +1 -1
  183. package/dist/components/VIcon/icons/priority_high.js.map +1 -1
  184. package/dist/components/VIcon/icons/remove.js.map +1 -1
  185. package/dist/components/VIcon/icons/schedule.js.map +1 -1
  186. package/dist/components/VIcon/icons/search.js.map +1 -1
  187. package/dist/components/VIcon/icons/search_off.js.map +1 -1
  188. package/dist/components/VIcon/icons/star.js.map +1 -1
  189. package/dist/components/VIcon/icons/swap_vert.js.map +1 -1
  190. package/dist/components/VIcon/icons/table_chart.js.map +1 -1
  191. package/dist/components/VIcon/icons/video_file.js.map +1 -1
  192. package/dist/components/VIcon/icons/viewBox.js.map +1 -1
  193. package/dist/components/VIcon/icons/warning.js.map +1 -1
  194. package/dist/components/VIcon/resolver.js.map +1 -1
  195. package/dist/components/VIconButton/VIconButton.d.ts +0 -3
  196. package/dist/components/VIconButton/VIconButton.js.map +1 -1
  197. package/dist/components/VIconButton/VIconButton.vue_vue_type_script_setup_true_lang.js +0 -6
  198. package/dist/components/VIconButton/VIconButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
  199. package/dist/components/VInput/VInput.css +1 -1
  200. package/dist/components/VInput/VInput.d.ts +0 -3
  201. package/dist/components/VInput/VInput.js.map +1 -1
  202. package/dist/components/VInput/VInput.vue_vue_type_script_setup_true_lang.js +2 -8
  203. package/dist/components/VInput/VInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
  204. package/dist/components/VInput/VInputGroup.d.ts +0 -3
  205. package/dist/components/VInput/VInputGroup.js.map +1 -1
  206. package/dist/components/VInput/VInputGroup.vue_vue_type_script_setup_true_lang.js +0 -7
  207. package/dist/components/VInput/VInputGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  208. package/dist/components/VInput/context.d.ts +0 -2
  209. package/dist/components/VInput/context.js.map +1 -1
  210. package/dist/components/VInputOTP/VInputOTP.d.ts +0 -3
  211. package/dist/components/VInputOTP/VInputOTP.js.map +1 -1
  212. package/dist/components/VInputOTP/VInputOTP.vue_vue_type_script_setup_true_lang.js +2 -14
  213. package/dist/components/VInputOTP/VInputOTP.vue_vue_type_script_setup_true_lang.js.map +1 -1
  214. package/dist/components/VLink/VLink.js.map +1 -1
  215. package/dist/components/VLink/VLink.vue_vue_type_script_setup_true_lang.js.map +1 -1
  216. package/dist/components/VListbox/VListboxChevron.js.map +1 -1
  217. package/dist/components/VListbox/VListboxChevron.vue_vue_type_script_setup_true_lang.js.map +1 -1
  218. package/dist/components/VListbox/VListboxGroup.js.map +1 -1
  219. package/dist/components/VListbox/VListboxGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  220. package/dist/components/VListbox/VListboxOption.js.map +1 -1
  221. package/dist/components/VListbox/VListboxOption.vue_vue_type_script_setup_true_lang.js.map +1 -1
  222. package/dist/components/VListbox/VListboxPanel.d.ts +0 -3
  223. package/dist/components/VListbox/VListboxPanel.js.map +1 -1
  224. package/dist/components/VListbox/VListboxPanel.vue_vue_type_script_setup_true_lang.js +0 -6
  225. package/dist/components/VListbox/VListboxPanel.vue_vue_type_script_setup_true_lang.js.map +1 -1
  226. package/dist/components/VListbox/VListboxSeparator.js.map +1 -1
  227. package/dist/components/VListbox/VListboxSeparator.vue_vue_type_script_setup_true_lang.js.map +1 -1
  228. package/dist/components/VListbox/VListboxValues.js.map +1 -1
  229. package/dist/components/VListbox/VListboxValues.vue_vue_type_script_setup_true_lang.js +4 -14
  230. package/dist/components/VListbox/VListboxValues.vue_vue_type_script_setup_true_lang.js.map +1 -1
  231. package/dist/components/VMenu/VMenu.d.ts +0 -3
  232. package/dist/components/VMenu/VMenu.js.map +1 -1
  233. package/dist/components/VMenu/VMenu.vue_vue_type_script_setup_true_lang.js +0 -6
  234. package/dist/components/VMenu/VMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
  235. package/dist/components/VMenu/VMenuGroup.js.map +1 -1
  236. package/dist/components/VMenu/VMenuGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  237. package/dist/components/VMenu/VMenuItem.js.map +1 -1
  238. package/dist/components/VMenu/VMenuItem.vue_vue_type_script_setup_true_lang.js +6 -12
  239. package/dist/components/VMenu/VMenuItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  240. package/dist/components/VMenu/VMenuPanel.d.ts +0 -3
  241. package/dist/components/VMenu/VMenuPanel.js.map +1 -1
  242. package/dist/components/VMenu/VMenuPanel.vue_vue_type_script_setup_true_lang.js +9 -16
  243. package/dist/components/VMenu/VMenuPanel.vue_vue_type_script_setup_true_lang.js.map +1 -1
  244. package/dist/components/VMenu/VMenuSeparator.js.map +1 -1
  245. package/dist/components/VMenu/VMenuSeparator.vue_vue_type_script_setup_true_lang.js.map +1 -1
  246. package/dist/components/VMenu/context.js.map +1 -1
  247. package/dist/components/VMeter/VMeter.js.map +1 -1
  248. package/dist/components/VMeter/VMeter.vue_vue_type_script_setup_true_lang.js.map +1 -1
  249. package/dist/components/VNumberInput/VNumberInput.d.ts +0 -3
  250. package/dist/components/VNumberInput/VNumberInput.js.map +1 -1
  251. package/dist/components/VNumberInput/VNumberInput.vue_vue_type_script_setup_true_lang.js +85 -90
  252. package/dist/components/VNumberInput/VNumberInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
  253. package/dist/components/VNumberInput/number.js.map +1 -1
  254. package/dist/components/VPagination/VPagination.d.ts +0 -3
  255. package/dist/components/VPagination/VPagination.js.map +1 -1
  256. package/dist/components/VPagination/VPagination.vue_vue_type_script_setup_true_lang.js +0 -6
  257. package/dist/components/VPagination/VPagination.vue_vue_type_script_setup_true_lang.js.map +1 -1
  258. package/dist/components/VPopover/VPopover.js.map +1 -1
  259. package/dist/components/VPopover/VPopover.vue_vue_type_script_setup_true_lang.js.map +1 -1
  260. package/dist/components/VProgressCircular/VProgressCircular.js.map +1 -1
  261. package/dist/components/VProgressCircular/VProgressCircular.vue_vue_type_script_setup_true_lang.js.map +1 -1
  262. package/dist/components/VProgressLinear/VProgressLinear.js.map +1 -1
  263. package/dist/components/VProgressLinear/VProgressLinear.vue_vue_type_script_setup_true_lang.js.map +1 -1
  264. package/dist/components/VRadio/VRadio.js.map +1 -1
  265. package/dist/components/VRadio/VRadio.vue_vue_type_script_setup_true_lang.js.map +1 -1
  266. package/dist/components/VRating/VRating.js.map +1 -1
  267. package/dist/components/VRating/VRating.vue_vue_type_script_setup_true_lang.js.map +1 -1
  268. package/dist/components/VResizable/VResizable.js.map +1 -1
  269. package/dist/components/VResizable/VResizable.vue_vue_type_script_setup_true_lang.js +8 -6
  270. package/dist/components/VResizable/VResizable.vue_vue_type_script_setup_true_lang.js.map +1 -1
  271. package/dist/components/VResizable/VResizablePanel.js.map +1 -1
  272. package/dist/components/VResizable/VResizablePanel.vue_vue_type_script_setup_true_lang.js.map +1 -1
  273. package/dist/components/VResizable/context.js.map +1 -1
  274. package/dist/components/VResizable/layout.js.map +1 -1
  275. package/dist/components/VSelect/VSelect.d.ts +0 -3
  276. package/dist/components/VSelect/VSelect.js.map +1 -1
  277. package/dist/components/VSelect/VSelect.vue_vue_type_script_setup_true_lang.js +80 -90
  278. package/dist/components/VSelect/VSelect.vue_vue_type_script_setup_true_lang.js.map +1 -1
  279. package/dist/components/VSeparator/VSeparator.js.map +1 -1
  280. package/dist/components/VSeparator/VSeparator.vue_vue_type_script_setup_true_lang.js.map +1 -1
  281. package/dist/components/VSideNavigation/VSideNavigation.d.ts +0 -6
  282. package/dist/components/VSideNavigation/VSideNavigation.js.map +1 -1
  283. package/dist/components/VSideNavigation/VSideNavigation.vue_vue_type_script_setup_true_lang.js +2 -11
  284. package/dist/components/VSideNavigation/VSideNavigation.vue_vue_type_script_setup_true_lang.js.map +1 -1
  285. package/dist/components/VSideNavigation/VSideNavigationGroup.js.map +1 -1
  286. package/dist/components/VSideNavigation/VSideNavigationGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  287. package/dist/components/VSideNavigation/VSideNavigationItem.js.map +1 -1
  288. package/dist/components/VSideNavigation/VSideNavigationItem.vue_vue_type_script_setup_true_lang.js +1 -5
  289. package/dist/components/VSideNavigation/VSideNavigationItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  290. package/dist/components/VSideNavigation/VSideNavigationSeparator.js.map +1 -1
  291. package/dist/components/VSideNavigation/context.js.map +1 -1
  292. package/dist/components/VSkeletonLoader/VSkeletonLoader.d.ts +0 -3
  293. package/dist/components/VSkeletonLoader/VSkeletonLoader.js.map +1 -1
  294. package/dist/components/VSkeletonLoader/VSkeletonLoader.vue_vue_type_script_setup_true_lang.js +0 -6
  295. package/dist/components/VSkeletonLoader/VSkeletonLoader.vue_vue_type_script_setup_true_lang.js.map +1 -1
  296. package/dist/components/VSlider/VSlider.js.map +1 -1
  297. package/dist/components/VSlider/VSlider.vue_vue_type_script_setup_true_lang.js +107 -112
  298. package/dist/components/VSlider/VSlider.vue_vue_type_script_setup_true_lang.js.map +1 -1
  299. package/dist/components/VSnackbar/VSnackbar.js.map +1 -1
  300. package/dist/components/VSnackbar/VSnackbar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  301. package/dist/components/VSnackbar/state.js.map +1 -1
  302. package/dist/components/VSpinner/VSpinner.js.map +1 -1
  303. package/dist/components/VSpinner/VSpinner.vue_vue_type_script_setup_true_lang.js.map +1 -1
  304. package/dist/components/VSplitButton/VSplitButton.d.ts +0 -3
  305. package/dist/components/VSplitButton/VSplitButton.js.map +1 -1
  306. package/dist/components/VSplitButton/VSplitButton.vue_vue_type_script_setup_true_lang.js +0 -6
  307. package/dist/components/VSplitButton/VSplitButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
  308. package/dist/components/VStepper/VStepper.js.map +1 -1
  309. package/dist/components/VStepper/VStepper.vue_vue_type_script_setup_true_lang.js.map +1 -1
  310. package/dist/components/VSwitch/VSwitch.js.map +1 -1
  311. package/dist/components/VSwitch/VSwitch.vue_vue_type_script_setup_true_lang.js.map +1 -1
  312. package/dist/components/VTabs/VTab.js.map +1 -1
  313. package/dist/components/VTabs/VTab.vue_vue_type_script_setup_true_lang.js +0 -2
  314. package/dist/components/VTabs/VTab.vue_vue_type_script_setup_true_lang.js.map +1 -1
  315. package/dist/components/VTabs/VTabPanel.js.map +1 -1
  316. package/dist/components/VTabs/VTabPanel.vue_vue_type_script_setup_true_lang.js.map +1 -1
  317. package/dist/components/VTabs/VTabs.css +1 -1
  318. package/dist/components/VTabs/VTabs.d.ts +0 -3
  319. package/dist/components/VTabs/VTabs.js.map +1 -1
  320. package/dist/components/VTabs/VTabs.vue_vue_type_script_setup_true_lang.js +2 -15
  321. package/dist/components/VTabs/VTabs.vue_vue_type_script_setup_true_lang.js.map +1 -1
  322. package/dist/components/VTabs/context.d.ts +0 -2
  323. package/dist/components/VTabs/context.js.map +1 -1
  324. package/dist/components/VTextarea/VTextarea.d.ts +0 -6
  325. package/dist/components/VTextarea/VTextarea.js.map +1 -1
  326. package/dist/components/VTextarea/VTextarea.vue_vue_type_script_setup_true_lang.js +0 -6
  327. package/dist/components/VTextarea/VTextarea.vue_vue_type_script_setup_true_lang.js.map +1 -1
  328. package/dist/components/VTimeInput/VTimeInput.d.ts +0 -3
  329. package/dist/components/VTimeInput/VTimeInput.js.map +1 -1
  330. package/dist/components/VTimeInput/VTimeInput.vue_vue_type_script_setup_true_lang.js +197 -204
  331. package/dist/components/VTimeInput/VTimeInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
  332. package/dist/components/VTimeInput/search.js.map +1 -1
  333. package/dist/components/VTimePicker/VTimePicker.js.map +1 -1
  334. package/dist/components/VTimePicker/VTimePicker.vue_vue_type_script_setup_true_lang.js +9 -9
  335. package/dist/components/VTimePicker/VTimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
  336. package/dist/components/VTimePicker/limits.js.map +1 -1
  337. package/dist/components/VTimeline/VTimeline.js.map +1 -1
  338. package/dist/components/VTimeline/VTimeline.vue_vue_type_script_setup_true_lang.js.map +1 -1
  339. package/dist/components/VTimeline/VTimelineItem.js.map +1 -1
  340. package/dist/components/VTimeline/VTimelineItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  341. package/dist/components/VTimeline/context.js.map +1 -1
  342. package/dist/components/VTimeline/datetime.js.map +1 -1
  343. package/dist/components/VToast/VToast.js.map +1 -1
  344. package/dist/components/VToast/VToast.vue_vue_type_script_setup_true_lang.js.map +1 -1
  345. package/dist/components/VToast/VToaster.js.map +1 -1
  346. package/dist/components/VToast/VToaster.vue_vue_type_script_setup_true_lang.js +1 -1
  347. package/dist/components/VToast/VToaster.vue_vue_type_script_setup_true_lang.js.map +1 -1
  348. package/dist/components/VToast/state.js.map +1 -1
  349. package/dist/components/VToggle/VToggle.d.ts +0 -3
  350. package/dist/components/VToggle/VToggle.js.map +1 -1
  351. package/dist/components/VToggle/VToggle.vue_vue_type_script_setup_true_lang.js +1 -13
  352. package/dist/components/VToggle/VToggle.vue_vue_type_script_setup_true_lang.js.map +1 -1
  353. package/dist/components/VToggle/VToggleItem.js.map +1 -1
  354. package/dist/components/VToggle/VToggleItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  355. package/dist/components/VToggle/context.js.map +1 -1
  356. package/dist/components/VTooltip/VTooltip.js.map +1 -1
  357. package/dist/components/VTooltip/VTooltip.vue_vue_type_script_setup_true_lang.js.map +1 -1
  358. package/dist/components/VTreeView/VTreeView.js.map +1 -1
  359. package/dist/components/VTreeView/VTreeView.vue_vue_type_script_setup_true_lang.js +1 -5
  360. package/dist/components/VTreeView/VTreeView.vue_vue_type_script_setup_true_lang.js.map +1 -1
  361. package/dist/components/VTypography/VTypography.js.map +1 -1
  362. package/dist/components/VTypography/VTypography.vue_vue_type_script_setup_true_lang.js.map +1 -1
  363. package/dist/components/VVirtualList/VVirtualList.js.map +1 -1
  364. package/dist/components/VVirtualList/VVirtualList.vue_vue_type_script_setup_true_lang.js.map +1 -1
  365. package/dist/composables/useAriaLabel.js.map +1 -1
  366. package/dist/composables/useChoice.js.map +1 -1
  367. package/dist/composables/useClearable.js.map +1 -1
  368. package/dist/composables/useControlShape.d.ts +1 -5
  369. package/dist/composables/useControlShape.js +0 -1
  370. package/dist/composables/useControlShape.js.map +1 -1
  371. package/dist/composables/useDebouncedSearch.js.map +1 -1
  372. package/dist/composables/useDetailsOpen.js.map +1 -1
  373. package/dist/composables/useEscapeDismiss.js.map +1 -1
  374. package/dist/composables/useFieldIds.js.map +1 -1
  375. package/dist/composables/useFieldPanel.js +3 -7
  376. package/dist/composables/useFieldPanel.js.map +1 -1
  377. package/dist/composables/useFileDrop.js.map +1 -1
  378. package/dist/composables/useFileField.js +2 -2
  379. package/dist/composables/useFileField.js.map +1 -1
  380. package/dist/composables/useFocusoutDismiss.js.map +1 -1
  381. package/dist/composables/useHotkeyListener.js.map +1 -1
  382. package/dist/composables/useIconClickHandlers.js.map +1 -1
  383. package/dist/composables/useInertLink.js.map +1 -1
  384. package/dist/composables/useInfiniteScroll.js +2 -2
  385. package/dist/composables/useInfiniteScroll.js.map +1 -1
  386. package/dist/composables/useListbox.d.ts +0 -1
  387. package/dist/composables/useListbox.js +4 -10
  388. package/dist/composables/useListbox.js.map +1 -1
  389. package/dist/composables/useLiveAnnouncer.js.map +1 -1
  390. package/dist/composables/useMaskedField.js +28 -48
  391. package/dist/composables/useMaskedField.js.map +1 -1
  392. package/dist/composables/useModalDialog.js +1 -1
  393. package/dist/composables/useModalDialog.js.map +1 -1
  394. package/dist/composables/usePopover.js +1 -1
  395. package/dist/composables/usePopover.js.map +1 -1
  396. package/dist/composables/useProgressValue.js.map +1 -1
  397. package/dist/composables/useRootAttrs.js.map +1 -1
  398. package/dist/composables/useSlotNodes.js.map +1 -1
  399. package/dist/composables/useTextLimit.js.map +1 -1
  400. package/dist/composables/useTimer.js.map +1 -1
  401. package/dist/composables/useTypeahead.js.map +1 -1
  402. package/dist/composables/useVirtualList.js.map +1 -1
  403. package/dist/i18n/en.js.map +1 -1
  404. package/dist/i18n/fr.js.map +1 -1
  405. package/dist/i18n/state.js.map +1 -1
  406. package/dist/styles.css +1 -1
  407. package/dist/tokens/css.js.map +1 -1
  408. package/dist/tokens/index.d.ts +3 -0
  409. package/dist/tokens/index.js.map +1 -1
  410. package/dist/tokens/primitives.js.map +1 -1
  411. package/dist/tokens/semantic.d.ts +3 -0
  412. package/dist/tokens/semantic.js +6 -5
  413. package/dist/tokens/semantic.js.map +1 -1
  414. package/dist/tokens/themes/dark.js.map +1 -1
  415. package/dist/tokens/types.js.map +1 -1
  416. package/dist/tokens.json +12 -5
  417. package/dist/types.d.ts +0 -2
  418. package/dist/utils/array.js.map +1 -1
  419. package/dist/utils/arrowNav.js.map +1 -1
  420. package/dist/utils/attrs.js.map +1 -1
  421. package/dist/utils/chip.d.ts +4 -6
  422. package/dist/utils/chip.js +8 -5
  423. package/dist/utils/chip.js.map +1 -1
  424. package/dist/utils/clock.js +3 -1
  425. package/dist/utils/clock.js.map +1 -1
  426. package/dist/utils/css.js +1 -1
  427. package/dist/utils/css.js.map +1 -1
  428. package/dist/utils/date.js.map +1 -1
  429. package/dist/utils/direction.js.map +1 -1
  430. package/dist/utils/env.js.map +1 -1
  431. package/dist/utils/file.js +13 -31
  432. package/dist/utils/file.js.map +1 -1
  433. package/dist/utils/focus.js.map +1 -1
  434. package/dist/utils/hostWarns.js.map +1 -1
  435. package/dist/utils/ids.js.map +1 -1
  436. package/dist/utils/matcher.js.map +1 -1
  437. package/dist/utils/memo.js.map +1 -1
  438. package/dist/utils/number.js.map +1 -1
  439. package/dist/utils/text.js.map +1 -1
  440. package/dist/utils/time.js.map +1 -1
  441. package/dist/utils/vnode.js.map +1 -1
  442. package/package.json +19 -19
@@ -1 +1 @@
1
- {"version":3,"file":"VDateInput.vue_vue_type_script_setup_true_lang.js","names":["$slots"],"sources":["../../../src/components/VDateInput/VDateInput.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @a11y @core\n/**\n * Compose VInput with VDatePicker. A text input cannot use popovertarget, so the manual panel\n * bridge handles opening, dismissal and focus transfer into the grid.\n */\n\nimport { computed, inject, provide, ref, watchEffect } from 'vue'\n\nimport { inputGroupKey } from '../VInput/context'\n\nimport VDatePicker from '../VDatePicker/VDatePicker.vue'\nimport type {\n DatePickerDaySlotProps,\n DatePickerEvent,\n DatePickerSelection,\n DatePickerValue,\n DatePickerMatcher,\n DatePickerRange,\n} from '../VDatePicker/VDatePicker.vue'\nimport {\n compareISO,\n formatDateDisplay,\n formatDisplayRange,\n isDateAllowed,\n isValidISO,\n} from '../../utils/date'\nimport {\n caretAfterDigits,\n dateMaskFor,\n formatDateMask,\n isoToMask,\n maskPlaceholder,\n parseDateMask,\n} from './mask'\nimport { digitsOf } from '../../utils/text'\nimport { resolveMatcher } from '../../utils/matcher'\nimport { isDev } from '../../utils/env'\nimport { hostWarnsKey } from '../../utils/hostWarns'\nimport { calendar_today as calendarTodayIcon } from '../VIcon/icons/calendar_today'\nimport type { IconSource } from '../VIcon/types'\nimport type { FieldLabelPosition } from '../VField/VField.vue'\nimport VInput from '../VInput/VInput.vue'\nimport VPopover from '../VPopover/VPopover.vue'\n\nimport { useControlShape } from '../../composables/useControlShape'\nimport { useRootAttrs } from '../../composables/useRootAttrs'\n\nimport { useFieldPanel } from '../../composables/useFieldPanel'\nimport { canClear } from '../../composables/useClearable'\nimport { iconStartListener } from '../../composables/useIconClickHandlers'\nimport { useMaskedField } from '../../composables/useMaskedField'\nimport { useMessages, useResolvedLocale } from '../../i18n/state'\n\n/** Where the calendar opens relative to the field. */\nexport type DateInputPlacement =\n 'bottom' | 'bottom-start' | 'bottom-end' | 'top' | 'top-start' | 'top-end'\n\n/** Whether the field can be typed into, or only filled from the calendar. */\nexport type DateInputMode = 'picker' | 'input'\n\n/** What the `#footer` slot receives. */\nexport interface DateInputFooterSlotProps {\n /** Closes the panel and hands the focus back to the field. */\n close: () => void\n}\n\nconst MODES: DateInputMode[] = ['picker', 'input']\n\n/**\n * The century a two-digit year is expanded into; \"10/06/26\" becomes 2026; applied only when the\n * reader leaves the field.\n */\nconst YEAR_PIVOT = 2000\n\nconst DEFAULT_DISPLAY_FORMAT: Intl.DateTimeFormatOptions = {\n day: 'numeric',\n month: 'short',\n year: 'numeric',\n}\n\n/** The height of the field: 32, 40 or 48 pixels. */\nexport type DateInputSize = 'sm' | 'md' | 'lg'\n\ninterface DateInputProps {\n /** What is being chosen: one date, a period between two, or several separate dates. */\n selection?: DatePickerSelection\n /**\n * A BCP 47 locale, which decides the month and day names, the first day of the week and\n * the order the field is typed in. It TAKES PRECEDENCE over the design system's global\n * locale and falls back to it, which is why it has no literal default: `undefined` has\n * to stay recognizable for the global locale to have its chance.\n */\n locale?: string\n /** Forces the day the weeks start on, from 0 for Sunday to 6 for Saturday. */\n firstDayOfWeek?: number\n /** The earliest date that can be chosen, as an ISO string. */\n min?: string\n /** The latest date that can be chosen, as an ISO string. */\n max?: string\n /** Dates that cannot be chosen, as a list or as a function. */\n disabledDates?: DatePickerMatcher\n /** Fills the corners of the grid with the greyed days of the neighbouring months. */\n showAdjacentDays?: boolean\n /** Lets those neighbouring days be clicked, which implies showing them. */\n selectAdjacentDays?: boolean\n /** Events to mark under the days they fall on. */\n events?: DatePickerEvent[]\n /**\n * Whether the field can be TYPED into (the default, using the numeric form of the\n * reader's language) or is filled from the calendar alone, which is `picker`.\n *\n * Typing is reserved for choosing a SINGLE date: a period or a list falls back to\n * `picker`, there being no sensible way to type either.\n */\n mode?: DateInputMode\n /**\n * Offers the date picker alongside a field that can be typed into: an icon at the end of the\n * field, and a panel that opens on focus.\n */\n showPicker?: boolean\n /** The label above the field. */\n label?: string\n /** A line of help under the field. */\n hint?: string\n /**\n * A message saying what is wrong with the value, shown in place of the hint so that the field\n * does not grow. It marks the field invalid, is read along with it, and is announced when it\n * appears or changes.\n */\n error?: string\n /** Marks the field as required: an asterisk follows the label, and the field is `required`. */\n required?: boolean\n /** Hides the label visually. It still names the field for assistive technology. */\n hideLabel?: boolean\n /**\n * Where the label sits: above the field (`top`, the default), or at its start, in a column of\n * its own, moving back above when there is not room for both.\n */\n labelPosition?: FieldLabelPosition\n /** What the field says while empty. */\n placeholder?: string\n /** The height of the field: 32, 40 or 48 pixels. */\n size?: DateInputSize\n /** Takes 4px off the height. */\n compact?: boolean\n /** Makes the field unusable, greyed out through the colour tokens. */\n disabled?: boolean\n /**\n * Shows the date without letting it be changed: nothing can be typed, there is no calendar\n * and no clear cross.\n */\n readonly?: boolean\n /** Marks the field as invalid, for a rule of your own. */\n invalid?: boolean\n /**\n * An icon inside the field, at the start. It is decorative by default and becomes a\n * real button as soon as a `@click:icon-start` listener is attached, in which case it\n * needs `iconStartLabel`.\n */\n iconStart?: IconSource\n /** What the start icon does, in words, once it is clickable. */\n iconStartLabel?: string\n /**\n * What the calendar button does, in words. It names the button `pickerIcon` renders,\n * and falls back to the design system dictionary.\n */\n pickerLabel?: string\n /**\n * Shows a spinner at the end of the field, in place of the calendar icon. It says\n * that something is being loaded and changes nothing else: the field can still be\n * typed into and the panel still opens.\n */\n loading?: boolean\n /**\n * What screen readers announce while the spinner turns. It falls back to the design\n * system dictionary.\n */\n loadingText?: string\n /** Offers a cross that empties the value, shown before the end icon. */\n clearable?: boolean\n /** What that cross does, in words. It falls back to the design system dictionary. */\n clearLabel?: string\n /**\n * The icon that opens the date picker, at the end of the field. The clear cross appears\n * to its left rather than in its place, and no icon is rendered at all when there is no\n * panel to open.\n */\n pickerIcon?: IconSource\n /**\n * How the date is written OUT in the field. It has no effect on a field being typed into,\n * which necessarily shows the numeric form one types, so it concerns the `picker` mode, and\n * the period and list selections, which fall back to it.\n */\n displayFormat?: Intl.DateTimeFormatOptions\n /** Where the panel opens relative to the field. */\n placement?: DateInputPlacement\n}\n\nconst props = withDefaults(defineProps<DateInputProps>(), {\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 // Deliberately left undefined rather than defaulted to the typed mode: that is what\n // distinguishes \"the prop was not given\" from \"the prop was given this value\", and therefore\n // what allows warning only the consumer who explicitly asked for something that cannot work.\n mode: undefined,\n showPicker: false,\n label: undefined,\n hint: undefined,\n error: undefined,\n required: false,\n hideLabel: false,\n labelPosition: 'top',\n placeholder: undefined,\n size: 'md',\n compact: false,\n disabled: false,\n readonly: false,\n invalid: false,\n iconStart: undefined,\n iconStartLabel: undefined,\n pickerLabel: undefined,\n loading: false,\n loadingText: undefined,\n clearable: false,\n clearLabel: undefined,\n pickerIcon: () => calendarTodayIcon,\n // Left undefined rather than defaulted to the format object, for the same reason: it is\n // what lets the component notice that a consumer has asked for a display format in a\n // mode where it has no effect, and say so.\n displayFormat: undefined,\n placement: 'bottom-start',\n})\n\n/**\n * The date or dates chosen, in the shape `selection` calls for: an ISO `YYYY-MM-DD` string for\n * `single`, a `{ start, end }` pair for `range`, an array for `multiple`.\n */\nconst model = defineModel<DatePickerValue>({ default: null })\n\nconst emit = defineEmits<{\n /** The clear cross emptied the field. The value has already been reset. */\n clear: []\n /** The start icon was clicked. Attaching this listener is what makes it a button. */\n 'click:icon-start': [event: MouseEvent]\n}>()\n\ndefineSlots<{\n /**\n * Content at the start of the field, rendered after `iconStart` rather than in its place,\n * as in VInput.\n */\n start?(): unknown\n /**\n * Controls of your own inside the field, placed before the ones the field owns: the clear\n * cross and the icon that opens the panel.\n */\n 'value-end'?(): unknown\n /** What a day cell shows, handed straight to the calendar. */\n day?(props: DatePickerDaySlotProps): unknown\n /**\n * The strip at the foot of the panel: actions, or preset dates such as \"today\". It receives\n * `close`, which lets one of those buttons dismiss the panel.\n */\n footer?(props: DateInputFooterSlotProps): unknown\n}>()\n\n// `class` and `style` stay on the wrapper; everything else goes down to the text field, which a\n// consumer's label points at and what assistive technology deals with.\ndefineOptions({ inheritAttrs: false })\nconst { rootClass, rootStyle, forwardedAttrs } = useRootAttrs()\n\n// Declared as this component's own event, `click:icon-start` is out of `$attrs`, so the\n// listener is relayed to the field by hand; and only when the consumer wrote one.\nconst iconStartClick = iconStartListener((event) => emit('click:icon-start', event))\n\n/** What reaches the field: the consumer's own attributes, plus that listener. */\nconst fieldAttrs = computed(() => ({ ...forwardedAttrs.value, ...iconStartClick }))\n\nconst rootEl = ref<HTMLElement | null>(null)\nconst panelRef = ref<InstanceType<typeof VPopover> | null>(null)\nconst inputRef = ref<InstanceType<typeof VInput> | null>(null)\nconst pickerRef = ref<InstanceType<typeof VDatePicker> | null>(null)\n\n/** The real input inside the field, which the mask and the caret work on. */\nconst fieldEl = computed<HTMLInputElement | null>(() => inputRef.value?.el ?? null)\n\n/** What was asked for, falling back to the default when nothing or nonsense was given. */\nconst requestedMode = computed<DateInputMode>(() =>\n props.mode !== undefined && MODES.includes(props.mode) ? props.mode : 'input',\n)\n/**\n * What is actually used. Typing is only possible for a single date: a period or a list\n * has no form one could type into a single field.\n */\nconst resolvedMode = computed<DateInputMode>(() =>\n requestedMode.value === 'input' && props.selection === 'single' ? 'input' : 'picker',\n)\nconst typing = computed(() => resolvedMode.value === 'input')\n\n/**\n * Whether there is a panel at all. The calendar is only optional beside a field one can\n * type into: in `picker` mode it is the only way to choose anything, and a frozen field\n * has none at all.\n */\nconst hasPanel = computed(() => !props.readonly && (!typing.value || props.showPicker))\n\n// @devwarn\nif (isDev) {\n // The calendar receives `min` and `max` as they stand, so what it would say about them is\n // said here, under the name the consumer wrote (utils/hostWarns).\n provide(hostWarnsKey, true)\n watchEffect(() => {\n if (props.min && props.max && compareISO(props.min, props.max) > 0)\n console.warn(\n `[VDateInput] min \"${props.min}\" falls after max \"${props.max}\", so no date can be chosen.`,\n )\n // Without a panel there is no icon to draw and no button to name. A read-only field is\n // left out: it is a state that comes and goes, not a configuration to correct.\n if (typing.value && !props.showPicker) {\n const inert = ([] as string[]).concat(\n props.pickerIcon !== calendarTodayIcon ? 'pickerIcon' : [],\n props.pickerLabel ? 'pickerLabel' : [],\n )\n if (inert.length > 0)\n console.warn(\n `[VDateInput] ${inert.join(', ')} ${inert.length > 1 ? 'are' : 'is'} ignored without showPicker: a field one types into has no calendar icon unless it offers the calendar.`,\n )\n }\n if (props.mode !== undefined && !MODES.includes(props.mode))\n console.warn(\n `[VDateInput] unknown mode \"${props.mode}\": use \"input\" (the default) or \"picker\".`,\n )\n // Only a consumer who explicitly asked to type deserves to be told it cannot work.\n if (props.mode === 'input' && props.selection !== 'single')\n console.warn(\n `[VDateInput] mode=\"input\" ignored in \"${props.selection}\" selection: a range or a list of dates cannot be typed on the keyboard.`,\n )\n // Here it is the RESOLVED mode that matters: the format really was supplied, and it\n // really will have no effect, whichever route led to a typed field. The warning stays\n // something the consumer can act on.\n if (props.displayFormat && typing.value)\n console.warn(\n '[VDateInput] displayFormat is ignored in \"input\" mode (the default): the field displays the locale\\'s numeric mask, the only typeable format. Pass mode=\"picker\" for a formatted display.',\n )\n })\n}\n\n// A VInputGroup joins several controls into one object, so the shape of this field is the\n// row's decision rather than its own (VInput/context.ts).\nconst group = inject(inputGroupKey, null)\nconst {\n size: resolvedSize,\n compact: resolvedCompact,\n disabled: resolvedDisabled,\n} = useControlShape(props, group)\n\n// The whole \"field plus panel\" shell, shared with VTimeInput: opening and closing, the\n// focus leaving the component and coming back to the field, a click on the field or its\n// icon, and the Escape, ArrowDown and Enter keys.\nconst {\n open,\n panelId,\n popupAttrs,\n closeAndFocus,\n focusField,\n onFieldFocus,\n toggleFromIcon,\n onControlClick,\n onFocusout,\n onKeydown,\n onPanelMousedown,\n} = useFieldPanel({\n rootEl,\n panelRef,\n field: inputRef,\n // This is the composable's SINGLE cut-off point, and every way in passes through it; clicking\n // the field, focusing it, the down arrow, Enter, the icon; so the condition never has to be\n // repeated in a handler.\n disabled: () => resolvedDisabled.value || !hasPanel.value,\n focusInPanel: () => pickerRef.value?.focus(),\n // The calendar stays mounted while the panel is closed, so it is put back on the days\n // view both ways: a field that opens on focus never goes through `focus()`.\n onOpen: () => pickerRef.value?.reset(),\n onClose: () => pickerRef.value?.reset(),\n // Beside a field one types into, the panel opens on focus WITHOUT taking it: typing\n // carries on in the field, and the down arrow remains the way into the grid.\n openOnFocus: () => typing.value,\n})\n\nconst inputAttrs = popupAttrs(\n () => fieldAttrs.value,\n () => hasPanel.value,\n)\n\nconst hasValue = computed(() => {\n if (props.selection === 'multiple') return Array.isArray(model.value) && model.value.length > 0\n if (props.selection === 'range') {\n const r = model.value as DatePickerRange | null\n return !!(r && (r.start || r.end))\n }\n return typeof model.value === 'string' && !!model.value\n})\n\n/*\n * This component is the SINGLE place the locale is resolved: what flows down to the calendar is\n * the RESULT, never the prop, which would usually be undefined and would have the calendar\n * resolve the language a second time; with every chance of the two disagreeing after a later\n * change.\n */\nconst resolvedLocale = useResolvedLocale(() => props.locale)\n\nconst displayText = computed(() => {\n const locale = resolvedLocale.value\n const displayFormat = props.displayFormat ?? DEFAULT_DISPLAY_FORMAT\n if (props.selection === 'single') {\n return typeof model.value === 'string' && isValidISO(model.value)\n ? formatDateDisplay(model.value, locale, displayFormat)\n : ''\n }\n if (props.selection === 'range') {\n const r = model.value as DatePickerRange | null\n if (!r?.start) return ''\n if (!r.end) return formatDateDisplay(r.start, locale, displayFormat)\n return formatDisplayRange(r.start, r.end, locale, displayFormat)\n }\n const list = Array.isArray(model.value) ? model.value : []\n return list.map((iso) => formatDateDisplay(iso, locale, displayFormat)).join(', ')\n})\n\nconst mask = computed(() => dateMaskFor(resolvedLocale.value))\nconst maskHint = computed(() => maskPlaceholder(resolvedLocale.value, mask.value))\nconst isDisabledDate = computed(() => resolveMatcher(props.disabledDates))\n\n/**\n * Whether a date the reader has finished typing may actually be taken: it has to fall\n * within the allowed bounds and not be one of the excluded days.\n */\nconst acceptable = (iso: string) => isDateAllowed(iso, props.min, props.max, isDisabledDate.value)\n\n/*\n * The mask machinery; the text being typed, the bridge to the value, the reformatting that\n * preserves the caret, the commit as soon as the date is complete and the silent revert when it\n * is not; is shared with VTimeInput and lives in `useMaskedField`. What is injected here is the\n * date VOCABULARY alone: the order of the fields, the separator between them and their widths,\n * all derived from the reader's language.\n */\nconst {\n draft,\n fieldModel,\n writeField,\n commitOrRevert,\n onFieldInput,\n onKeydown: onMaskKeydown,\n onPaste,\n} = useMaskedField({\n fieldEl,\n typing: () => typing.value,\n displayText: () => displayText.value,\n readValue: () =>\n typeof model.value === 'string' && isValidISO(model.value) ? model.value : null,\n writeValue: (iso) => {\n model.value = iso\n },\n maxDigits: () => mask.value.size,\n format: (digits) => formatDateMask(digits, mask.value),\n caret: (text, digitsBefore, inserting) =>\n caretAfterDigits(text, digitsBefore, inserting ? mask.value.separator : undefined),\n // A two-digit year is only expanded on the FINAL commit, when the reader leaves the field;\n // never while they are still typing, where \"26\" may well be on its way to becoming \"2026\".\n parse: (text, final) =>\n parseDateMask(text, mask.value, final ? { yearPivot: YEAR_PIVOT } : undefined),\n toMask: (iso) => (iso ? isoToMask(iso, mask.value) : ''),\n acceptable,\n})\n\n/**\n * Typing anything that is not a digit; a slash, a dot, a space; completes the field being typed\n * with a leading zero and moves on to the next.\n */\nfunction padCurrentField(el: HTMLInputElement) {\n const start = el.selectionStart ?? el.value.length\n const before = digitsOf(el.value.slice(0, start)).length\n const digits = digitsOf(el.value)\n let offset = 0\n for (let k = 0; k < mask.value.order.length; k++) {\n const len = mask.value.lengths[k] as number\n if (before < offset + len) {\n const filled = before - offset\n if (mask.value.order[k] === 'year' || filled !== len - 1) return\n const next = digits.slice(0, offset) + '0'.repeat(len - filled) + digits.slice(offset)\n const text = formatDateMask(next.slice(0, mask.value.size), mask.value)\n writeField(text, caretAfterDigits(text, offset + len, mask.value.separator))\n return\n }\n offset += len\n }\n}\n\n// @keyboard\n// What the mask's keys mean for a date: a separator completes the field being\n// typed, and the down arrow is the one explicit way from the field into the calendar.\nfunction onFieldKeydown(event: KeyboardEvent) {\n onMaskKeydown(event, {\n onSeparator: padCurrentField,\n onArrowDown: () => {\n if (!open.value) return false\n pickerRef.value?.focus()\n return true\n },\n onEnter: closeAndFocus,\n })\n}\n\n/**\n * Pasting. A date recognizable as a whole; in the ISO form, or already written the way this\n * field writes them; is adopted as it stands; anything else contributes its digits alone.\n */\nfunction onFieldPaste(event: ClipboardEvent) {\n onPaste(event, (pasted) =>\n isValidISO(pasted) ? pasted : parseDateMask(pasted, mask.value, { yearPivot: YEAR_PIVOT }),\n )\n}\n\n/*\n * Whether it is shown has to be answered explicitly here: outside the typed mode the field is\n * read-only, and a read-only field hides its cross by default, rightly so; but here the value\n * comes from the panel, so there is something to clear all the same. The `readonly` PROP is the\n * one case where the default answer was right: frozen, the field offers no route to a new\n * value, so it offers no route to none either.\n */\nconst clearVisible = computed(() =>\n canClear(props, resolvedDisabled.value, hasValue.value || (typing.value && !!draft.value)),\n)\nconst endIcon = computed<IconSource | undefined>(() =>\n hasPanel.value ? props.pickerIcon : undefined,\n)\nconst m = useMessages()\n\n// @a11y @devwarn\n// Defined even when no icon is rendered: VInput warns at setup about a clickable icon without a\n// label, and cannot know whether the icon exists.\nconst endIconLabel = computed(() => props.pickerLabel ?? m.value.dateInput.openPicker)\nconst resolvedClearLabel = computed(() => props.clearLabel ?? m.value.dateInput.clear)\n\n/*\n * Emptying the value, called by the field as it emits its clear event. The focus is taken\n * through `focusField`, whose note says why that stops the panel reopening.\n */\nfunction clearValue() {\n model.value =\n props.selection === 'multiple'\n ? []\n : props.selection === 'range'\n ? { start: null, end: null }\n : null\n // The typed text is emptied EXPLICITLY: when the value was already empty, nothing\n // changes, and the guard that keeps the field and the value from chasing each other\n // would leave the text where it was.\n if (typing.value) writeField('')\n focusField()\n emit('clear')\n}\n\n/**\n * A date was chosen in the calendar. Choosing ONE date finishes the job, so the panel\n * closes; a period or a list is still being built and it stays open.\n */\nfunction onSelect() {\n if (props.selection === 'single') closeAndFocus()\n}\n\ndefineExpose({\n /** Moves the focus to the text field. */\n focus: (options?: FocusOptions) => inputRef.value?.focus(options),\n /** Selects what the field is showing. */\n select: () => inputRef.value?.select(),\n /** The real `<input>` behind the field, for what neither of the two above covers. */\n el: computed(() => inputRef.value?.el ?? null),\n})\n</script>\n\n<template>\n <div\n ref=\"rootEl\"\n class=\"v-date-input\"\n :class=\"rootClass\"\n :style=\"rootStyle\"\n :data-open=\"open ? '' : undefined\"\n :data-mode=\"resolvedMode\"\n :data-disabled=\"resolvedDisabled ? '' : undefined\"\n :data-readonly=\"readonly ? '' : undefined\"\n @focusout=\"onFocusout\"\n @keydown=\"onKeydown\"\n >\n <div class=\"v-date-input-control\" @click=\"onControlClick\">\n <!--\n The field is declared a combobox rather than left as the plain text box it implicitly\n is, because a text box may not carry the attribute saying whether something is expanded;\n and a text field with a panel attached IS the combobox pattern, the same role VCombobox\n gives its own field. The role and the three attributes are all conditioned on the same\n thing, so the role never appears without the expanded state it requires, and nothing\n ever points at a panel that was not rendered.\n -->\n <VInput\n ref=\"inputRef\"\n v-model=\"fieldModel\"\n :inputmode=\"typing ? 'numeric' : undefined\"\n :autocomplete=\"typing ? 'off' : undefined\"\n v-bind=\"inputAttrs\"\n :readonly=\"readonly\"\n :no-typing=\"!typing\"\n :label=\"label\"\n :hint=\"hint\"\n :error=\"error\"\n :required=\"required\"\n :hide-label=\"hideLabel\"\n :label-position=\"labelPosition\"\n :placeholder=\"placeholder ?? (typing ? maskHint : undefined)\"\n :size=\"resolvedSize\"\n :compact=\"resolvedCompact\"\n :disabled=\"resolvedDisabled\"\n :invalid=\"invalid\"\n :clearable=\"clearable\"\n :clear-visible=\"clearVisible\"\n :clear-label=\"resolvedClearLabel\"\n :icon-start=\"iconStart\"\n :icon-start-label=\"iconStartLabel\"\n :loading=\"loading\"\n :loading-text=\"loadingText\"\n :icon-end=\"endIcon\"\n :icon-end-label=\"endIconLabel\"\n @click:icon-end=\"toggleFromIcon\"\n @clear=\"clearValue\"\n @focus=\"onFieldFocus\"\n @input=\"onFieldInput\"\n @change=\"commitOrRevert\"\n @blur=\"commitOrRevert\"\n @keydown=\"onFieldKeydown\"\n @paste=\"onFieldPaste\"\n >\n <template v-if=\"$slots.start\" #start><slot name=\"start\" /></template>\n <template v-if=\"$slots['value-end']\" #value-end><slot name=\"value-end\" /></template>\n </VInput>\n </div>\n\n <VPopover\n v-if=\"hasPanel\"\n :id=\"panelId\"\n ref=\"panelRef\"\n v-model:open=\"open\"\n mode=\"manual\"\n anchor=\"--date-input-anchor\"\n :placement=\"placement\"\n role=\"dialog\"\n :aria-label=\"label ?? m.dateInput.pickerLabel\"\n class=\"v-date-input-panel\"\n @mousedown=\"onPanelMousedown\"\n >\n <VDatePicker\n ref=\"pickerRef\"\n v-model=\"model\"\n :selection=\"selection\"\n :locale=\"resolvedLocale\"\n :first-day-of-week=\"firstDayOfWeek\"\n :min=\"min\"\n :max=\"max\"\n :disabled-dates=\"disabledDates\"\n :show-adjacent-days=\"showAdjacentDays\"\n :select-adjacent-days=\"selectAdjacentDays\"\n :events=\"events\"\n @select=\"onSelect\"\n >\n <template v-if=\"$slots.day\" #day=\"slotProps\">\n <slot name=\"day\" v-bind=\"slotProps\" />\n </template>\n <template v-if=\"$slots.footer\" #footer>\n <slot name=\"footer\" :close=\"closeAndFocus\" />\n </template>\n </VDatePicker>\n </VPopover>\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n .v-date-input {\n anchor-scope: --date-input-anchor;\n display: block;\n width: 100%;\n font-family: var(--vectis-text-family);\n }\n\n .v-date-input:not([data-disabled]):not([data-readonly]) .v-date-input-control {\n cursor: pointer;\n }\n\n /*\n * The anchor is the FIELD's box and not this wrapper's, which also holds the label and the\n * hint: anchored to the wrapper, the calendar opens a hint's height below the field, and a\n * label's height above it once there is no room below and `flip-block` turns it over. Against\n * the field it covers whichever of the two it lands on, which a panel belonging to a control\n * is supposed to do.\n */\n .v-date-input-control .v-input-field {\n anchor-name: --date-input-anchor;\n }\n\n .v-date-input[data-mode='input']:not([data-disabled]):not([data-readonly]) .v-date-input-control {\n cursor: text;\n }\n\n /* Tabular figures give the mask a fixed width, so the caret does not jitter between digits. */\n .v-date-input[data-mode='input'] .v-input-control {\n font-variant-numeric: tabular-nums;\n }\n\n /*\n * `position-anchor` and the chrome come from VPopover (the `anchor` prop, and the `.v-panel`\n * it sets on any panel that is not `bare`): only the dimensions are left here, which\n * `panel.css` deliberately does not carry. The panel's own padding is cancelled, VDatePicker\n * padding itself as VTimePicker does, so both pickers keep the same room on a page and in a\n * panel.\n */\n .v-popover-panel.v-date-input-panel {\n width: max-content;\n padding: 0;\n }\n}\n</style>\n"],"mappings":"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"}
1
+ {"version":3,"file":"VDateInput.vue_vue_type_script_setup_true_lang.js","names":["$slots","calendarTodayIcon","_useModel","_openBlock","_createElementBlock","_normalizeClass","_unref","_normalizeStyle","_createElementVNode","_createVNode","VInput","_mergeProps","_isRef","_createSlots","_withCtx","_renderSlot","_createBlock","VPopover","VDatePicker","_normalizeProps","_guardReactiveProps","_createCommentVNode","VPopover_default","VInput_default","VDatePicker_default","_hoisted_1","YEAR_PIVOT","VDateInput_vue_vue_type_script_setup_true_lang_default","calendar_today","\"modelValue\"","\"modelModifiers\"","__expose","__emit","MODES","DEFAULT_DISPLAY_FORMAT","props","__props","model","useModel","emit","useRootAttrs","iconStartClick","iconStartListener","event","fieldAttrs","computed","forwardedAttrs","rootEl","ref","panelRef","inputRef","pickerRef","fieldEl","requestedMode","resolvedMode","typing","hasPanel","isDev","provide","hostWarnsKey","watchEffect","compareISO","inert","group","inject","inputGroupKey","resolvedSize","resolvedDisabled","useControlShape","useFieldPanel","inputAttrs","popupAttrs","hasValue","r","resolvedLocale","useResolvedLocale","displayText","locale","displayFormat","isValidISO","formatDateDisplay","formatDisplayRange","iso","mask","dateMaskFor","maskHint","maskPlaceholder","isDisabledDate","resolveMatcher","onMaskKeydown","useMaskedField","formatDateMask","digits","caretAfterDigits","text","digitsBefore","inserting","parseDateMask","final","isoToMask","isDateAllowed","padCurrentField","start","el","before","digitsOf","offset","k","len","filled","next","onFieldKeydown","open","closeAndFocus","onFieldPaste","pasted","clearVisible","canClear","draft","endIcon","m","useMessages","endIconLabel","resolvedClearLabel","clearValue","writeField","focusField","onSelect","options","openBlock","createElementBlock","normalizeClass","unref","rootClass","normalizeStyle","rootStyle","_cache","args","onFocusout","onKeydown","createElementVNode","onControlClick","createVNode","mergeProps","fieldModel","isRef","$event","toggleFromIcon","onFieldFocus","onFieldInput","commitOrRevert","createSlots","_ctx","withCtx","renderSlot","createBlock","panelId","onPanelMousedown","normalizeProps","guardReactiveProps","slotProps","createCommentVNode"],"sources":["../../../src/components/VDateInput/VDateInput.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @a11y @core\n/**\n * Compose VInput with VDatePicker. A text input cannot use popovertarget, so the manual panel\n * bridge handles opening, dismissal and focus transfer into the grid.\n */\n\nimport { computed, inject, provide, ref, watchEffect } from 'vue'\n\nimport { inputGroupKey } from '../VInput/context'\n\nimport VDatePicker from '../VDatePicker/VDatePicker.vue'\nimport type {\n DatePickerDaySlotProps,\n DatePickerEvent,\n DatePickerSelection,\n DatePickerValue,\n DatePickerMatcher,\n DatePickerRange,\n} from '../VDatePicker/VDatePicker.vue'\nimport {\n compareISO,\n formatDateDisplay,\n formatDisplayRange,\n isDateAllowed,\n isValidISO,\n} from '../../utils/date'\nimport {\n caretAfterDigits,\n dateMaskFor,\n formatDateMask,\n isoToMask,\n maskPlaceholder,\n parseDateMask,\n} from './mask'\nimport { digitsOf } from '../../utils/text'\nimport { resolveMatcher } from '../../utils/matcher'\nimport { isDev } from '../../utils/env'\nimport { hostWarnsKey } from '../../utils/hostWarns'\nimport { calendar_today as calendarTodayIcon } from '../VIcon/icons/calendar_today'\nimport type { IconSource } from '../VIcon/types'\nimport type { FieldLabelPosition } from '../VField/VField.vue'\nimport VInput from '../VInput/VInput.vue'\nimport VPopover from '../VPopover/VPopover.vue'\n\nimport { useControlShape } from '../../composables/useControlShape'\nimport { useRootAttrs } from '../../composables/useRootAttrs'\n\nimport { useFieldPanel } from '../../composables/useFieldPanel'\nimport { canClear } from '../../composables/useClearable'\nimport { iconStartListener } from '../../composables/useIconClickHandlers'\nimport { useMaskedField } from '../../composables/useMaskedField'\nimport { useMessages, useResolvedLocale } from '../../i18n/state'\n\n/** Where the calendar opens relative to the field. */\nexport type DateInputPlacement =\n | 'bottom'\n | 'bottom-start'\n | 'bottom-end'\n | 'top'\n | 'top-start'\n | 'top-end'\n\n/** Whether the field can be typed into, or only filled from the calendar. */\nexport type DateInputMode = 'picker' | 'input'\n\n/** What the `#footer` slot receives. */\nexport interface DateInputFooterSlotProps {\n /** Closes the panel and hands the focus back to the field. */\n close: () => void\n}\n\nconst MODES: DateInputMode[] = ['picker', 'input']\n\n/**\n * The century a two-digit year is expanded into; \"10/06/26\" becomes 2026; applied only when the\n * reader leaves the field.\n */\nconst YEAR_PIVOT = 2000\n\nconst DEFAULT_DISPLAY_FORMAT: Intl.DateTimeFormatOptions = {\n day: 'numeric',\n month: 'short',\n year: 'numeric',\n}\n\n/** The height of the field: 32, 40 or 48 pixels. */\nexport type DateInputSize = 'sm' | 'md' | 'lg'\n\ninterface DateInputProps {\n /** What is being chosen: one date, a period between two, or several separate dates. */\n selection?: DatePickerSelection\n /**\n * A BCP 47 locale, which decides the month and day names, the first day of the week and\n * the order the field is typed in. It TAKES PRECEDENCE over the design system's global\n * locale and falls back to it, which is why it has no literal default: `undefined` has\n * to stay recognizable for the global locale to have its chance.\n */\n locale?: string\n /** Forces the day the weeks start on, from 0 for Sunday to 6 for Saturday. */\n firstDayOfWeek?: number\n /** The earliest date that can be chosen, as an ISO string. */\n min?: string\n /** The latest date that can be chosen, as an ISO string. */\n max?: string\n /** Dates that cannot be chosen, as a list or as a function. */\n disabledDates?: DatePickerMatcher\n /** Fills the corners of the grid with the greyed days of the neighbouring months. */\n showAdjacentDays?: boolean\n /** Lets those neighbouring days be clicked, which implies showing them. */\n selectAdjacentDays?: boolean\n /** Events to mark under the days they fall on. */\n events?: DatePickerEvent[]\n /**\n * Whether the field can be TYPED into (the default, using the numeric form of the\n * reader's language) or is filled from the calendar alone, which is `picker`.\n *\n * Typing is reserved for choosing a SINGLE date: a period or a list falls back to\n * `picker`, there being no sensible way to type either.\n */\n mode?: DateInputMode\n /**\n * Offers the date picker alongside a field that can be typed into: an icon at the end of the\n * field, and a panel that opens on focus.\n */\n showPicker?: boolean\n /** The label above the field. */\n label?: string\n /** A line of help under the field. */\n hint?: string\n /**\n * A message saying what is wrong with the value, shown in place of the hint so that the field\n * does not grow. It marks the field invalid, is read along with it, and is announced when it\n * appears or changes.\n */\n error?: string\n /** Marks the field as required: an asterisk follows the label, and the field is `required`. */\n required?: boolean\n /** Hides the label visually. It still names the field for assistive technology. */\n hideLabel?: boolean\n /**\n * Where the label sits: above the field (`top`, the default), or at its start, in a column of\n * its own, moving back above when there is not room for both.\n */\n labelPosition?: FieldLabelPosition\n /** What the field says while empty. */\n placeholder?: string\n /** The height of the field: 32, 40 or 48 pixels. */\n size?: DateInputSize\n /** Makes the field unusable, greyed out through the colour tokens. */\n disabled?: boolean\n /**\n * Shows the date without letting it be changed: nothing can be typed, there is no calendar\n * and no clear cross.\n */\n readonly?: boolean\n /** Marks the field as invalid, for a rule of your own. */\n invalid?: boolean\n /**\n * An icon inside the field, at the start. It is decorative by default and becomes a\n * real button as soon as a `@click:icon-start` listener is attached, in which case it\n * needs `iconStartLabel`.\n */\n iconStart?: IconSource\n /** What the start icon does, in words, once it is clickable. */\n iconStartLabel?: string\n /**\n * What the calendar button does, in words. It names the button `pickerIcon` renders,\n * and falls back to the design system dictionary.\n */\n pickerLabel?: string\n /**\n * Shows a spinner at the end of the field, in place of the calendar icon. It says\n * that something is being loaded and changes nothing else: the field can still be\n * typed into and the panel still opens.\n */\n loading?: boolean\n /**\n * What screen readers announce while the spinner turns. It falls back to the design\n * system dictionary.\n */\n loadingText?: string\n /** Offers a cross that empties the value, shown before the end icon. */\n clearable?: boolean\n /** What that cross does, in words. It falls back to the design system dictionary. */\n clearLabel?: string\n /**\n * The icon that opens the date picker, at the end of the field. The clear cross appears\n * to its left rather than in its place, and no icon is rendered at all when there is no\n * panel to open.\n */\n pickerIcon?: IconSource\n /**\n * How the date is written OUT in the field. It has no effect on a field being typed into,\n * which necessarily shows the numeric form one types, so it concerns the `picker` mode, and\n * the period and list selections, which fall back to it.\n */\n displayFormat?: Intl.DateTimeFormatOptions\n /** Where the panel opens relative to the field. */\n placement?: DateInputPlacement\n}\n\nconst props = withDefaults(defineProps<DateInputProps>(), {\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 // Deliberately left undefined rather than defaulted to the typed mode: that is what\n // distinguishes \"the prop was not given\" from \"the prop was given this value\", and therefore\n // what allows warning only the consumer who explicitly asked for something that cannot work.\n mode: undefined,\n showPicker: false,\n label: undefined,\n hint: undefined,\n error: undefined,\n required: false,\n hideLabel: false,\n labelPosition: 'top',\n placeholder: undefined,\n size: 'md',\n disabled: false,\n readonly: false,\n invalid: false,\n iconStart: undefined,\n iconStartLabel: undefined,\n pickerLabel: undefined,\n loading: false,\n loadingText: undefined,\n clearable: false,\n clearLabel: undefined,\n pickerIcon: () => calendarTodayIcon,\n // Left undefined rather than defaulted to the format object, for the same reason: it is\n // what lets the component notice that a consumer has asked for a display format in a\n // mode where it has no effect, and say so.\n displayFormat: undefined,\n placement: 'bottom-start',\n})\n\n/**\n * The date or dates chosen, in the shape `selection` calls for: an ISO `YYYY-MM-DD` string for\n * `single`, a `{ start, end }` pair for `range`, an array for `multiple`.\n */\nconst model = defineModel<DatePickerValue>({ default: null })\n\nconst emit = defineEmits<{\n /** The clear cross emptied the field. The value has already been reset. */\n clear: []\n /** The start icon was clicked. Attaching this listener is what makes it a button. */\n 'click:icon-start': [event: MouseEvent]\n}>()\n\ndefineSlots<{\n /**\n * Content at the start of the field, rendered after `iconStart` rather than in its place,\n * as in VInput.\n */\n start?(): unknown\n /**\n * Controls of your own inside the field, placed before the ones the field owns: the clear\n * cross and the icon that opens the panel.\n */\n 'value-end'?(): unknown\n /** What a day cell shows, handed straight to the calendar. */\n day?(props: DatePickerDaySlotProps): unknown\n /**\n * The strip at the foot of the panel: actions, or preset dates such as \"today\". It receives\n * `close`, which lets one of those buttons dismiss the panel.\n */\n footer?(props: DateInputFooterSlotProps): unknown\n}>()\n\n// `class` and `style` stay on the wrapper; everything else goes down to the text field, which a\n// consumer's label points at and what assistive technology deals with.\ndefineOptions({ inheritAttrs: false })\nconst { rootClass, rootStyle, forwardedAttrs } = useRootAttrs()\n\n// Declared as this component's own event, `click:icon-start` is out of `$attrs`, so the\n// listener is relayed to the field by hand; and only when the consumer wrote one.\nconst iconStartClick = iconStartListener((event) => emit('click:icon-start', event))\n\n/** What reaches the field: the consumer's own attributes, plus that listener. */\nconst fieldAttrs = computed(() => ({ ...forwardedAttrs.value, ...iconStartClick }))\n\nconst rootEl = ref<HTMLElement | null>(null)\nconst panelRef = ref<InstanceType<typeof VPopover> | null>(null)\nconst inputRef = ref<InstanceType<typeof VInput> | null>(null)\nconst pickerRef = ref<InstanceType<typeof VDatePicker> | null>(null)\n\n/** The real input inside the field, which the mask and the caret work on. */\nconst fieldEl = computed<HTMLInputElement | null>(() => inputRef.value?.el ?? null)\n\n/** What was asked for, falling back to the default when nothing or nonsense was given. */\nconst requestedMode = computed<DateInputMode>(() =>\n props.mode !== undefined && MODES.includes(props.mode) ? props.mode : 'input',\n)\n/**\n * What is actually used. Typing is only possible for a single date: a period or a list\n * has no form one could type into a single field.\n */\nconst resolvedMode = computed<DateInputMode>(() =>\n requestedMode.value === 'input' && props.selection === 'single' ? 'input' : 'picker',\n)\nconst typing = computed(() => resolvedMode.value === 'input')\n\n/**\n * Whether there is a panel at all. The calendar is only optional beside a field one can\n * type into: in `picker` mode it is the only way to choose anything, and a frozen field\n * has none at all.\n */\nconst hasPanel = computed(() => !props.readonly && (!typing.value || props.showPicker))\n\n// @devwarn\nif (isDev) {\n // The calendar receives `min` and `max` as they stand, so what it would say about them is\n // said here, under the name the consumer wrote (utils/hostWarns).\n provide(hostWarnsKey, true)\n watchEffect(() => {\n if (props.min && props.max && compareISO(props.min, props.max) > 0)\n console.warn(\n `[VDateInput] min \"${props.min}\" falls after max \"${props.max}\", so no date can be chosen.`,\n )\n // Without a panel there is no icon to draw and no button to name. A read-only field is\n // left out: it is a state that comes and goes, not a configuration to correct.\n if (typing.value && !props.showPicker) {\n const inert = ([] as string[]).concat(\n props.pickerIcon !== calendarTodayIcon ? 'pickerIcon' : [],\n props.pickerLabel ? 'pickerLabel' : [],\n )\n if (inert.length > 0)\n console.warn(\n `[VDateInput] ${inert.join(', ')} ${inert.length > 1 ? 'are' : 'is'} ignored without showPicker: a field one types into has no calendar icon unless it offers the calendar.`,\n )\n }\n if (props.mode !== undefined && !MODES.includes(props.mode))\n console.warn(\n `[VDateInput] unknown mode \"${props.mode}\": use \"input\" (the default) or \"picker\".`,\n )\n // Only a consumer who explicitly asked to type deserves to be told it cannot work.\n if (props.mode === 'input' && props.selection !== 'single')\n console.warn(\n `[VDateInput] mode=\"input\" ignored in \"${props.selection}\" selection: a range or a list of dates cannot be typed on the keyboard.`,\n )\n // Here it is the RESOLVED mode that matters: the format really was supplied, and it\n // really will have no effect, whichever route led to a typed field. The warning stays\n // something the consumer can act on.\n if (props.displayFormat && typing.value)\n console.warn(\n '[VDateInput] displayFormat is ignored in \"input\" mode (the default): the field displays the locale\\'s numeric mask, the only typeable format. Pass mode=\"picker\" for a formatted display.',\n )\n })\n}\n\n// A VInputGroup joins several controls into one object, so the shape of this field is the\n// row's decision rather than its own (VInput/context.ts).\nconst group = inject(inputGroupKey, null)\nconst { size: resolvedSize, disabled: resolvedDisabled } = useControlShape(props, group)\n\n// The whole \"field plus panel\" shell, shared with VTimeInput: opening and closing, the\n// focus leaving the component and coming back to the field, a click on the field or its\n// icon, and the Escape, ArrowDown and Enter keys.\nconst {\n open,\n panelId,\n popupAttrs,\n closeAndFocus,\n focusField,\n onFieldFocus,\n toggleFromIcon,\n onControlClick,\n onFocusout,\n onKeydown,\n onPanelMousedown,\n} = useFieldPanel({\n rootEl,\n panelRef,\n field: inputRef,\n // This is the composable's SINGLE cut-off point, and every way in passes through it; clicking\n // the field, focusing it, the down arrow, Enter, the icon; so the condition never has to be\n // repeated in a handler.\n disabled: () => resolvedDisabled.value || !hasPanel.value,\n focusInPanel: () => pickerRef.value?.focus(),\n // The calendar stays mounted while the panel is closed, so it is put back on the days\n // view both ways: a field that opens on focus never goes through `focus()`.\n onOpen: () => pickerRef.value?.reset(),\n onClose: () => pickerRef.value?.reset(),\n // Beside a field one types into, the panel opens on focus WITHOUT taking it: typing\n // carries on in the field, and the down arrow remains the way into the grid.\n openOnFocus: () => typing.value,\n})\n\nconst inputAttrs = popupAttrs(\n () => fieldAttrs.value,\n () => hasPanel.value,\n)\n\nconst hasValue = computed(() => {\n if (props.selection === 'multiple') return Array.isArray(model.value) && model.value.length > 0\n if (props.selection === 'range') {\n const r = model.value as DatePickerRange | null\n return !!(r && (r.start || r.end))\n }\n return typeof model.value === 'string' && !!model.value\n})\n\n/*\n * This component is the SINGLE place the locale is resolved: what flows down to the calendar is\n * the RESULT, never the prop, which would usually be undefined and would have the calendar\n * resolve the language a second time; with every chance of the two disagreeing after a later\n * change.\n */\nconst resolvedLocale = useResolvedLocale(() => props.locale)\n\nconst displayText = computed(() => {\n const locale = resolvedLocale.value\n const displayFormat = props.displayFormat ?? DEFAULT_DISPLAY_FORMAT\n if (props.selection === 'single') {\n return typeof model.value === 'string' && isValidISO(model.value)\n ? formatDateDisplay(model.value, locale, displayFormat)\n : ''\n }\n if (props.selection === 'range') {\n const r = model.value as DatePickerRange | null\n if (!r?.start) return ''\n if (!r.end) return formatDateDisplay(r.start, locale, displayFormat)\n return formatDisplayRange(r.start, r.end, locale, displayFormat)\n }\n const list = Array.isArray(model.value) ? model.value : []\n return list.map((iso) => formatDateDisplay(iso, locale, displayFormat)).join(', ')\n})\n\nconst mask = computed(() => dateMaskFor(resolvedLocale.value))\nconst maskHint = computed(() => maskPlaceholder(resolvedLocale.value, mask.value))\nconst isDisabledDate = computed(() => resolveMatcher(props.disabledDates))\n\n/**\n * Whether a date the reader has finished typing may actually be taken: it has to fall\n * within the allowed bounds and not be one of the excluded days.\n */\nconst acceptable = (iso: string) => isDateAllowed(iso, props.min, props.max, isDisabledDate.value)\n\n/*\n * The mask machinery; the text being typed, the bridge to the value, the reformatting that\n * preserves the caret, the commit as soon as the date is complete and the silent revert when it\n * is not; is shared with VTimeInput and lives in `useMaskedField`. What is injected here is the\n * date VOCABULARY alone: the order of the fields, the separator between them and their widths,\n * all derived from the reader's language.\n */\nconst {\n draft,\n fieldModel,\n writeField,\n commitOrRevert,\n onFieldInput,\n onKeydown: onMaskKeydown,\n onPaste,\n} = useMaskedField({\n fieldEl,\n typing: () => typing.value,\n displayText: () => displayText.value,\n readValue: () =>\n typeof model.value === 'string' && isValidISO(model.value) ? model.value : null,\n writeValue: (iso) => {\n model.value = iso\n },\n maxDigits: () => mask.value.size,\n format: (digits) => formatDateMask(digits, mask.value),\n caret: (text, digitsBefore, inserting) =>\n caretAfterDigits(text, digitsBefore, inserting ? mask.value.separator : undefined),\n // A two-digit year is only expanded on the FINAL commit, when the reader leaves the field;\n // never while they are still typing, where \"26\" may well be on its way to becoming \"2026\".\n parse: (text, final) =>\n parseDateMask(text, mask.value, final ? { yearPivot: YEAR_PIVOT } : undefined),\n toMask: (iso) => (iso ? isoToMask(iso, mask.value) : ''),\n acceptable,\n})\n\n/**\n * Typing anything that is not a digit; a slash, a dot, a space; completes the field being typed\n * with a leading zero and moves on to the next.\n */\nfunction padCurrentField(el: HTMLInputElement) {\n const start = el.selectionStart ?? el.value.length\n const before = digitsOf(el.value.slice(0, start)).length\n const digits = digitsOf(el.value)\n let offset = 0\n for (let k = 0; k < mask.value.order.length; k++) {\n const len = mask.value.lengths[k] as number\n if (before < offset + len) {\n const filled = before - offset\n if (mask.value.order[k] === 'year' || filled !== len - 1) return\n const next = digits.slice(0, offset) + '0'.repeat(len - filled) + digits.slice(offset)\n const text = formatDateMask(next.slice(0, mask.value.size), mask.value)\n writeField(text, caretAfterDigits(text, offset + len, mask.value.separator))\n return\n }\n offset += len\n }\n}\n\n// @keyboard\n// What the mask's keys mean for a date: a separator completes the field being\n// typed, and the down arrow is the one explicit way from the field into the calendar.\nfunction onFieldKeydown(event: KeyboardEvent) {\n onMaskKeydown(event, {\n onSeparator: padCurrentField,\n onArrowDown: () => {\n if (!open.value) return false\n pickerRef.value?.focus()\n return true\n },\n onEnter: closeAndFocus,\n })\n}\n\n/**\n * Pasting. A date recognizable as a whole; in the ISO form, or already written the way this\n * field writes them; is adopted as it stands; anything else contributes its digits alone.\n */\nfunction onFieldPaste(event: ClipboardEvent) {\n onPaste(event, (pasted) =>\n isValidISO(pasted) ? pasted : parseDateMask(pasted, mask.value, { yearPivot: YEAR_PIVOT }),\n )\n}\n\n/*\n * Whether it is shown has to be answered explicitly here: outside the typed mode the field is\n * read-only, and a read-only field hides its cross by default, rightly so; but here the value\n * comes from the panel, so there is something to clear all the same. The `readonly` PROP is the\n * one case where the default answer was right: frozen, the field offers no route to a new\n * value, so it offers no route to none either.\n */\nconst clearVisible = computed(() =>\n canClear(props, resolvedDisabled.value, hasValue.value || (typing.value && !!draft.value)),\n)\nconst endIcon = computed<IconSource | undefined>(() =>\n hasPanel.value ? props.pickerIcon : undefined,\n)\nconst m = useMessages()\n\n// @a11y @devwarn\n// Defined even when no icon is rendered: VInput warns at setup about a clickable icon without a\n// label, and cannot know whether the icon exists.\nconst endIconLabel = computed(() => props.pickerLabel ?? m.value.dateInput.openPicker)\nconst resolvedClearLabel = computed(() => props.clearLabel ?? m.value.dateInput.clear)\n\n/*\n * Emptying the value, called by the field as it emits its clear event. The focus is taken\n * through `focusField`, whose note says why that stops the panel reopening.\n */\nfunction clearValue() {\n model.value =\n props.selection === 'multiple'\n ? []\n : props.selection === 'range'\n ? { start: null, end: null }\n : null\n // The typed text is emptied EXPLICITLY: when the value was already empty, nothing\n // changes, and the guard that keeps the field and the value from chasing each other\n // would leave the text where it was.\n if (typing.value) writeField('')\n focusField()\n emit('clear')\n}\n\n/**\n * A date was chosen in the calendar. Choosing ONE date finishes the job, so the panel\n * closes; a period or a list is still being built and it stays open.\n */\nfunction onSelect() {\n if (props.selection === 'single') closeAndFocus()\n}\n\ndefineExpose({\n /** Moves the focus to the text field. */\n focus: (options?: FocusOptions) => inputRef.value?.focus(options),\n /** Selects what the field is showing. */\n select: () => inputRef.value?.select(),\n /** The real `<input>` behind the field, for what neither of the two above covers. */\n el: computed(() => inputRef.value?.el ?? null),\n})\n</script>\n\n<template>\n <div\n ref=\"rootEl\"\n class=\"v-date-input\"\n :class=\"rootClass\"\n :style=\"rootStyle\"\n :data-open=\"open ? '' : undefined\"\n :data-mode=\"resolvedMode\"\n :data-disabled=\"resolvedDisabled ? '' : undefined\"\n :data-readonly=\"readonly ? '' : undefined\"\n @focusout=\"onFocusout\"\n @keydown=\"onKeydown\"\n >\n <div class=\"v-date-input-control\" @click=\"onControlClick\">\n <!--\n The field is declared a combobox rather than left as the plain text box it implicitly\n is, because a text box may not carry the attribute saying whether something is expanded;\n and a text field with a panel attached IS the combobox pattern, the same role VCombobox\n gives its own field. The role and the three attributes are all conditioned on the same\n thing, so the role never appears without the expanded state it requires, and nothing\n ever points at a panel that was not rendered.\n -->\n <VInput\n ref=\"inputRef\"\n v-model=\"fieldModel\"\n :inputmode=\"typing ? 'numeric' : undefined\"\n :autocomplete=\"typing ? 'off' : undefined\"\n v-bind=\"inputAttrs\"\n :readonly=\"readonly\"\n :no-typing=\"!typing\"\n :label=\"label\"\n :hint=\"hint\"\n :error=\"error\"\n :required=\"required\"\n :hide-label=\"hideLabel\"\n :label-position=\"labelPosition\"\n :placeholder=\"placeholder ?? (typing ? maskHint : undefined)\"\n :size=\"resolvedSize\"\n :disabled=\"resolvedDisabled\"\n :invalid=\"invalid\"\n :clearable=\"clearable\"\n :clear-visible=\"clearVisible\"\n :clear-label=\"resolvedClearLabel\"\n :icon-start=\"iconStart\"\n :icon-start-label=\"iconStartLabel\"\n :loading=\"loading\"\n :loading-text=\"loadingText\"\n :icon-end=\"endIcon\"\n :icon-end-label=\"endIconLabel\"\n @click:icon-end=\"toggleFromIcon\"\n @clear=\"clearValue\"\n @focus=\"onFieldFocus\"\n @input=\"onFieldInput\"\n @change=\"commitOrRevert\"\n @blur=\"commitOrRevert\"\n @keydown=\"onFieldKeydown\"\n @paste=\"onFieldPaste\"\n >\n <template v-if=\"$slots.start\" #start><slot name=\"start\" /></template>\n <template v-if=\"$slots['value-end']\" #value-end><slot name=\"value-end\" /></template>\n </VInput>\n </div>\n\n <VPopover\n v-if=\"hasPanel\"\n :id=\"panelId\"\n ref=\"panelRef\"\n v-model:open=\"open\"\n mode=\"manual\"\n anchor=\"--date-input-anchor\"\n :placement=\"placement\"\n role=\"dialog\"\n :aria-label=\"label ?? m.dateInput.pickerLabel\"\n class=\"v-date-input-panel\"\n @mousedown=\"onPanelMousedown\"\n >\n <VDatePicker\n ref=\"pickerRef\"\n v-model=\"model\"\n :selection=\"selection\"\n :locale=\"resolvedLocale\"\n :first-day-of-week=\"firstDayOfWeek\"\n :min=\"min\"\n :max=\"max\"\n :disabled-dates=\"disabledDates\"\n :show-adjacent-days=\"showAdjacentDays\"\n :select-adjacent-days=\"selectAdjacentDays\"\n :events=\"events\"\n @select=\"onSelect\"\n >\n <template v-if=\"$slots.day\" #day=\"slotProps\">\n <slot name=\"day\" v-bind=\"slotProps\" />\n </template>\n <template v-if=\"$slots.footer\" #footer>\n <slot name=\"footer\" :close=\"closeAndFocus\" />\n </template>\n </VDatePicker>\n </VPopover>\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n .v-date-input {\n anchor-scope: --date-input-anchor;\n display: block;\n width: 100%;\n font-family: var(--vectis-text-family);\n }\n\n .v-date-input:not([data-disabled]):not([data-readonly]) .v-date-input-control {\n cursor: pointer;\n }\n\n /*\n * The anchor is the FIELD's box and not this wrapper's, which also holds the label and the\n * hint: anchored to the wrapper, the calendar opens a hint's height below the field, and a\n * label's height above it once there is no room below and `flip-block` turns it over. Against\n * the field it covers whichever of the two it lands on, which a panel belonging to a control\n * is supposed to do.\n */\n .v-date-input-control .v-input-field {\n anchor-name: --date-input-anchor;\n }\n\n .v-date-input[data-mode='input']:not([data-disabled]):not([data-readonly]) .v-date-input-control {\n cursor: text;\n }\n\n /* Tabular figures give the mask a fixed width, so the caret does not jitter between digits. */\n .v-date-input[data-mode='input'] .v-input-control {\n font-variant-numeric: tabular-nums;\n }\n\n /*\n * `position-anchor` and the chrome come from VPopover (the `anchor` prop, and the `.v-panel`\n * it sets on any panel that is not `bare`): only the dimensions are left here, which\n * `panel.css` deliberately does not carry. The panel's own padding is cancelled, VDatePicker\n * padding itself as VTimePicker does, so both pickers keep the same room on a page and in a\n * panel.\n */\n .v-popover-panel.v-date-input-panel {\n width: max-content;\n padding: 0;\n }\n}\n</style>\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"mask.js","names":[],"sources":["../../../src/components/VDateInput/mask.ts"],"sourcesContent":["// @core\n/**\n * Locale-derived date input masks stay outside general date utilities so calendar views do not\n * import field-only code.\n */\n\nimport { isValidISO } from '../../utils/date'\nimport { memo } from '../../utils/memo'\nimport { digitsOf } from '../../utils/text'\n\n/*\n * A field being typed into never shows the long display format; \"10 June 2026\" is not something\n * one can type; but a purely numeric mask instead. The order of the three fields and the\n * separator between them are DERIVED from the locale rather than hardcoded, which makes the\n * same field work for a reader in Tokyo and one in Chicago.\n */\n\nexport type DateMaskField = 'day' | 'month' | 'year'\n\n/** Everything a locale decides about how a date is typed. */\nexport interface DateMask {\n /**\n * The order the three fields appear in: day, month, year in the United Kingdom,\n * month, day, year in the United States, year, month, day in Japan.\n */\n order: readonly DateMaskField[]\n /** The single character between two fields, stripped of bidi marks and spaces. */\n separator: string\n /** How many digits each field takes, in the same order: 4 for the year, 2 otherwise. */\n lengths: readonly number[]\n /** How many digits the complete mask holds, which is always 8. */\n size: number\n}\n\nconst MASK_FALLBACK: DateMask = {\n order: ['day', 'month', 'year'],\n separator: '/',\n lengths: [2, 2, 4],\n size: 8,\n}\n\n/**\n * The date the mask is read from: 22 November 2021. Its three numbers all differ, so\n * whichever order the locale prints them in, each one can be told apart.\n */\nconst REF_MASK_DATE = Date.UTC(2021, 10, 22)\n\n/** The invisible direction marks some locales insert, such as U+200F before \"/\" in ar-EG. */\nconst BIDI_MARKS = /[‎‏؜]/g\n\nconst maskCache = new Map<string, DateMask>()\n\n/**\n * The calendar and the numbering system are FORCED to Gregorian and Latin digits. An invalid\n * locale throws, and the answer then falls back to day/month/year separated by \"/\".\n */\nexport function dateMaskFor(locale: string): DateMask {\n return memo(maskCache, locale, () => buildDateMask(locale))\n}\n\n/*\n * The returned `DateMask` is shared between every caller for a locale, so it must be treated as\n * read-only. Nothing mutates it today (it is read field by field in `formatDateMask`,\n * `parseDateMask` and `maskPlaceholder`), and it is the same contract the memoized `Intl`\n * formatters in this file already have.\n */\nfunction buildDateMask(locale: string): DateMask {\n try {\n const parts = new Intl.DateTimeFormat(locale, {\n day: '2-digit',\n month: '2-digit',\n year: 'numeric',\n timeZone: 'UTC',\n calendar: 'gregory',\n numberingSystem: 'latn',\n }).formatToParts(REF_MASK_DATE)\n\n const order = parts\n .map((p) => p.type)\n .filter((t): t is DateMaskField => t === 'day' || t === 'month' || t === 'year')\n\n // The separator is the first literal appearing after the first field, and not simply the\n // first literal: Hungarian and Korean end the whole format with a dot (\"2021. 11. 22.\"),\n // which must not be mistaken for it.\n const firstField = parts.findIndex((p) => p.type !== 'literal')\n const separator = parts\n .slice(firstField)\n .find((p) => p.type === 'literal')\n ?.value.replace(BIDI_MARKS, '')\n .trim()\n\n if (order.length === 3 && separator) {\n const lengths = order.map((f) => (f === 'year' ? 4 : 2))\n return { order, separator, lengths, size: 8 }\n }\n } catch {\n /* An invalid locale throws a RangeError: fall through to the fallback */\n }\n return MASK_FALLBACK\n}\n\n/** Lays a run of digits out as masked text. */\nexport function formatDateMask(digits: string, mask: DateMask): string {\n const all = digitsOf(digits).slice(0, mask.size)\n let out = ''\n let i = 0\n for (let f = 0; f < mask.lengths.length; f++) {\n const len = mask.lengths[f] as number\n const chunk = all.slice(i, i + len)\n if (!chunk) break\n out += chunk\n i += len\n if (chunk.length < len) break\n if (f < mask.lengths.length - 1) out += mask.separator\n }\n return out\n}\n\n/**\n * Writes an ISO date in the mask of the locale, ready to be put in the field: the\n * same day reads \"10/06/2026\" in London and \"06/10/2026\" in Chicago.\n */\nexport function isoToMask(iso: string, mask: DateMask): string {\n if (!isValidISO(iso)) return ''\n const [year, month, day] = iso.split('-') as [string, string, string]\n const by: Record<DateMaskField, string> = { year, month, day }\n return formatDateMask(mask.order.map((f) => by[f]).join(''), mask)\n}\n\nexport interface ParseMaskOptions {\n /** The century a two-digit year is expanded into: with 2000, \"10/06/26\" is read as 2026. */\n yearPivot?: number\n}\n\n/**\n * Reads masked text back into an ISO date, or returns `null` when the text is incomplete, holds\n * too many digits, or names a day that does not exist: 31 February passes every length check\n * and is caught by the round trip `isValidISO` performs.\n */\nexport function parseDateMask(\n text: string,\n mask: DateMask,\n options: ParseMaskOptions = {},\n): string | null {\n const digits = digitsOf(text)\n const by: Partial<Record<DateMaskField, string>> = {}\n let i = 0\n for (let k = 0; k < mask.order.length; k++) {\n const field = mask.order[k] as DateMaskField\n const len = mask.lengths[k] as number\n const chunk = digits.slice(i, i + len)\n if (chunk.length === len) i += len\n else if (\n field === 'year' &&\n options.yearPivot !== undefined &&\n k === mask.order.length - 1 &&\n chunk.length === 2\n )\n i += 2\n else return null\n by[field] = chunk\n }\n if (i !== digits.length) return null\n const year =\n (by.year as string).length === 2\n ? String((options.yearPivot as number) + Number(by.year))\n : (by.year as string)\n const iso = `${year}-${by.month}-${by.day}`\n return isValidISO(iso) ? iso : null\n}\n\n/** Where the caret has to go to sit just after the nth digit. */\nexport function caretAfterDigits(text: string, n: number, separator?: string): number {\n let pos = 0\n if (n > 0) {\n pos = text.length\n let seen = 0\n for (let i = 0; i < text.length; i++) {\n const code = text.charCodeAt(i)\n if (code >= 48 && code <= 57 && ++seen === n) {\n pos = i + 1\n break\n }\n }\n }\n if (separator && text.startsWith(separator, pos)) pos += separator.length\n return pos\n}\n\nconst PLACEHOLDER_FALLBACK: Record<DateMaskField, string> = { day: 'd', month: 'm', year: 'y' }\n\n/**\n * Ideographic scripts, which are excluded from the placeholder: a repeated \"日\" does\n * not read as a template the way a repeated letter does.\n */\nconst IDEOGRAPHIC = /[\\p{sc=Han}\\p{sc=Hangul}\\p{sc=Hiragana}\\p{sc=Katakana}]/u\n\n// @fallback\n/**\n * The empty template shown in the field: \"dd/mm/yyyy\" in English, \"jj/mm/aaaa\" in French,\n * \"tt.mm.jjjj\" in German, \"дд/мм/гггг\" in Russian. It falls back to the Latin letters when that\n * part of `Intl` is missing, or when the script is ideographic and the repetition would mean\n * nothing.\n */\nexport function maskPlaceholder(locale: string, mask: DateMask): string {\n const letters = placeholderLetters(locale)\n return mask.order.map((f, k) => letters[f].repeat(mask.lengths[k] as number)).join(mask.separator)\n}\n\nconst placeholderLetterCache = new Map<string, typeof PLACEHOLDER_FALLBACK>()\n\n/** The three letters a locale writes its date fields with, worked out once per locale. */\nfunction placeholderLetters(locale: string): typeof PLACEHOLDER_FALLBACK {\n return memo(placeholderLetterCache, locale, () => buildPlaceholderLetters(locale))\n}\n\nfunction buildPlaceholderLetters(locale: string): typeof PLACEHOLDER_FALLBACK {\n const letters = { ...PLACEHOLDER_FALLBACK }\n try {\n const names = new Intl.DisplayNames(locale, { type: 'dateTimeField' })\n for (const field of ['day', 'month', 'year'] as const) {\n const first = [...(names.of(field) ?? '')][0]\n if (first && /\\p{L}/u.test(first) && !IDEOGRAPHIC.test(first))\n letters[field] = first.toLocaleLowerCase(locale)\n }\n } catch {\n /* Intl.DisplayNames is unavailable here: keep the Latin letters */\n }\n return letters\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"mask.js","names":["MASK_FALLBACK","REF_MASK_DATE","BIDI_MARKS","maskCache","dateMaskFor","memo","locale","buildDateMask","parts","order","p","t","firstField","separator","f","formatDateMask","all","digitsOf","digits","mask","out","i","len","chunk","isoToMask","isValidISO","iso","year","month","day","by","parseDateMask","text","k","field","options","caretAfterDigits","pos","n","seen","code","PLACEHOLDER_FALLBACK","IDEOGRAPHIC","maskPlaceholder","letters","placeholderLetters","placeholderLetterCache","buildPlaceholderLetters","names","first"],"sources":["../../../src/components/VDateInput/mask.ts"],"sourcesContent":["// @core\n/**\n * Locale-derived date input masks stay outside general date utilities so calendar views do not\n * import field-only code.\n */\n\nimport { isValidISO } from '../../utils/date'\nimport { memo } from '../../utils/memo'\nimport { digitsOf } from '../../utils/text'\n\n/*\n * A field being typed into never shows the long display format; \"10 June 2026\" is not something\n * one can type; but a purely numeric mask instead. The order of the three fields and the\n * separator between them are DERIVED from the locale rather than hardcoded, which makes the\n * same field work for a reader in Tokyo and one in Chicago.\n */\n\nexport type DateMaskField = 'day' | 'month' | 'year'\n\n/** Everything a locale decides about how a date is typed. */\nexport interface DateMask {\n /**\n * The order the three fields appear in: day, month, year in the United Kingdom,\n * month, day, year in the United States, year, month, day in Japan.\n */\n order: readonly DateMaskField[]\n /** The single character between two fields, stripped of bidi marks and spaces. */\n separator: string\n /** How many digits each field takes, in the same order: 4 for the year, 2 otherwise. */\n lengths: readonly number[]\n /** How many digits the complete mask holds, which is always 8. */\n size: number\n}\n\nconst MASK_FALLBACK: DateMask = {\n order: ['day', 'month', 'year'],\n separator: '/',\n lengths: [2, 2, 4],\n size: 8,\n}\n\n/**\n * The date the mask is read from: 22 November 2021. Its three numbers all differ, so\n * whichever order the locale prints them in, each one can be told apart.\n */\nconst REF_MASK_DATE = Date.UTC(2021, 10, 22)\n\n/** The invisible direction marks some locales insert, such as U+200F before \"/\" in ar-EG. */\nconst BIDI_MARKS = /[‎‏؜]/g\n\nconst maskCache = new Map<string, DateMask>()\n\n/**\n * The calendar and the numbering system are FORCED to Gregorian and Latin digits. An invalid\n * locale throws, and the answer then falls back to day/month/year separated by \"/\".\n */\nexport function dateMaskFor(locale: string): DateMask {\n return memo(maskCache, locale, () => buildDateMask(locale))\n}\n\n/*\n * The returned `DateMask` is shared between every caller for a locale, so it must be treated as\n * read-only. Nothing mutates it today (it is read field by field in `formatDateMask`,\n * `parseDateMask` and `maskPlaceholder`), and it is the same contract the memoized `Intl`\n * formatters in this file already have.\n */\nfunction buildDateMask(locale: string): DateMask {\n try {\n const parts = new Intl.DateTimeFormat(locale, {\n day: '2-digit',\n month: '2-digit',\n year: 'numeric',\n timeZone: 'UTC',\n calendar: 'gregory',\n numberingSystem: 'latn',\n }).formatToParts(REF_MASK_DATE)\n\n const order = parts\n .map((p) => p.type)\n .filter((t): t is DateMaskField => t === 'day' || t === 'month' || t === 'year')\n\n // The separator is the first literal appearing after the first field, and not simply the\n // first literal: Hungarian and Korean end the whole format with a dot (\"2021. 11. 22.\"),\n // which must not be mistaken for it.\n const firstField = parts.findIndex((p) => p.type !== 'literal')\n const separator = parts\n .slice(firstField)\n .find((p) => p.type === 'literal')\n ?.value.replace(BIDI_MARKS, '')\n .trim()\n\n if (order.length === 3 && separator) {\n const lengths = order.map((f) => (f === 'year' ? 4 : 2))\n return { order, separator, lengths, size: 8 }\n }\n } catch {\n /* An invalid locale throws a RangeError: fall through to the fallback */\n }\n return MASK_FALLBACK\n}\n\n/** Lays a run of digits out as masked text. */\nexport function formatDateMask(digits: string, mask: DateMask): string {\n const all = digitsOf(digits).slice(0, mask.size)\n let out = ''\n let i = 0\n for (let f = 0; f < mask.lengths.length; f++) {\n const len = mask.lengths[f] as number\n const chunk = all.slice(i, i + len)\n if (!chunk) break\n out += chunk\n i += len\n if (chunk.length < len) break\n if (f < mask.lengths.length - 1) out += mask.separator\n }\n return out\n}\n\n/**\n * Writes an ISO date in the mask of the locale, ready to be put in the field: the\n * same day reads \"10/06/2026\" in London and \"06/10/2026\" in Chicago.\n */\nexport function isoToMask(iso: string, mask: DateMask): string {\n if (!isValidISO(iso)) return ''\n const [year, month, day] = iso.split('-') as [string, string, string]\n const by: Record<DateMaskField, string> = { year, month, day }\n return formatDateMask(mask.order.map((f) => by[f]).join(''), mask)\n}\n\nexport interface ParseMaskOptions {\n /** The century a two-digit year is expanded into: with 2000, \"10/06/26\" is read as 2026. */\n yearPivot?: number\n}\n\n/**\n * Reads masked text back into an ISO date, or returns `null` when the text is incomplete, holds\n * too many digits, or names a day that does not exist: 31 February passes every length check\n * and is caught by the round trip `isValidISO` performs.\n */\nexport function parseDateMask(\n text: string,\n mask: DateMask,\n options: ParseMaskOptions = {},\n): string | null {\n const digits = digitsOf(text)\n const by: Partial<Record<DateMaskField, string>> = {}\n let i = 0\n for (let k = 0; k < mask.order.length; k++) {\n const field = mask.order[k] as DateMaskField\n const len = mask.lengths[k] as number\n const chunk = digits.slice(i, i + len)\n if (chunk.length === len) i += len\n else if (\n field === 'year' &&\n options.yearPivot !== undefined &&\n k === mask.order.length - 1 &&\n chunk.length === 2\n )\n i += 2\n else return null\n by[field] = chunk\n }\n if (i !== digits.length) return null\n const year =\n (by.year as string).length === 2\n ? String((options.yearPivot as number) + Number(by.year))\n : (by.year as string)\n const iso = `${year}-${by.month}-${by.day}`\n return isValidISO(iso) ? iso : null\n}\n\n/** Where the caret has to go to sit just after the nth digit. */\nexport function caretAfterDigits(text: string, n: number, separator?: string): number {\n let pos = 0\n if (n > 0) {\n pos = text.length\n let seen = 0\n for (let i = 0; i < text.length; i++) {\n const code = text.charCodeAt(i)\n if (code >= 48 && code <= 57 && ++seen === n) {\n pos = i + 1\n break\n }\n }\n }\n if (separator && text.startsWith(separator, pos)) pos += separator.length\n return pos\n}\n\nconst PLACEHOLDER_FALLBACK: Record<DateMaskField, string> = { day: 'd', month: 'm', year: 'y' }\n\n/**\n * Ideographic scripts, which are excluded from the placeholder: a repeated \"日\" does\n * not read as a template the way a repeated letter does.\n */\nconst IDEOGRAPHIC = /[\\p{sc=Han}\\p{sc=Hangul}\\p{sc=Hiragana}\\p{sc=Katakana}]/u\n\n// @fallback\n/**\n * The empty template shown in the field: \"dd/mm/yyyy\" in English, \"jj/mm/aaaa\" in French,\n * \"tt.mm.jjjj\" in German, \"дд/мм/гггг\" in Russian. It falls back to the Latin letters when that\n * part of `Intl` is missing, or when the script is ideographic and the repetition would mean\n * nothing.\n */\nexport function maskPlaceholder(locale: string, mask: DateMask): string {\n const letters = placeholderLetters(locale)\n return mask.order.map((f, k) => letters[f].repeat(mask.lengths[k] as number)).join(mask.separator)\n}\n\nconst placeholderLetterCache = new Map<string, typeof PLACEHOLDER_FALLBACK>()\n\n/** The three letters a locale writes its date fields with, worked out once per locale. */\nfunction placeholderLetters(locale: string): typeof PLACEHOLDER_FALLBACK {\n return memo(placeholderLetterCache, locale, () => buildPlaceholderLetters(locale))\n}\n\nfunction buildPlaceholderLetters(locale: string): typeof PLACEHOLDER_FALLBACK {\n const letters = { ...PLACEHOLDER_FALLBACK }\n try {\n const names = new Intl.DisplayNames(locale, { type: 'dateTimeField' })\n for (const field of ['day', 'month', 'year'] as const) {\n const first = [...(names.of(field) ?? '')][0]\n if (first && /\\p{L}/u.test(first) && !IDEOGRAPHIC.test(first))\n letters[field] = first.toLocaleLowerCase(locale)\n }\n } catch {\n /* Intl.DisplayNames is unavailable here: keep the Latin letters */\n }\n return letters\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"VDatePicker.js","names":[],"sources":["../../../src/components/VDatePicker/VDatePicker.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @keyboard @a11y @core\n/**\n * Implement roving grid focus and date selection because the platform has no composable,\n * stylable date grid. VDateInput reuses this calendar logic.\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 { isRtl } from '../../utils/direction'\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 * Fills the empty corners of the grid with the greyed days of the neighbouring months. It is\n * 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 read and\n * walked through (another month, another year), which separates it from `disabled`.\n */\n readonly?: boolean\n /**\n * The accessible name of the whole picker, its header and its grid together. It falls back to\n * 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 `single`,\n * a `{ start, end }` pair for `range`, an array of strings for `multiple`.\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 place to change\n// 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\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// A range start or a list entry is validated here, the way the single value is validated\n// upstream: both arrive as the consumer wrote them, and the month arrows assert that the focused\n// date parses, so a malformed one (`{ start: 'foo' }`) must never become it.\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 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 * With nothing selected, the month on display is read from the clock at setup, on the server\n * and again in the browser, and the two can disagree: a page prerendered in September and\n * opened in October, or a server a timezone behind its visitor on the last evening of a month.\n * Hydration patches the text but keeps the server's attributes, which would leave the month\n * button's accessible name and the day ids `focusDay` looks up on the server's month: bumping\n * the epoch re-renders the header and the grid once mounted.\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 `aria-selected` says: the end a range\n * preview is drawing is not selected yet, and announcing every day the focus walks over as\n * \"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 provisional\n // end shown during the preview.\n return isSameISO(iso, effectiveRange.value.start) || isSameISO(iso, effectiveRange.value.end)\n}\n/** Whether a day falls inside the selected period, both ends included. */\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/** The 42 squares of the month on display, rebuilt only when the MONTH changes. */\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 // Navigation is deliberately not guarded by `readonly`: a calendar one may read is a calendar\n // 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 // Emit what was just computed, never `model.value` read back. Under a parent `v-model`,\n // `defineModel` does not update its local copy on write; it waits for the parent to\n // 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.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, isRtl(event.currentTarget as Element))\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 the\n * 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, isRtl(event.currentTarget as Element))\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 on it\n // would move the tab stop where the focus cannot follow. The walk goes on the same way round\n // 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\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 placed straight\n * under the grid fails aria-required-children and aria-required-parent at the same time. The\n * cells are therefore cut into rows of PICKER_COLUMNS, matching the `grid-template-columns` of\n * the stylesheet; the row element itself is `display: contents`, so the CSS grid never sees it.\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\nconst yearRange = computed(() => {\n /*\n * `min` and `max` come straight from the consumer, and this is the only place where they are\n * turned into a Date instead of being compared as ISO text; `compareISO`, `isWithin` and\n * `clampISO` all tolerate a malformed bound. A value that is not a valid ISO date therefore\n * has to fall back to the open range here: asserting the parse would throw and take the whole\n * render down the moment the 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// Only from the OUTSIDE. The picker's own writes change the leading value too: unticking the\n// earliest date of a list makes the next one lead, and following it would throw the reader into\n// another month and drop the focus on `<body>`, the day they were on having left the document.\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 * A panel's content stays MOUNTED while the panel is closed, so without this the months or\n * years view a reader left open is what the next opening shows; and a field that opens its\n * 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 <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 <!--\n A day of a neighbouring month that cannot be selected. It renders the very same slot\n as the clickable days: were it left with the bare number, custom content taking\n several lines would apply to this month's days only, and the numbers would stop\n lining up from one cell to the next.\n -->\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 <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 <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 /*\n * The consumer sets the size of the day disc through its token; the cell around it; the\n * hover area and the width of the column; grows to follow, and never falls below the size\n * the cell token sets.\n */\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 /*\n * The days grid then fills that width through its 1fr columns, and never goes below the seven\n * cells its own floor guarantees.\n */\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 font-weight: var(--vectis-font-weight-semibold);\n text-transform: capitalize;\n }\n\n /*\n * The days grid can never be narrower than seven cells. Above that floor it takes whatever\n * width the calendar has; set by the header; and the 1fr columns share it out equally.\n */\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 /*\n * The two cap rules below only shape a pseudo-element that `[data-in-range]` has already\n * created, so they depend on `isInRange` counting both ends of the period as inside it. Make\n * it exclusive and there is no `::before` to cap: both rounded ends of every range vanish,\n * leaving a band that stops square one cell short at each side, with nothing in the console.\n */\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 /*\n * The semibold in the two rules below marks a state; today, and the selection; and is not a\n * typographic role, which is why it reads a font token directly.\n */\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 /*\n * It hangs on its own attribute rather than on `aria-disabled`, which a read-only calendar\n * also carries on every day: nothing can be chosen there, but the dates themselves are\n * perfectly available and striking them all out would say the opposite. The hover rule below\n * still reads `aria-disabled`, so neither highlights.\n */\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 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":""}
1
+ {"version":3,"file":"VDatePicker.js","names":["_sfc_main","VDatePicker_vue_vue_type_script_setup_true_lang_default","VDatePicker_default"],"sources":["../../../src/components/VDatePicker/VDatePicker.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @keyboard @a11y @core\n/**\n * Implement roving grid focus and date selection because the platform has no composable,\n * stylable date grid. VDateInput reuses this calendar logic.\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 { isRtl } from '../../utils/direction'\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 * Fills the empty corners of the grid with the greyed days of the neighbouring months. It is\n * 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 read and\n * walked through (another month, another year), which separates it from `disabled`.\n */\n readonly?: boolean\n /**\n * The accessible name of the whole picker, its header and its grid together. It falls back to\n * 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 `single`,\n * a `{ start, end }` pair for `range`, an array of strings for `multiple`.\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 place to change\n// 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\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// A range start or a list entry is validated here, the way the single value is validated\n// upstream: both arrive as the consumer wrote them, and the month arrows assert that the focused\n// date parses, so a malformed one (`{ start: 'foo' }`) must never become it.\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 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 * With nothing selected, the month on display is read from the clock at setup, on the server\n * and again in the browser, and the two can disagree: a page prerendered in September and\n * opened in October, or a server a timezone behind its visitor on the last evening of a month.\n * Hydration patches the text but keeps the server's attributes, which would leave the month\n * button's accessible name and the day ids `focusDay` looks up on the server's month: bumping\n * the epoch re-renders the header and the grid once mounted.\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 `aria-selected` says: the end a range\n * preview is drawing is not selected yet, and announcing every day the focus walks over as\n * \"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 provisional\n // end shown during the preview.\n return isSameISO(iso, effectiveRange.value.start) || isSameISO(iso, effectiveRange.value.end)\n}\n/** Whether a day falls inside the selected period, both ends included. */\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/** The 42 squares of the month on display, rebuilt only when the MONTH changes. */\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 // Navigation is deliberately not guarded by `readonly`: a calendar one may read is a calendar\n // 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 // Emit what was just computed, never `model.value` read back. Under a parent `v-model`,\n // `defineModel` does not update its local copy on write; it waits for the parent to\n // 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.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, isRtl(event.currentTarget as Element))\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 the\n * 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, isRtl(event.currentTarget as Element))\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 on it\n // would move the tab stop where the focus cannot follow. The walk goes on the same way round\n // 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\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 placed straight\n * under the grid fails aria-required-children and aria-required-parent at the same time. The\n * cells are therefore cut into rows of PICKER_COLUMNS, matching the `grid-template-columns` of\n * the stylesheet; the row element itself is `display: contents`, so the CSS grid never sees it.\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\nconst yearRange = computed(() => {\n /*\n * `min` and `max` come straight from the consumer, and this is the only place where they are\n * turned into a Date instead of being compared as ISO text; `compareISO`, `isWithin` and\n * `clampISO` all tolerate a malformed bound. A value that is not a valid ISO date therefore\n * has to fall back to the open range here: asserting the parse would throw and take the whole\n * render down the moment the 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// Only from the OUTSIDE. The picker's own writes change the leading value too: unticking the\n// earliest date of a list makes the next one lead, and following it would throw the reader into\n// another month and drop the focus on `<body>`, the day they were on having left the document.\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 * A panel's content stays MOUNTED while the panel is closed, so without this the months or\n * years view a reader left open is what the next opening shows; and a field that opens its\n * 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 <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 <!--\n A day of a neighbouring month that cannot be selected. It renders the very same slot\n as the clickable days: were it left with the bare number, custom content taking\n several lines would apply to this month's days only, and the numbers would stop\n lining up from one cell to the next.\n -->\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 <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 <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 /*\n * The consumer sets the size of the day disc through its token; the cell around it; the\n * hover area and the width of the column; grows to follow, and never falls below the size\n * the cell token sets.\n */\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 /*\n * The days grid then fills that width through its 1fr columns, and never goes below the seven\n * cells its own floor guarantees.\n */\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 font-weight: var(--vectis-font-weight-semibold);\n text-transform: capitalize;\n }\n\n /*\n * The days grid can never be narrower than seven cells. Above that floor it takes whatever\n * width the calendar has; set by the header; and the 1fr columns share it out equally.\n */\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 /*\n * The two cap rules below only shape a pseudo-element that `[data-in-range]` has already\n * created, so they depend on `isInRange` counting both ends of the period as inside it. Make\n * it exclusive and there is no `::before` to cap: both rounded ends of every range vanish,\n * leaving a band that stops square one cell short at each side, with nothing in the console.\n */\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 /*\n * The semibold in the two rules below marks a state; today, and the selection; and is not a\n * typographic role, which is why it reads a font token directly.\n */\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 /*\n * It hangs on its own attribute rather than on `aria-disabled`, which a read-only calendar\n * also carries on every day: nothing can be chosen there, but the dates themselves are\n * perfectly available and striking them all out would say the opposite. The hover rule below\n * still reads `aria-disabled`, so neither highlights.\n */\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 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":""}
@@ -250,7 +250,8 @@ var je = [
250
250
  n && (e.preventDefault(), Q("days" in n ? re(V.value, n.days) : u(V.value, n.months), !0));
251
251
  }
252
252
  function Et(e, t) {
253
- Q(m(e, t, Math.min(h(V.value).getDate(), oe(e, t)))), H.value = "days", Z(V.value);
253
+ let n = Math.min(h(V.value).getDate(), oe(e, t));
254
+ Q(m(e, t, n)), H.value = "days", Z(V.value);
254
255
  }
255
256
  function Dt(e, t, n, r, o, s = () => !0) {
256
257
  if (e.altKey || e.ctrlKey || e.metaKey) return;