vectis-ui 0.10.0 → 0.10.2

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 (334) hide show
  1. package/dist/components/VAccordion/VAccordion.js.map +1 -1
  2. package/dist/components/VAccordion/VAccordion.vue_vue_type_script_setup_true_lang.js.map +1 -1
  3. package/dist/components/VAccordion/VAccordionItem.d.ts +6 -21
  4. package/dist/components/VAccordion/VAccordionItem.js.map +1 -1
  5. package/dist/components/VAccordion/VAccordionItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  6. package/dist/components/VAccordion/context.js.map +1 -1
  7. package/dist/components/VAvatar/VAvatar.d.ts +2 -12
  8. package/dist/components/VAvatar/VAvatar.js.map +1 -1
  9. package/dist/components/VAvatar/VAvatar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  10. package/dist/components/VAvatar/VAvatarGroup.d.ts +2 -2
  11. package/dist/components/VAvatar/VAvatarGroup.js.map +1 -1
  12. package/dist/components/VAvatar/VAvatarGroup.vue_vue_type_script_setup_true_lang.js +6 -6
  13. package/dist/components/VAvatar/VAvatarGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  14. package/dist/components/VAvatar/context.d.ts +1 -5
  15. package/dist/components/VAvatar/context.js.map +1 -1
  16. package/dist/components/VBadge/VBadge.d.ts +13 -27
  17. package/dist/components/VBadge/VBadge.js.map +1 -1
  18. package/dist/components/VBadge/VBadge.vue_vue_type_script_setup_true_lang.js.map +1 -1
  19. package/dist/components/VBreadcrumb/VBreadcrumb.d.ts +3 -9
  20. package/dist/components/VBreadcrumb/VBreadcrumb.js.map +1 -1
  21. package/dist/components/VBreadcrumb/VBreadcrumb.vue_vue_type_script_setup_true_lang.js.map +1 -1
  22. package/dist/components/VButton/VButton.d.ts +10 -17
  23. package/dist/components/VButton/VButton.js.map +1 -1
  24. package/dist/components/VButton/VButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
  25. package/dist/components/VButton/VButtonGroup.d.ts +6 -15
  26. package/dist/components/VButton/VButtonGroup.js.map +1 -1
  27. package/dist/components/VButton/VButtonGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  28. package/dist/components/VButton/context.d.ts +1 -9
  29. package/dist/components/VButton/context.js.map +1 -1
  30. package/dist/components/VCalendar/VCalendar.d.ts +9 -24
  31. package/dist/components/VCalendar/VCalendar.js.map +1 -1
  32. package/dist/components/VCalendar/VCalendar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  33. package/dist/components/VCalendar/VCalendarEvent.d.ts +4 -13
  34. package/dist/components/VCalendar/VCalendarEvent.js.map +1 -1
  35. package/dist/components/VCalendar/VCalendarEvent.vue_vue_type_script_setup_true_lang.js.map +1 -1
  36. package/dist/components/VCalendar/VCalendarMonth.js.map +1 -1
  37. package/dist/components/VCalendar/VCalendarMonth.vue_vue_type_script_setup_true_lang.js.map +1 -1
  38. package/dist/components/VCalendar/VCalendarTimeGrid.d.ts +1 -5
  39. package/dist/components/VCalendar/VCalendarTimeGrid.js.map +1 -1
  40. package/dist/components/VCalendar/VCalendarTimeGrid.vue_vue_type_script_setup_true_lang.js.map +1 -1
  41. package/dist/components/VCalendar/VCalendarYear.js.map +1 -1
  42. package/dist/components/VCalendar/VCalendarYear.vue_vue_type_script_setup_true_lang.js.map +1 -1
  43. package/dist/components/VCalendar/color.d.ts +1 -7
  44. package/dist/components/VCalendar/color.js.map +1 -1
  45. package/dist/components/VCalendar/edgeStep.d.ts +5 -15
  46. package/dist/components/VCalendar/edgeStep.js.map +1 -1
  47. package/dist/components/VCalendar/gesture.d.ts +12 -36
  48. package/dist/components/VCalendar/gesture.js.map +1 -1
  49. package/dist/components/VCalendar/keyboard.d.ts +5 -42
  50. package/dist/components/VCalendar/keyboard.js.map +1 -1
  51. package/dist/components/VCalendar/layout.d.ts +38 -199
  52. package/dist/components/VCalendar/layout.js.map +1 -1
  53. package/dist/components/VCalendar/timeGrid.d.ts +3 -25
  54. package/dist/components/VCalendar/timeGrid.js.map +1 -1
  55. package/dist/components/VCalendar/types.d.ts +6 -23
  56. package/dist/components/VCarousel/VCarousel.d.ts +25 -96
  57. package/dist/components/VCarousel/VCarousel.js.map +1 -1
  58. package/dist/components/VCarousel/VCarousel.vue_vue_type_script_setup_true_lang.js +6 -6
  59. package/dist/components/VCarousel/VCarousel.vue_vue_type_script_setup_true_lang.js.map +1 -1
  60. package/dist/components/VCarousel/VCarouselItem.d.ts +1 -6
  61. package/dist/components/VCarousel/VCarouselItem.js.map +1 -1
  62. package/dist/components/VCarousel/VCarouselItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  63. package/dist/components/VCarousel/context.js.map +1 -1
  64. package/dist/components/VCheckbox/VCheckbox.d.ts +1 -5
  65. package/dist/components/VCheckbox/VCheckbox.js.map +1 -1
  66. package/dist/components/VCheckbox/VCheckbox.vue_vue_type_script_setup_true_lang.js.map +1 -1
  67. package/dist/components/VChip/VChip.d.ts +2 -8
  68. package/dist/components/VChip/VChip.js.map +1 -1
  69. package/dist/components/VChip/VChip.vue_vue_type_script_setup_true_lang.js.map +1 -1
  70. package/dist/components/VCombobox/VCombobox.d.ts +21 -59
  71. package/dist/components/VCombobox/VCombobox.js.map +1 -1
  72. package/dist/components/VCombobox/VCombobox.vue_vue_type_script_setup_true_lang.js +117 -119
  73. package/dist/components/VCombobox/VCombobox.vue_vue_type_script_setup_true_lang.js.map +1 -1
  74. package/dist/components/VCombobox/VComboboxGroup.js.map +1 -1
  75. package/dist/components/VCombobox/VComboboxGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  76. package/dist/components/VCombobox/VComboboxOption.js.map +1 -1
  77. package/dist/components/VCombobox/VComboboxOption.vue_vue_type_script_setup_true_lang.js.map +1 -1
  78. package/dist/components/VCombobox/VComboboxSeparator.js.map +1 -1
  79. package/dist/components/VCombobox/VComboboxSeparator.vue_vue_type_script_setup_true_lang.js.map +1 -1
  80. package/dist/components/VCombobox/infiniteScroll.d.ts +4 -10
  81. package/dist/components/VCombobox/infiniteScroll.js.map +1 -1
  82. package/dist/components/VDataTable/VDataTable.d.ts +11 -36
  83. package/dist/components/VDataTable/VDataTable.js.map +1 -1
  84. package/dist/components/VDataTable/VDataTable.vue_vue_type_script_setup_true_lang.js +23 -20
  85. package/dist/components/VDataTable/VDataTable.vue_vue_type_script_setup_true_lang.js.map +1 -1
  86. package/dist/components/VDateInput/VDateInput.d.ts +12 -21
  87. package/dist/components/VDateInput/VDateInput.js.map +1 -1
  88. package/dist/components/VDateInput/VDateInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
  89. package/dist/components/VDateInput/mask.d.ts +14 -59
  90. package/dist/components/VDateInput/mask.js.map +1 -1
  91. package/dist/components/VDatePicker/VDatePicker.d.ts +6 -12
  92. package/dist/components/VDatePicker/VDatePicker.js.map +1 -1
  93. package/dist/components/VDatePicker/VDatePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
  94. package/dist/components/VDatePicker/keyboard.d.ts +10 -42
  95. package/dist/components/VDatePicker/keyboard.js.map +1 -1
  96. package/dist/components/VDatePicker/names.d.ts +8 -22
  97. package/dist/components/VDatePicker/names.js.map +1 -1
  98. package/dist/components/VDialog/VDialog.d.ts +5 -10
  99. package/dist/components/VDialog/VDialog.js.map +1 -1
  100. package/dist/components/VDialog/VDialog.vue_vue_type_script_setup_true_lang.js +51 -53
  101. package/dist/components/VDialog/VDialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
  102. package/dist/components/VDialog/VDialogAlert.d.ts +2 -3
  103. package/dist/components/VDialog/VDialogAlert.js.map +1 -1
  104. package/dist/components/VDialog/VDialogAlert.vue_vue_type_script_setup_true_lang.js.map +1 -1
  105. package/dist/components/VFileInput/VFileInput.d.ts +11 -37
  106. package/dist/components/VFileInput/VFileInput.js.map +1 -1
  107. package/dist/components/VFileInput/VFileInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
  108. package/dist/components/VFileInput/truncate.d.ts +3 -23
  109. package/dist/components/VFileInput/truncate.js.map +1 -1
  110. package/dist/components/VFilePicker/VFilePicker.d.ts +15 -65
  111. package/dist/components/VFilePicker/VFilePicker.js.map +1 -1
  112. package/dist/components/VFilePicker/VFilePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
  113. package/dist/components/VFilePicker/fileKind.js.map +1 -1
  114. package/dist/components/VHotkeys/VHotkeys.d.ts +6 -15
  115. package/dist/components/VHotkeys/VHotkeys.js.map +1 -1
  116. package/dist/components/VHotkeys/VHotkeys.vue_vue_type_script_setup_true_lang.js.map +1 -1
  117. package/dist/components/VHotkeys/platform.d.ts +10 -49
  118. package/dist/components/VHotkeys/platform.js.map +1 -1
  119. package/dist/components/VIcon/VIcon.d.ts +7 -19
  120. package/dist/components/VIcon/VIcon.js.map +1 -1
  121. package/dist/components/VIcon/VIcon.vue_vue_type_script_setup_true_lang.js.map +1 -1
  122. package/dist/components/VIcon/iconProps.d.ts +5 -19
  123. package/dist/components/VIcon/iconProps.js.map +1 -1
  124. package/dist/components/VIcon/resolver.d.ts +15 -43
  125. package/dist/components/VIcon/resolver.js.map +1 -1
  126. package/dist/components/VIcon/types.d.ts +7 -34
  127. package/dist/components/VIconButton/VIconButton.d.ts +2 -3
  128. package/dist/components/VIconButton/VIconButton.js.map +1 -1
  129. package/dist/components/VIconButton/VIconButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
  130. package/dist/components/VInput/VInput.d.ts +14 -29
  131. package/dist/components/VInput/VInput.js.map +1 -1
  132. package/dist/components/VInput/VInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
  133. package/dist/components/VInput/VInputGroup.js.map +1 -1
  134. package/dist/components/VInput/VInputGroup.vue_vue_type_script_setup_true_lang.js +34 -50
  135. package/dist/components/VInput/VInputGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  136. package/dist/components/VInput/context.js.map +1 -1
  137. package/dist/components/VInputOTP/VInputOTP.d.ts +8 -16
  138. package/dist/components/VInputOTP/VInputOTP.js.map +1 -1
  139. package/dist/components/VInputOTP/VInputOTP.vue_vue_type_script_setup_true_lang.js +55 -63
  140. package/dist/components/VInputOTP/VInputOTP.vue_vue_type_script_setup_true_lang.js.map +1 -1
  141. package/dist/components/VMenu/VMenu.js.map +1 -1
  142. package/dist/components/VMenu/VMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
  143. package/dist/components/VMenu/VMenuGroup.d.ts +1 -6
  144. package/dist/components/VMenu/VMenuGroup.js.map +1 -1
  145. package/dist/components/VMenu/VMenuGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  146. package/dist/components/VMenu/VMenuItem.d.ts +0 -5
  147. package/dist/components/VMenu/VMenuItem.js.map +1 -1
  148. package/dist/components/VMenu/VMenuItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  149. package/dist/components/VMenu/VMenuPanel.d.ts +1 -6
  150. package/dist/components/VMenu/VMenuPanel.js.map +1 -1
  151. package/dist/components/VMenu/VMenuPanel.vue_vue_type_script_setup_true_lang.js +2 -2
  152. package/dist/components/VMenu/VMenuPanel.vue_vue_type_script_setup_true_lang.js.map +1 -1
  153. package/dist/components/VMenu/VMenuSeparator.js.map +1 -1
  154. package/dist/components/VMenu/VMenuSeparator.vue_vue_type_script_setup_true_lang.js.map +1 -1
  155. package/dist/components/VMenu/context.d.ts +3 -11
  156. package/dist/components/VMenu/context.js.map +1 -1
  157. package/dist/components/VPagination/VPagination.d.ts +9 -20
  158. package/dist/components/VPagination/VPagination.js.map +1 -1
  159. package/dist/components/VPagination/VPagination.vue_vue_type_script_setup_true_lang.js.map +1 -1
  160. package/dist/components/VPopover/VPopover.d.ts +7 -18
  161. package/dist/components/VPopover/VPopover.js.map +1 -1
  162. package/dist/components/VPopover/VPopover.vue_vue_type_script_setup_true_lang.js +23 -27
  163. package/dist/components/VPopover/VPopover.vue_vue_type_script_setup_true_lang.js.map +1 -1
  164. package/dist/components/VProgressCircular/VProgressCircular.d.ts +2 -6
  165. package/dist/components/VProgressCircular/VProgressCircular.js.map +1 -1
  166. package/dist/components/VProgressCircular/VProgressCircular.vue_vue_type_script_setup_true_lang.js.map +1 -1
  167. package/dist/components/VProgressLinear/VProgressLinear.d.ts +4 -15
  168. package/dist/components/VProgressLinear/VProgressLinear.js.map +1 -1
  169. package/dist/components/VProgressLinear/VProgressLinear.vue_vue_type_script_setup_true_lang.js.map +1 -1
  170. package/dist/components/VRadio/VRadio.d.ts +1 -5
  171. package/dist/components/VRadio/VRadio.js.map +1 -1
  172. package/dist/components/VRadio/VRadio.vue_vue_type_script_setup_true_lang.js.map +1 -1
  173. package/dist/components/VSeparator/VSeparator.d.ts +2 -15
  174. package/dist/components/VSeparator/VSeparator.js.map +1 -1
  175. package/dist/components/VSeparator/VSeparator.vue_vue_type_script_setup_true_lang.js.map +1 -1
  176. package/dist/components/VSideNavigation/VSideNavigation.d.ts +1 -1
  177. package/dist/components/VSideNavigation/VSideNavigation.js.map +1 -1
  178. package/dist/components/VSideNavigation/VSideNavigation.vue_vue_type_script_setup_true_lang.js.map +1 -1
  179. package/dist/components/VSideNavigation/VSideNavigationGroup.d.ts +1 -5
  180. package/dist/components/VSideNavigation/VSideNavigationGroup.js.map +1 -1
  181. package/dist/components/VSideNavigation/VSideNavigationGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  182. package/dist/components/VSideNavigation/VSideNavigationItem.d.ts +1 -5
  183. package/dist/components/VSideNavigation/VSideNavigationItem.js.map +1 -1
  184. package/dist/components/VSideNavigation/VSideNavigationItem.vue_vue_type_script_setup_true_lang.js +80 -75
  185. package/dist/components/VSideNavigation/VSideNavigationItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  186. package/dist/components/VSideNavigation/VSideNavigationSeparator.js.map +1 -1
  187. package/dist/components/VSideNavigation/context.js.map +1 -1
  188. package/dist/components/VSkeletonLoader/VSkeletonLoader.d.ts +6 -19
  189. package/dist/components/VSkeletonLoader/VSkeletonLoader.js.map +1 -1
  190. package/dist/components/VSkeletonLoader/VSkeletonLoader.vue_vue_type_script_setup_true_lang.js.map +1 -1
  191. package/dist/components/VSlider/VSlider.d.ts +5 -13
  192. package/dist/components/VSlider/VSlider.js.map +1 -1
  193. package/dist/components/VSlider/VSlider.vue_vue_type_script_setup_true_lang.js.map +1 -1
  194. package/dist/components/VSnackbar/VSnackbar.js.map +1 -1
  195. package/dist/components/VSnackbar/VSnackbar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  196. package/dist/components/VSnackbar/state.d.ts +4 -17
  197. package/dist/components/VSnackbar/state.js.map +1 -1
  198. package/dist/components/VSpinner/VSpinner.d.ts +3 -5
  199. package/dist/components/VSpinner/VSpinner.js.map +1 -1
  200. package/dist/components/VSpinner/VSpinner.vue_vue_type_script_setup_true_lang.js.map +1 -1
  201. package/dist/components/VSwitch/VSwitch.js.map +1 -1
  202. package/dist/components/VSwitch/VSwitch.vue_vue_type_script_setup_true_lang.js.map +1 -1
  203. package/dist/components/VTabs/VTab.d.ts +1 -5
  204. package/dist/components/VTabs/VTab.js.map +1 -1
  205. package/dist/components/VTabs/VTab.vue_vue_type_script_setup_true_lang.js.map +1 -1
  206. package/dist/components/VTabs/VTabPanel.js.map +1 -1
  207. package/dist/components/VTabs/VTabPanel.vue_vue_type_script_setup_true_lang.js.map +1 -1
  208. package/dist/components/VTabs/VTabs.d.ts +5 -17
  209. package/dist/components/VTabs/VTabs.js.map +1 -1
  210. package/dist/components/VTabs/VTabs.vue_vue_type_script_setup_true_lang.js.map +1 -1
  211. package/dist/components/VTabs/context.js.map +1 -1
  212. package/dist/components/VTextarea/VTextarea.d.ts +13 -20
  213. package/dist/components/VTextarea/VTextarea.js.map +1 -1
  214. package/dist/components/VTextarea/VTextarea.vue_vue_type_script_setup_true_lang.js.map +1 -1
  215. package/dist/components/VTimeInput/VTimeInput.d.ts +8 -21
  216. package/dist/components/VTimeInput/VTimeInput.js.map +1 -1
  217. package/dist/components/VTimeInput/VTimeInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
  218. package/dist/components/VTimeInput/search.d.ts +3 -34
  219. package/dist/components/VTimeInput/search.js.map +1 -1
  220. package/dist/components/VTimePicker/VTimePicker.d.ts +9 -31
  221. package/dist/components/VTimePicker/VTimePicker.js.map +1 -1
  222. package/dist/components/VTimePicker/VTimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
  223. package/dist/components/VTimePicker/limits.d.ts +18 -45
  224. package/dist/components/VTimePicker/limits.js.map +1 -1
  225. package/dist/components/VToast/VToast.js.map +1 -1
  226. package/dist/components/VToast/VToast.vue_vue_type_script_setup_true_lang.js.map +1 -1
  227. package/dist/components/VToast/VToaster.js.map +1 -1
  228. package/dist/components/VToast/VToaster.vue_vue_type_script_setup_true_lang.js.map +1 -1
  229. package/dist/components/VToast/state.d.ts +2 -7
  230. package/dist/components/VToast/state.js.map +1 -1
  231. package/dist/components/VToggle/VToggle.d.ts +5 -9
  232. package/dist/components/VToggle/VToggle.js.map +1 -1
  233. package/dist/components/VToggle/VToggle.vue_vue_type_script_setup_true_lang.js.map +1 -1
  234. package/dist/components/VToggle/VToggleItem.d.ts +1 -9
  235. package/dist/components/VToggle/VToggleItem.js.map +1 -1
  236. package/dist/components/VToggle/VToggleItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  237. package/dist/components/VToggle/context.js.map +1 -1
  238. package/dist/components/VTooltip/VTooltip.d.ts +3 -16
  239. package/dist/components/VTooltip/VTooltip.js.map +1 -1
  240. package/dist/components/VTooltip/VTooltip.vue_vue_type_script_setup_true_lang.js +2 -2
  241. package/dist/components/VTooltip/VTooltip.vue_vue_type_script_setup_true_lang.js.map +1 -1
  242. package/dist/components/VTypography/VTypography.d.ts +4 -8
  243. package/dist/components/VTypography/VTypography.js.map +1 -1
  244. package/dist/components/VTypography/VTypography.vue_vue_type_script_setup_true_lang.js.map +1 -1
  245. package/dist/composables/useAriaLabel.js.map +1 -1
  246. package/dist/composables/useClearable.d.ts +2 -8
  247. package/dist/composables/useClearable.js.map +1 -1
  248. package/dist/composables/useControlShape.js.map +1 -1
  249. package/dist/composables/useDetailsOpen.d.ts +2 -10
  250. package/dist/composables/useDetailsOpen.js.map +1 -1
  251. package/dist/composables/useFieldIds.js.map +1 -1
  252. package/dist/composables/useFieldPanel.d.ts +4 -17
  253. package/dist/composables/useFieldPanel.js.map +1 -1
  254. package/dist/composables/useFileDrop.js.map +1 -1
  255. package/dist/composables/useFileField.d.ts +1 -5
  256. package/dist/composables/useFileField.js.map +1 -1
  257. package/dist/composables/useFocusoutDismiss.js.map +1 -1
  258. package/dist/composables/useIconClickHandlers.d.ts +4 -19
  259. package/dist/composables/useIconClickHandlers.js.map +1 -1
  260. package/dist/composables/useInertLink.d.ts +1 -1
  261. package/dist/composables/useInertLink.js.map +1 -1
  262. package/dist/composables/useLiveAnnouncer.js.map +1 -1
  263. package/dist/composables/useMaskedField.d.ts +12 -27
  264. package/dist/composables/useMaskedField.js.map +1 -1
  265. package/dist/composables/usePopover.d.ts +3 -11
  266. package/dist/composables/usePopover.js.map +1 -1
  267. package/dist/composables/useProgressValue.js.map +1 -1
  268. package/dist/composables/useRootAttrs.d.ts +0 -9
  269. package/dist/composables/useRootAttrs.js +11 -4
  270. package/dist/composables/useRootAttrs.js.map +1 -1
  271. package/dist/composables/useSlotNodes.d.ts +3 -14
  272. package/dist/composables/useSlotNodes.js.map +1 -1
  273. package/dist/composables/useTextLimit.d.ts +4 -16
  274. package/dist/composables/useTextLimit.js.map +1 -1
  275. package/dist/composables/useTimer.d.ts +2 -15
  276. package/dist/composables/useTimer.js.map +1 -1
  277. package/dist/i18n/en.js.map +1 -1
  278. package/dist/i18n/fr.js.map +1 -1
  279. package/dist/i18n/state.d.ts +9 -38
  280. package/dist/i18n/state.js.map +1 -1
  281. package/dist/i18n/types.d.ts +19 -81
  282. package/dist/icons.d.ts +2 -12
  283. package/dist/styles.css +1 -1
  284. package/dist/tokens/css.d.ts +3 -16
  285. package/dist/tokens/css.js.map +1 -1
  286. package/dist/tokens/index.d.ts +5 -0
  287. package/dist/tokens/index.js.map +1 -1
  288. package/dist/tokens/primitives.js.map +1 -1
  289. package/dist/tokens/semantic.d.ts +6 -23
  290. package/dist/tokens/semantic.js +5 -0
  291. package/dist/tokens/semantic.js.map +1 -1
  292. package/dist/tokens/themes/dark.js.map +1 -1
  293. package/dist/tokens/types.d.ts +2 -12
  294. package/dist/tokens/types.js.map +1 -1
  295. package/dist/tokens.json +14 -0
  296. package/dist/types.d.ts +3 -21
  297. package/dist/utils/array.d.ts +2 -4
  298. package/dist/utils/array.js.map +1 -1
  299. package/dist/utils/arrowNav.d.ts +2 -26
  300. package/dist/utils/arrowNav.js.map +1 -1
  301. package/dist/utils/chip.d.ts +1 -8
  302. package/dist/utils/chip.js.map +1 -1
  303. package/dist/utils/clock.d.ts +16 -39
  304. package/dist/utils/clock.js.map +1 -1
  305. package/dist/utils/css.d.ts +5 -16
  306. package/dist/utils/css.js.map +1 -1
  307. package/dist/utils/date.d.ts +17 -60
  308. package/dist/utils/date.js.map +1 -1
  309. package/dist/utils/direction.d.ts +2 -9
  310. package/dist/utils/direction.js.map +1 -1
  311. package/dist/utils/env.d.ts +2 -15
  312. package/dist/utils/env.js.map +1 -1
  313. package/dist/utils/file.d.ts +8 -46
  314. package/dist/utils/file.js.map +1 -1
  315. package/dist/utils/focus.d.ts +1 -14
  316. package/dist/utils/focus.js +1 -6
  317. package/dist/utils/focus.js.map +1 -1
  318. package/dist/utils/hostWarns.d.ts +3 -8
  319. package/dist/utils/hostWarns.js.map +1 -1
  320. package/dist/utils/ids.d.ts +2 -7
  321. package/dist/utils/ids.js.map +1 -1
  322. package/dist/utils/matcher.d.ts +1 -8
  323. package/dist/utils/matcher.js.map +1 -1
  324. package/dist/utils/memo.d.ts +1 -11
  325. package/dist/utils/memo.js.map +1 -1
  326. package/dist/utils/number.d.ts +1 -7
  327. package/dist/utils/number.js.map +1 -1
  328. package/dist/utils/text.d.ts +4 -23
  329. package/dist/utils/text.js.map +1 -1
  330. package/dist/utils/time.d.ts +4 -12
  331. package/dist/utils/time.js.map +1 -1
  332. package/dist/utils/vnode.d.ts +0 -10
  333. package/dist/utils/vnode.js.map +1 -1
  334. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"VRadio.vue_vue_type_script_setup_true_lang.js","names":["$slots"],"sources":["../../../src/components/VRadio/VRadio.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * A radio button whose dot is drawn by the design system, on the same principle as\n * VCheckbox: the real `<input type=\"radio\">` stays in place and only its own drawing\n * is hidden.\n *\n * The group is native as well. Several VRadio sharing the same `name` and the same\n * v-model form one choice, and it is the browser that then makes the arrow keys move\n * between them, that lets only one be selected, and that gives the group a single\n * stop in the tab order. There is no JavaScript here for any of it; the only piece this\n * component writes is the refusal `readonly` asks for, which a radio has no native form of.\n */\n\nimport { ref } from 'vue'\n\nimport { useFieldIds } from '../../composables/useFieldIds'\nimport { useRootAttrs } from '../../composables/useRootAttrs'\nimport type { ItemValue } from '../../types'\n\n/** Which side of the dot the label sits on. */\nexport type RadioLabelPosition = 'start' | 'end'\n\ninterface RadioProps {\n /**\n * What choosing this button means. The group's v-model holds the value of the\n * selected button, so this is what it becomes when this one is picked.\n */\n value: ItemValue\n /** The text beside the dot, which names it. The default slot replaces it. */\n label?: string\n /**\n * A line of help under the label. It is tied to the radio button for assistive\n * technology, so it is read out after the label rather than as part of it.\n */\n hint?: string\n /** Which side of the dot the label sits on. */\n labelPosition?: RadioLabelPosition\n /**\n * Pushes the label and the dot to opposite ends of the line, the row taking the\n * full width available.\n */\n spread?: boolean\n /**\n * Marks the field as invalid, which colours the dot and tells assistive technology\n * so. It is for a rule the browser cannot check by itself.\n */\n invalid?: boolean\n /** Makes this choice unusable, greyed out through the colour tokens. */\n disabled?: boolean\n /**\n * Shows the selection without allowing it to be changed. The button can still be\n * focused and is still submitted with its form; a click or an arrow key simply selects\n * nothing. Set it on every button of the group.\n */\n readonly?: boolean\n}\n\nconst props = withDefaults(defineProps<RadioProps>(), {\n label: undefined,\n hint: undefined,\n labelPosition: 'end',\n spread: false,\n invalid: false,\n disabled: false,\n readonly: false,\n})\n\n// @a11y — the redirection buys the whole keyboard. Moving between the buttons of a group is\n// the browser's job, but it only groups inputs that share a `name` — so redirecting the\n// attributes is what makes the arrow keys work at all. The root being a layout box, `name`\n// left on it would reach nothing.\ndefineOptions({ inheritAttrs: false })\nconst { attrs, rootClass, rootStyle, forwardedAttrs } = useRootAttrs()\nconst { hintId, describedBy } = useFieldIds(attrs, () => !!props.hint)\n\n/**\n * The value selected in the group, shared by every radio carrying the same `name`. It is\n * empty until one is chosen, and a radio is selected when it matches its own `value`.\n */\nconst model = defineModel<ItemValue>({ default: '' })\n\ndefineSlots<{\n /** The label, when it needs more than the `label` prop's text. It is clickable. */\n default?(): unknown\n}>()\n\nconst inputEl = ref<HTMLInputElement | null>(null)\n\n// @core\n// The native `readonly` attribute does nothing on a radio button. Cancelling the click is\n// what refuses the selection: the browser puts the group's previous selection back and fires\n// no `change`. It covers the arrow keys too, which select the next button of the group\n// through a click the browser dispatches on it — so the focus still moves, the selection\n// does not.\n//\n// No `aria-readonly` goes with it, unlike VCheckbox and VSwitch: ARIA allows it on a\n// `radiogroup` and not on a `radio`, and axe fails the page for it.\nfunction refuseWhenReadonly(event: MouseEvent) {\n if (props.readonly) event.preventDefault()\n}\n\n// The root is a wrapper, so a template ref on the component reaches the layout box and not\n// the control: these two are the way to the real radio button.\ndefineExpose({\n /** Moves the focus to the real radio button. */\n focus: (options?: FocusOptions) => inputEl.value?.focus(options),\n /** The real `<input type=\"radio\">`, for what `focus` does not cover. */\n el: inputEl,\n})\n</script>\n\n<template>\n <span\n class=\"v-radio v-choice\"\n :class=\"rootClass\"\n :style=\"rootStyle\"\n :data-label-position=\"labelPosition\"\n :data-spread=\"spread ? '' : undefined\"\n :data-readonly=\"readonly ? '' : undefined\"\n >\n <label class=\"v-choice-row\">\n <input\n ref=\"inputEl\"\n v-model=\"model\"\n type=\"radio\"\n class=\"v-radio-input v-hidden-input\"\n :aria-invalid=\"invalid || undefined\"\n v-bind=\"forwardedAttrs\"\n :value=\"value\"\n :disabled=\"disabled\"\n :aria-describedby=\"describedBy\"\n @click=\"refuseWhenReadonly\"\n />\n <span class=\"v-radio-dot\" aria-hidden=\"true\" />\n <span v-if=\"$slots.default || label\" class=\"v-radio-label v-choice-label\">\n <slot>{{ label }}</slot>\n </span>\n </label>\n <span v-if=\"hint\" :id=\"hintId\" class=\"v-radio-hint v-choice-hint\">{{ hint }}</span>\n </span>\n</template>\n\n<style>\n@layer vectis.components {\n /* The dot works exactly like VCheckbox's box, the accent filling it once the input is\n checked, with the small inner disc drawn as a pseudo-element in currentcolor so it\n follows whatever colour the state gives the ring's content. */\n .v-radio-dot {\n display: inline-grid;\n place-items: center;\n width: var(--vectis-control-size-check);\n height: var(--vectis-control-size-check);\n background: transparent;\n border: var(--vectis-control-border-width) solid var(--vectis-color-border-strong);\n border-radius: var(--vectis-radius-pill);\n color: var(--vectis-color-text-on-accent);\n transition:\n background-color var(--vectis-duration-fast) var(--vectis-ease-default),\n border-color var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n\n .v-radio-dot::before {\n content: '';\n width: var(--vectis-control-size-check-dot);\n height: var(--vectis-control-size-check-dot);\n border-radius: var(--vectis-radius-pill);\n background: currentcolor;\n opacity: 0;\n transition: opacity var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n\n .v-radio-input:checked + .v-radio-dot::before {\n opacity: 1;\n }\n\n /* The state painting, rule for rule the same as VCheckbox's with its own classes: keep the\n two ALIGNED. The states below weigh (0,3,0), bar the read-only base at (0,2,0), so their\n ORDER arbitrates them: checked, read-only, invalid, then disabled last.\n\n The two hovers sit at (0,7,0) and therefore beat every one of them on specificity, order\n or no order — which is why they have to EXCLUDE by hand each state they must not repaint.\n Forgetting the invalid pair is what once rubbed the danger border out under the pointer,\n on a control whose whole point at that moment is to look wrong. */\n .v-radio:not([data-readonly])\n .v-choice-row:hover\n .v-radio-input:not(:disabled, :checked, :user-invalid, [aria-invalid='true'])\n + .v-radio-dot {\n border-color: color-mix(\n in oklab,\n var(--vectis-color-border-strong),\n var(--vectis-color-text) 15%\n );\n }\n\n .v-radio-input:checked + .v-radio-dot {\n background: var(--vectis-color-accent);\n border-color: var(--vectis-color-accent);\n }\n\n .v-radio:not([data-readonly])\n .v-choice-row:hover\n .v-radio-input:not(:disabled, :user-invalid, [aria-invalid='true']):checked\n + .v-radio-dot {\n background: var(--vectis-color-accent-hover);\n border-color: var(--vectis-color-accent-hover);\n }\n\n /* Read-only sinks like a read-only field, and a selected control trades the accent for the\n muted text colour: still plainly on, no longer inviting a click. The inner disc takes the\n surface colour, which contrasts with that fill in both themes, where white would vanish\n against the light grey of the dark theme. `:where()` keeps both rules at the weight of\n the states they sit between. */\n :where(.v-radio[data-readonly]) .v-radio-input + .v-radio-dot {\n background: var(--vectis-color-surface-sunken);\n border-color: var(--vectis-color-border);\n }\n\n :where(.v-radio[data-readonly]) .v-radio-input:checked + .v-radio-dot {\n background: var(--vectis-color-text-muted);\n border-color: var(--vectis-color-text-muted);\n color: var(--vectis-color-surface);\n }\n\n .v-radio-input:user-invalid + .v-radio-dot,\n .v-radio-input[aria-invalid='true'] + .v-radio-dot {\n border-color: var(--vectis-color-danger);\n }\n\n .v-radio-input:disabled + .v-radio-dot {\n background: var(--vectis-color-surface-muted);\n border-color: var(--vectis-color-border);\n color: var(--vectis-color-text-subtle);\n }\n\n @media (forced-colors: active) {\n /* Windows forced colors erase every author colour: a `background` becomes `Canvas` and a\n `border-color` becomes `CanvasText`, so a selected radio loses its inner disc outright, that disc being\n a `background` on a `background` where a checkbox has a `stroke` that survives. The system\n Highlight pair is what says \"selected\" here, as it does on a pressed VToggleItem, a\n selected VChip and the current VPagination page.\n\n The class is repeated to (0,8,0) so the row's own hover rules, which reach (0,7,0),\n cannot repaint it: `forced-color-adjust: none` takes the forcing off this element, and\n a hover left winning would then paint its REAL grey over the system colour. */\n .v-radio-input.v-radio-input.v-radio-input.v-radio-input.v-radio-input:checked:not(:disabled)\n + .v-radio-dot {\n forced-color-adjust: none;\n background: Highlight;\n border-color: Highlight;\n color: HighlightText;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-radio-dot,\n .v-radio-dot::before {\n transition: none;\n }\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyDA,IAAM,IAAQ,GAeR,EAAE,UAAO,cAAW,cAAW,sBAAmB,EAAa,GAC/D,EAAE,WAAQ,mBAAgB,EAAY,SAAa,CAAC,CAAC,EAAM,IAAI,GAM/D,IAAQ,EAAsB,GAAA,YAAgB,GAO9C,IAAU,EAA6B,IAAI;EAWjD,SAAS,EAAmB,GAAmB;GAC7C,AAAI,EAAM,YAAU,EAAM,eAAe;EAC3C;SAIA,EAAa;GAEX,QAAQ,MAA2B,EAAQ,OAAO,MAAM,CAAO;GAE/D,IAAI;EACN,CAAC,mBAIC,EA2BO,QAAA;GA1BL,OAAK,EAAA,CAAC,oBACE,EAAA,CAAA,CAAS,CAAA;GAChB,OAAK,EAAE,EAAA,CAAA,CAAS;GAChB,uBAAqB,EAAA;GACrB,eAAa,EAAA,SAAM,KAAQ,KAAA;GAC3B,iBAAe,EAAA,WAAQ,KAAQ,KAAA;MAEhC,EAiBQ,SAjBR,GAiBQ;KAhBN,EAWE,SAXF,EAWE;aAVI;IAAJ,KAAI;6CACU,QAAA;IACd,MAAK;IACL,OAAM;IACL,gBAAc,EAAA,WAAW,KAAA;MAClB,EAAA,CAAA,GAAc;IACrB,OAAO,EAAA;IACP,UAAU,EAAA;IACV,oBAAkB,EAAA,CAAA;IAClB,SAAO;0BARC,EAAA,KAAK,CAAA,CAAA;YAUhB,EAA+C,QAAA;IAAzC,OAAM;IAAc,eAAY;;GAC1BA,EAAAA,OAAO,WAAW,EAAA,SAAA,EAAA,GAA9B,EAEO,QAFP,GAEO,CADL,EAAwB,EAAA,QAAA,WAAA,CAAA,SAAA,CAAA,EAAA,EAAf,EAAA,KAAK,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,KAAA,EAAA,IAAA,EAAA;MAGN,EAAA,QAAA,EAAA,GAAZ,EAAmF,QAAA;;GAAhE,IAAI,EAAA,CAAA;GAAQ,OAAM;OAAgC,EAAA,IAAI,GAAA,GAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,GAAA,IAAA,CAAA"}
1
+ {"version":3,"file":"VRadio.vue_vue_type_script_setup_true_lang.js","names":["$slots"],"sources":["../../../src/components/VRadio/VRadio.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Retain the native radio for keyboard selection and forms. Its hint stays outside the label so\n * it does not become part of the accessible name.\n */\n\nimport { ref } from 'vue'\n\nimport { useFieldIds } from '../../composables/useFieldIds'\nimport { useRootAttrs } from '../../composables/useRootAttrs'\nimport type { ItemValue } from '../../types'\n\n/** Which side of the dot the label sits on. */\nexport type RadioLabelPosition = 'start' | 'end'\n\ninterface RadioProps {\n /**\n * What choosing this button means. The group's v-model holds the value of the\n * selected button, so this is what it becomes when this one is picked.\n */\n value: ItemValue\n /** The text beside the dot, which names it. The default slot replaces it. */\n label?: string\n /**\n * A line of help under the label. It is tied to the radio button for assistive\n * technology, so it is read out after the label rather than as part of it.\n */\n hint?: string\n /** Which side of the dot the label sits on. */\n labelPosition?: RadioLabelPosition\n /**\n * Pushes the label and the dot to opposite ends of the line, the row taking the\n * full width available.\n */\n spread?: boolean\n /**\n * Marks the field as invalid, which colours the dot and tells assistive technology\n * so. It is for a rule the browser cannot check by itself.\n */\n invalid?: boolean\n /** Makes this choice unusable, greyed out through the colour tokens. */\n disabled?: boolean\n /** Shows the selection without allowing it to be changed. */\n readonly?: boolean\n}\n\nconst props = withDefaults(defineProps<RadioProps>(), {\n label: undefined,\n hint: undefined,\n labelPosition: 'end',\n spread: false,\n invalid: false,\n disabled: false,\n readonly: false,\n})\n\n// @a11y\n// The browser's job, but it only groups inputs that share a `name`; so redirecting the\n// attributes is what makes the arrow keys work at all. The root being a layout box, `name` left\n// on it would reach nothing.\ndefineOptions({ inheritAttrs: false })\nconst { attrs, rootClass, rootStyle, forwardedAttrs } = useRootAttrs()\nconst { hintId, describedBy } = useFieldIds(attrs, () => !!props.hint)\n\n/**\n * The value selected in the group, shared by every radio carrying the same `name`. It is\n * empty until one is chosen, and a radio is selected when it matches its own `value`.\n */\nconst model = defineModel<ItemValue>({ default: '' })\n\ndefineSlots<{\n /** The label, when it needs more than the `label` prop's text. It is clickable. */\n default?(): unknown\n}>()\n\nconst inputEl = ref<HTMLInputElement | null>(null)\n\n// @core\n// The native `readonly` attribute does nothing on a radio button. Cancelling the click is what\n// refuses the selection: the browser puts the group's previous selection back and fires no\n// `change`.\nfunction refuseWhenReadonly(event: MouseEvent) {\n if (props.readonly) event.preventDefault()\n}\n\n// The root is a wrapper, so a template ref on the component reaches the layout box and not\n// the control: these two are the way to the real radio button.\ndefineExpose({\n /** Moves the focus to the real radio button. */\n focus: (options?: FocusOptions) => inputEl.value?.focus(options),\n /** The real `<input type=\"radio\">`, for what `focus` does not cover. */\n el: inputEl,\n})\n</script>\n\n<template>\n <span\n class=\"v-radio v-choice\"\n :class=\"rootClass\"\n :style=\"rootStyle\"\n :data-label-position=\"labelPosition\"\n :data-spread=\"spread ? '' : undefined\"\n :data-readonly=\"readonly ? '' : undefined\"\n >\n <label class=\"v-choice-row\">\n <input\n ref=\"inputEl\"\n v-model=\"model\"\n type=\"radio\"\n class=\"v-radio-input v-hidden-input\"\n :aria-invalid=\"invalid || undefined\"\n v-bind=\"forwardedAttrs\"\n :value=\"value\"\n :disabled=\"disabled\"\n :aria-describedby=\"describedBy\"\n @click=\"refuseWhenReadonly\"\n />\n <span class=\"v-radio-dot\" aria-hidden=\"true\" />\n <span v-if=\"$slots.default || label\" class=\"v-radio-label v-choice-label\">\n <slot>{{ label }}</slot>\n </span>\n </label>\n <span v-if=\"hint\" :id=\"hintId\" class=\"v-radio-hint v-choice-hint\">{{ hint }}</span>\n </span>\n</template>\n\n<style>\n@layer vectis.components {\n /* The dot works exactly like VCheckbox's box, the accent filling it once the input is\n checked, with the small inner disc drawn as a pseudo-element in currentcolor so it\n follows whatever colour the state gives the ring's content. */\n .v-radio-dot {\n display: inline-grid;\n place-items: center;\n width: var(--vectis-control-size-check);\n height: var(--vectis-control-size-check);\n background: transparent;\n border: var(--vectis-control-border-width) solid var(--vectis-color-border-strong);\n border-radius: var(--vectis-radius-pill);\n color: var(--vectis-color-text-on-accent);\n transition:\n background-color var(--vectis-duration-fast) var(--vectis-ease-default),\n border-color var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n\n .v-radio-dot::before {\n content: '';\n width: var(--vectis-control-size-check-dot);\n height: var(--vectis-control-size-check-dot);\n border-radius: var(--vectis-radius-pill);\n background: currentcolor;\n opacity: 0;\n transition: opacity var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n\n .v-radio-input:checked + .v-radio-dot::before {\n opacity: 1;\n }\n\n /*\n * The states below weigh (0,3,0), bar the read-only base at (0,2,0), so their ORDER\n * arbitrates them: checked, read-only, invalid, then disabled last. The two hovers sit at\n * (0,7,0) and therefore beat every one of them on specificity, order or no order; which is\n * why they have to EXCLUDE by hand each state they must not repaint.\n */\n .v-radio:not([data-readonly])\n .v-choice-row:hover\n .v-radio-input:not(:disabled, :checked, :user-invalid, [aria-invalid='true'])\n + .v-radio-dot {\n border-color: color-mix(\n in oklab,\n var(--vectis-color-border-strong),\n var(--vectis-color-text) 15%\n );\n }\n\n .v-radio-input:checked + .v-radio-dot {\n background: var(--vectis-color-accent);\n border-color: var(--vectis-color-accent);\n }\n\n .v-radio:not([data-readonly])\n .v-choice-row:hover\n .v-radio-input:not(:disabled, :user-invalid, [aria-invalid='true']):checked\n + .v-radio-dot {\n background: var(--vectis-color-accent-hover);\n border-color: var(--vectis-color-accent-hover);\n }\n\n /*\n * The inner disc takes the surface colour, which contrasts with that fill in both themes,\n * where white would vanish against the light grey of the dark theme. `:where()` keeps both\n * rules at the weight of the states they sit between.\n */\n :where(.v-radio[data-readonly]) .v-radio-input + .v-radio-dot {\n background: var(--vectis-color-surface-sunken);\n border-color: var(--vectis-color-border);\n }\n\n :where(.v-radio[data-readonly]) .v-radio-input:checked + .v-radio-dot {\n background: var(--vectis-color-text-muted);\n border-color: var(--vectis-color-text-muted);\n color: var(--vectis-color-surface);\n }\n\n .v-radio-input:user-invalid + .v-radio-dot,\n .v-radio-input[aria-invalid='true'] + .v-radio-dot {\n border-color: var(--vectis-color-danger);\n }\n\n .v-radio-input:disabled + .v-radio-dot {\n background: var(--vectis-color-surface-muted);\n border-color: var(--vectis-color-border);\n color: var(--vectis-color-text-subtle);\n }\n\n @media (forced-colors: active) {\n /*\n * The class is repeated to (0,8,0) so the row's own hover rules, which reach (0,7,0),\n * cannot repaint it: `forced-color-adjust: none` takes the forcing off this element, and a\n * hover left winning would then paint its real grey over the system colour.\n */\n .v-radio-input.v-radio-input.v-radio-input.v-radio-input.v-radio-input:checked:not(:disabled)\n + .v-radio-dot {\n forced-color-adjust: none;\n background: Highlight;\n border-color: Highlight;\n color: HighlightText;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-radio-dot,\n .v-radio-dot::before {\n transition: none;\n }\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8CA,IAAM,IAAQ,GAeR,EAAE,UAAO,cAAW,cAAW,sBAAmB,EAAa,GAC/D,EAAE,WAAQ,mBAAgB,EAAY,SAAa,CAAC,CAAC,EAAM,IAAI,GAM/D,IAAQ,EAAsB,GAAA,YAAgB,GAO9C,IAAU,EAA6B,IAAI;EAMjD,SAAS,EAAmB,GAAmB;GAC7C,AAAI,EAAM,YAAU,EAAM,eAAe;EAC3C;SAIA,EAAa;GAEX,QAAQ,MAA2B,EAAQ,OAAO,MAAM,CAAO;GAE/D,IAAI;EACN,CAAC,mBAIC,EA2BO,QAAA;GA1BL,OAAK,EAAA,CAAC,oBACE,EAAA,CAAA,CAAS,CAAA;GAChB,OAAK,EAAE,EAAA,CAAA,CAAS;GAChB,uBAAqB,EAAA;GACrB,eAAa,EAAA,SAAM,KAAQ,KAAA;GAC3B,iBAAe,EAAA,WAAQ,KAAQ,KAAA;MAEhC,EAiBQ,SAjBR,GAiBQ;KAhBN,EAWE,SAXF,EAWE;aAVI;IAAJ,KAAI;6CACU,QAAA;IACd,MAAK;IACL,OAAM;IACL,gBAAc,EAAA,WAAW,KAAA;MAClB,EAAA,CAAA,GAAc;IACrB,OAAO,EAAA;IACP,UAAU,EAAA;IACV,oBAAkB,EAAA,CAAA;IAClB,SAAO;0BARC,EAAA,KAAK,CAAA,CAAA;YAUhB,EAA+C,QAAA;IAAzC,OAAM;IAAc,eAAY;;GAC1BA,EAAAA,OAAO,WAAW,EAAA,SAAA,EAAA,GAA9B,EAEO,QAFP,GAEO,CADL,EAAwB,EAAA,QAAA,WAAA,CAAA,SAAA,CAAA,EAAA,EAAf,EAAA,KAAK,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,KAAA,EAAA,IAAA,EAAA;MAGN,EAAA,QAAA,EAAA,GAAZ,EAAmF,QAAA;;GAAhE,IAAI,EAAA,CAAA;GAAQ,OAAM;OAAgC,EAAA,IAAI,GAAA,GAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,GAAA,IAAA,CAAA"}
@@ -1,21 +1,8 @@
1
- /**
2
- * A one-pixel rule drawn between two blocks. It renders an `<hr>`, so assistive
3
- * technology already knows it is a separator, and the element takes no focus and
4
- * appears in no keyboard navigation.
5
- *
6
- * It carries no content slot and no spacing prop, on purpose. A divider with a label
7
- * in the middle is really a heading that happens to have a rule, and the space
8
- * around a rule belongs to the layout placing it: the same rule VTypography
9
- * follows.
10
- */
1
+ /** Use a native hr for separator semantics and borders for visibility in forced colours. */
11
2
  /** Which way the rule runs. */
12
3
  export type SeparatorOrientation = 'horizontal' | 'vertical';
13
4
  interface SeparatorProps {
14
- /**
15
- * The direction the rule runs in: across by default, or down the page under
16
- * `vertical`. A vertical rule needs a height to show: as a flex or grid item it
17
- * takes the one of its line, but in ordinary flow the consumer has to set one.
18
- */
5
+ /** The direction the rule runs in: across by default, or down the page under `vertical`. */
19
6
  orientation?: SeparatorOrientation;
20
7
  }
21
8
  declare const __VLS_export: import('vue').DefineComponent<SeparatorProps, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<SeparatorProps> & Readonly<{}>, {
@@ -1 +1 @@
1
- {"version":3,"file":"VSeparator.js","names":[],"sources":["../../../src/components/VSeparator/VSeparator.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// No behavioural JS at all. Choosing an `<hr>` as the root IS the\n// accessibility decision: the `separator` role comes with it, and\n// `aria-orientation` is emitted for the vertical case alone.\n/**\n * A one-pixel rule drawn between two blocks. It renders an `<hr>`, so assistive\n * technology already knows it is a separator, and the element takes no focus and\n * appears in no keyboard navigation.\n *\n * It carries no content slot and no spacing prop, on purpose. A divider with a label\n * in the middle is really a heading that happens to have a rule, and the space\n * around a rule belongs to the layout placing it: the same rule VTypography\n * follows.\n */\n/** Which way the rule runs. */\nexport type SeparatorOrientation = 'horizontal' | 'vertical'\n\ninterface SeparatorProps {\n /**\n * The direction the rule runs in: across by default, or down the page under\n * `vertical`. A vertical rule needs a height to show: as a flex or grid item it\n * takes the one of its line, but in ordinary flow the consumer has to set one.\n */\n orientation?: SeparatorOrientation\n}\n\nwithDefaults(defineProps<SeparatorProps>(), {\n orientation: 'horizontal',\n})\n</script>\n\n<template>\n <!-- aria-orientation is emitted only when it CONTRADICTS what the role already\n implies: a separator is horizontal by default, so stating it would merely\n restate the role. This is the same convention the VTabs tablist follows. -->\n <hr\n class=\"v-separator\"\n :data-orientation=\"orientation\"\n :aria-orientation=\"orientation === 'vertical' ? 'vertical' : undefined\"\n />\n</template>\n\n<style>\n@layer vectis.components {\n .v-separator {\n flex: none;\n /* The rule is painted with a BORDER and not a background. Under Windows forced\n colours a background is forced to Canvas, where a rule drawn that way simply\n vanishes, while a border colour is forced to CanvasText and survives — the\n same argument that made the icon registry ship SVG paths. Everywhere else the\n two paints are pixel-identical, `box-sizing: border-box` keeping the box at\n one pixel in total either way.\n\n The user agent gives an <hr> a 0.5em block margin, an automatic inline one and\n an inset border. All three are cancelled here rather than in the reset: the\n reset sits in a weaker layer, so the margin below would win only by accident.\n\n TRAP — `.v-menu-separator` and `.v-combobox-separator` override that margin\n from THEIR OWN sheet, and which of the two sheets the consumer's bundler puts\n last is not ours to decide. Both are therefore written as the compound\n `.v-separator.v-x-separator`, and every declaration added here falls under the\n same obligation. */\n margin: 0;\n border: 0 solid var(--vectis-color-border);\n }\n\n .v-separator[data-orientation='horizontal'] {\n border-block-start-width: 1px;\n }\n\n /* `align-self: stretch` IS the contract of a vertical rule. An <hr> has no height\n of its own, so the rule only appears when it is a flex or grid item, where this\n makes it take the full cross size of its line whatever the container's\n align-items says. In ordinary flow it collapses to nothing, silently and with no\n error — there it is up to the consumer to give it a block-size. */\n .v-separator[data-orientation='vertical'] {\n align-self: stretch;\n border-inline-start-width: 1px;\n }\n}\n</style>\n"],"mappings":""}
1
+ {"version":3,"file":"VSeparator.js","names":[],"sources":["../../../src/components/VSeparator/VSeparator.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/** Use a native hr for separator semantics and borders for visibility in forced colours. */\n/** Which way the rule runs. */\nexport type SeparatorOrientation = 'horizontal' | 'vertical'\n\ninterface SeparatorProps {\n /** The direction the rule runs in: across by default, or down the page under `vertical`. */\n orientation?: SeparatorOrientation\n}\n\nwithDefaults(defineProps<SeparatorProps>(), {\n orientation: 'horizontal',\n})\n</script>\n\n<template>\n <!--\n Aria-orientation is emitted only when it CONTRADICTS what the role already implies: a\n separator is horizontal by default, so stating it would merely restate the role. This is the\n same convention the VTabs tablist follows.\n -->\n <hr\n class=\"v-separator\"\n :data-orientation=\"orientation\"\n :aria-orientation=\"orientation === 'vertical' ? 'vertical' : undefined\"\n />\n</template>\n\n<style>\n@layer vectis.components {\n .v-separator {\n flex: none;\n /*\n * `.v-menu-separator` and `.v-combobox-separator` override that margin from THEIR own\n * sheet, and which of the two sheets the consumer's bundler puts last is not ours to\n * decide. Both are therefore written as the compound `.v-separator.v-x-separator`, and\n * every declaration added here falls under the same obligation.\n */\n margin: 0;\n border: 0 solid var(--vectis-color-border);\n }\n\n .v-separator[data-orientation='horizontal'] {\n border-block-start-width: 1px;\n }\n\n /*\n * In ordinary flow it collapses to nothing, silently and with no error; there it is up to the\n * consumer to give it a block-size.\n */\n .v-separator[data-orientation='vertical'] {\n align-self: stretch;\n border-inline-start-width: 1px;\n }\n}\n</style>\n"],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"VSeparator.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/VSeparator/VSeparator.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// No behavioural JS at all. Choosing an `<hr>` as the root IS the\n// accessibility decision: the `separator` role comes with it, and\n// `aria-orientation` is emitted for the vertical case alone.\n/**\n * A one-pixel rule drawn between two blocks. It renders an `<hr>`, so assistive\n * technology already knows it is a separator, and the element takes no focus and\n * appears in no keyboard navigation.\n *\n * It carries no content slot and no spacing prop, on purpose. A divider with a label\n * in the middle is really a heading that happens to have a rule, and the space\n * around a rule belongs to the layout placing it: the same rule VTypography\n * follows.\n */\n/** Which way the rule runs. */\nexport type SeparatorOrientation = 'horizontal' | 'vertical'\n\ninterface SeparatorProps {\n /**\n * The direction the rule runs in: across by default, or down the page under\n * `vertical`. A vertical rule needs a height to show: as a flex or grid item it\n * takes the one of its line, but in ordinary flow the consumer has to set one.\n */\n orientation?: SeparatorOrientation\n}\n\nwithDefaults(defineProps<SeparatorProps>(), {\n orientation: 'horizontal',\n})\n</script>\n\n<template>\n <!-- aria-orientation is emitted only when it CONTRADICTS what the role already\n implies: a separator is horizontal by default, so stating it would merely\n restate the role. This is the same convention the VTabs tablist follows. -->\n <hr\n class=\"v-separator\"\n :data-orientation=\"orientation\"\n :aria-orientation=\"orientation === 'vertical' ? 'vertical' : undefined\"\n />\n</template>\n\n<style>\n@layer vectis.components {\n .v-separator {\n flex: none;\n /* The rule is painted with a BORDER and not a background. Under Windows forced\n colours a background is forced to Canvas, where a rule drawn that way simply\n vanishes, while a border colour is forced to CanvasText and survives — the\n same argument that made the icon registry ship SVG paths. Everywhere else the\n two paints are pixel-identical, `box-sizing: border-box` keeping the box at\n one pixel in total either way.\n\n The user agent gives an <hr> a 0.5em block margin, an automatic inline one and\n an inset border. All three are cancelled here rather than in the reset: the\n reset sits in a weaker layer, so the margin below would win only by accident.\n\n TRAP — `.v-menu-separator` and `.v-combobox-separator` override that margin\n from THEIR OWN sheet, and which of the two sheets the consumer's bundler puts\n last is not ours to decide. Both are therefore written as the compound\n `.v-separator.v-x-separator`, and every declaration added here falls under the\n same obligation. */\n margin: 0;\n border: 0 solid var(--vectis-color-border);\n }\n\n .v-separator[data-orientation='horizontal'] {\n border-block-start-width: 1px;\n }\n\n /* `align-self: stretch` IS the contract of a vertical rule. An <hr> has no height\n of its own, so the rule only appears when it is a flex or grid item, where this\n makes it take the full cross size of its line whatever the container's\n align-items says. In ordinary flow it collapses to nothing, silently and with no\n error — there it is up to the consumer to give it a block-size. */\n .v-separator[data-orientation='vertical'] {\n align-self: stretch;\n border-inline-start-width: 1px;\n }\n}\n</style>\n"],"mappings":";;;;;;yBAmCE,EAIE,MAAA;GAHA,OAAM;GACL,oBAAkB,EAAA;GAClB,oBAAkB,EAAA,gBAAW,aAAA,aAA+B,KAAA"}
1
+ {"version":3,"file":"VSeparator.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/VSeparator/VSeparator.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/** Use a native hr for separator semantics and borders for visibility in forced colours. */\n/** Which way the rule runs. */\nexport type SeparatorOrientation = 'horizontal' | 'vertical'\n\ninterface SeparatorProps {\n /** The direction the rule runs in: across by default, or down the page under `vertical`. */\n orientation?: SeparatorOrientation\n}\n\nwithDefaults(defineProps<SeparatorProps>(), {\n orientation: 'horizontal',\n})\n</script>\n\n<template>\n <!--\n Aria-orientation is emitted only when it CONTRADICTS what the role already implies: a\n separator is horizontal by default, so stating it would merely restate the role. This is the\n same convention the VTabs tablist follows.\n -->\n <hr\n class=\"v-separator\"\n :data-orientation=\"orientation\"\n :aria-orientation=\"orientation === 'vertical' ? 'vertical' : undefined\"\n />\n</template>\n\n<style>\n@layer vectis.components {\n .v-separator {\n flex: none;\n /*\n * `.v-menu-separator` and `.v-combobox-separator` override that margin from THEIR own\n * sheet, and which of the two sheets the consumer's bundler puts last is not ours to\n * decide. Both are therefore written as the compound `.v-separator.v-x-separator`, and\n * every declaration added here falls under the same obligation.\n */\n margin: 0;\n border: 0 solid var(--vectis-color-border);\n }\n\n .v-separator[data-orientation='horizontal'] {\n border-block-start-width: 1px;\n }\n\n /*\n * In ordinary flow it collapses to nothing, silently and with no error; there it is up to the\n * consumer to give it a block-size.\n */\n .v-separator[data-orientation='vertical'] {\n align-self: stretch;\n border-inline-start-width: 1px;\n }\n}\n</style>\n"],"mappings":";;;;;;yBAqBE,EAIE,MAAA;GAHA,OAAM;GACL,oBAAkB,EAAA;GAClB,oBAAkB,EAAA,gBAAW,aAAA,aAA+B,KAAA"}
@@ -11,7 +11,7 @@ interface SideNavigationProps {
11
11
  /** The height of the rows, 32 or 40 pixels, inherited by every level. */
12
12
  size?: SideNavigationSize;
13
13
  /**
14
- * Takes 4px off the height of every row. It is a density setting and NOT a collapsed
14
+ * Takes 4px off the height of every row. It is a density setting and not a collapsed
15
15
  * icon-only rail, which this component does not offer.
16
16
  */
17
17
  compact?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"VSideNavigation.js","names":[],"sources":["../../../src/components/VSideNavigation/VSideNavigation.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @keyboard @core\n/**\n * A sidebar's navigation: a tree of links shown in place rather than in a panel, its\n * branches foldable. Written out level by level with its subcomponents, never from an\n * `items` prop.\n *\n * Real `<ul>`/`<li>` markup, where VMenu uses plain containers, and the difference is\n * meaningful: the ARIA menu pattern forbids lists, admitting only `menuitem` and `group`,\n * whereas in a navigation the counting and the nesting ARE the information. \"List of 4\n * items, item 2, itself a list of 3\" is a screen reader describing the site's structure.\n *\n * The folding is native `<details>`: state, keyboard, exclusivity between neighbouring\n * sections and animation all come from the browser. The only behavioural JS is arrow-key\n * focus movement.\n */\n\nimport { provide, ref, useId } from 'vue'\n\nimport { expand_more as expandMoreIcon } from '../VIcon/icons/expand_more'\nimport type { IconSource } from '../VIcon/types'\nimport { sideNavigationKey } from './context'\n\nimport { arrowNavigate } from '../../utils/arrowNav'\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useMessages } from '../../i18n/state'\n\n/** The height of the rows: 32 or 40 pixels. */\nexport type SideNavigationSize = 'sm' | 'md'\n\ninterface SideNavigationProps {\n /**\n * What screen readers announce for this navigation. A page often has several (a\n * main one, a sidebar, a footer) and this is what tells them apart. It falls back\n * to the design system dictionary.\n */\n label?: string\n /** The height of the rows, 32 or 40 pixels, inherited by every level. */\n size?: SideNavigationSize\n /**\n * Takes 4px off the height of every row. It is a density setting and NOT a collapsed\n * icon-only rail, which this component does not offer.\n */\n compact?: boolean\n /**\n * Keeps a single section open at a time WITHIN EACH LEVEL, which the browser does on\n * its own. It is off by default: a sidebar normally lets several sections stay open.\n */\n exclusive?: boolean\n /** The chevron of a closed section: an icon name, or an explicit render. */\n expandIcon?: IconSource\n /**\n * The chevron of an open section. Leave it out and the closed one is simply rotated\n * by 180°.\n */\n collapseIcon?: IconSource\n}\n\nconst props = withDefaults(defineProps<SideNavigationProps>(), {\n label: undefined,\n size: 'md',\n compact: false,\n exclusive: false,\n expandIcon: () => expandMoreIcon,\n collapseIcon: undefined,\n})\n\ndefineSlots<{\n /** The first level of the tree: items, groups and separators. */\n default(): unknown\n}>()\n\nconst m = useMessages()\nconst ariaLabel = useAriaLabel(() => props.label ?? m.value.sideNavigation.label)\n\n// The name shared by the first level's sections. Each item mints another for its own\n// children, which is what keeps the exclusivity local to a level (see context.ts).\nconst rootName = useId()\n\nprovide(sideNavigationKey, {\n get name() {\n return props.exclusive ? rootName : undefined\n },\n get exclusive() {\n return props.exclusive\n },\n get expandIcon() {\n return props.expandIcon\n },\n get collapseIcon() {\n return props.collapseIcon\n },\n})\n\nconst rootEl = ref<HTMLElement | null>(null)\n\n// @keyboard @a11y\n/**\n * What the arrow keys may move to: the header of a branch, and the link of a leaf.\n *\n * Both forms of disabling have to be excluded, since `:disabled` only ever matches a\n * button — an inert link and a disabled branch header are marked with `aria-disabled`\n * instead, exactly as in VMenu's panel.\n */\nconst ROW_SELECTOR = ':is(summary, .v-side-nav-action):not(:disabled):not([aria-disabled=\"true\"])'\n\n// @keyboard @a11y\n/**\n * Whether a row can actually be reached: everything inside a CLOSED branch is skipped,\n * except that branch's own header, which stays focusable.\n *\n * TRAP — this cannot be left to the shared helper, which skips whatever is not\n * displayed. The content of a closed disclosure element is not hidden that way: the\n * browser passes over it by a rule of its own, and it still reports itself as\n * displayed. Walking the ancestors is the only reliable answer, and it also spares one\n * style computation per row.\n */\nfunction reachable(el: HTMLElement, root: HTMLElement): boolean {\n for (\n let child: HTMLElement = el, parent = el.parentElement;\n parent && child !== root;\n child = parent, parent = parent.parentElement\n ) {\n if (parent.tagName === 'DETAILS' && !(parent as HTMLDetailsElement).open) {\n if (child.tagName !== 'SUMMARY') return false\n }\n }\n return true\n}\n\n// @keyboard @a11y\n/*\n * The component's only behavioural JavaScript, and it exists because nothing native\n * moves the focus from one link to the next.\n *\n * It follows the design system's contract: the arrows MOVE the focus and never\n * activate anything. Every visible row also stays a stop in the tab order — the\n * VToggle model — which is what the disclosure navigation pattern calls for.\n */\nfunction onKeydown(event: KeyboardEvent) {\n const root = rootEl.value\n if (!root || event.defaultPrevented) return\n // Only a key pressed ON a row: a field or a menu in a row's `#end` slot is a descendant\n // too, and its caret or its own list must keep the arrows and Home/End.\n if (!(event.target as Element | null)?.matches(ROW_SELECTOR)) return\n arrowNavigate(\n event,\n root,\n () => [...root.querySelectorAll<HTMLElement>(ROW_SELECTOR)].filter((el) => reachable(el, root)),\n { vertical: true },\n )\n}\n</script>\n\n<template>\n <nav\n ref=\"rootEl\"\n class=\"v-side-nav v-control\"\n :data-size=\"size\"\n :data-compact=\"compact ? '' : undefined\"\n :aria-label=\"ariaLabel\"\n @keydown=\"onKeydown\"\n >\n <ul class=\"v-side-nav-list\">\n <slot />\n </ul>\n </nav>\n</template>\n\n<style>\n@layer vectis.components {\n .v-side-nav {\n /*\n * How much one level of the tree is indented by: exactly the room a leading icon\n * occupies, the icon plus the gap after it. That is what makes a subitem's label\n * start on the SAME VERTICAL as its parent's, whether or not the parent has an\n * icon.\n *\n * Both measurements come from the shared size class set on this very element, so\n * the indent follows the size scale with no table of its own, and a consumer who\n * changes the icon size sees it follow. Every level inherits it.\n */\n --side-nav-indent: calc(var(--vectis-icon-size) + var(--control-gap));\n\n font-family: var(--vectis-text-family);\n }\n\n /*\n * The three lists of the tree are stripped of their bullets and their padding here,\n * once, rather than in each of the three components that render one. Nothing can be\n * arbitrated wrongly by doing so: these classes exist nowhere else in the design\n * system.\n *\n * They are laid out as flex columns and not as ordinary blocks, which removes margin\n * collapsing entirely — otherwise a group's margin could escape a branch that is\n * closed, and therefore of zero height, and push the rows apart under it.\n */\n .v-side-nav-list,\n .v-side-nav-children,\n .v-side-nav-group-list {\n display: flex;\n flex-direction: column;\n margin: 0;\n padding: 0;\n list-style: none;\n }\n}\n</style>\n"],"mappings":""}
1
+ {"version":3,"file":"VSideNavigation.js","names":[],"sources":["../../../src/components/VSideNavigation/VSideNavigation.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @keyboard @core\n/**\n * Native details folds branches; JavaScript bridges open models and adds arrow navigation\n * without replacing native links or buttons.\n */\n\nimport { provide, ref, useId } from 'vue'\n\nimport { expand_more as expandMoreIcon } from '../VIcon/icons/expand_more'\nimport type { IconSource } from '../VIcon/types'\nimport { sideNavigationKey } from './context'\n\nimport { arrowNavigate } from '../../utils/arrowNav'\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useMessages } from '../../i18n/state'\n\n/** The height of the rows: 32 or 40 pixels. */\nexport type SideNavigationSize = 'sm' | 'md'\n\ninterface SideNavigationProps {\n /**\n * What screen readers announce for this navigation. A page often has several (a\n * main one, a sidebar, a footer) and this is what tells them apart. It falls back\n * to the design system dictionary.\n */\n label?: string\n /** The height of the rows, 32 or 40 pixels, inherited by every level. */\n size?: SideNavigationSize\n /**\n * Takes 4px off the height of every row. It is a density setting and not a collapsed\n * icon-only rail, which this component does not offer.\n */\n compact?: boolean\n /**\n * Keeps a single section open at a time WITHIN EACH LEVEL, which the browser does on\n * its own. It is off by default: a sidebar normally lets several sections stay open.\n */\n exclusive?: boolean\n /** The chevron of a closed section: an icon name, or an explicit render. */\n expandIcon?: IconSource\n /**\n * The chevron of an open section. Leave it out and the closed one is simply rotated\n * by 180°.\n */\n collapseIcon?: IconSource\n}\n\nconst props = withDefaults(defineProps<SideNavigationProps>(), {\n label: undefined,\n size: 'md',\n compact: false,\n exclusive: false,\n expandIcon: () => expandMoreIcon,\n collapseIcon: undefined,\n})\n\ndefineSlots<{\n /** The first level of the tree: items, groups and separators. */\n default(): unknown\n}>()\n\nconst m = useMessages()\nconst ariaLabel = useAriaLabel(() => props.label ?? m.value.sideNavigation.label)\n\n// The name shared by the first level's sections. Each item mints another for its own children,\n// which keeps the exclusivity local to a level (see context.ts).\nconst rootName = useId()\n\nprovide(sideNavigationKey, {\n get name() {\n return props.exclusive ? rootName : undefined\n },\n get exclusive() {\n return props.exclusive\n },\n get expandIcon() {\n return props.expandIcon\n },\n get collapseIcon() {\n return props.collapseIcon\n },\n})\n\nconst rootEl = ref<HTMLElement | null>(null)\n\n// @keyboard @a11y\n/**\n * What the arrow keys may move to: the header of a branch, and the link of a leaf. Both forms\n * of disabling have to be excluded, since `:disabled` only ever matches a button; an inert link\n * and a disabled branch header are marked with `aria-disabled` instead, exactly as in VMenu's\n * panel.\n */\nconst ROW_SELECTOR = ':is(summary, .v-side-nav-action):not(:disabled):not([aria-disabled=\"true\"])'\n\n// @keyboard @a11y\n/**\n * This cannot be left to the shared helper, which skips whatever is not displayed. The content\n * of a closed disclosure element is not hidden that way: the browser passes over it by a rule\n * of its own, and it still reports itself as displayed.\n */\nfunction reachable(el: HTMLElement, root: HTMLElement): boolean {\n for (\n let child: HTMLElement = el, parent = el.parentElement;\n parent && child !== root;\n child = parent, parent = parent.parentElement\n ) {\n if (parent.tagName === 'DETAILS' && !(parent as HTMLDetailsElement).open) {\n if (child.tagName !== 'SUMMARY') return false\n }\n }\n return true\n}\n\n// @keyboard @a11y\n/*\n * The component's only behavioural JavaScript, and it exists because nothing native moves the\n * focus from one link to the next. It follows the design system's contract: the arrows MOVE the\n * focus and never activate anything.\n */\nfunction onKeydown(event: KeyboardEvent) {\n const root = rootEl.value\n if (!root || event.defaultPrevented) return\n // Only a key pressed on a row: a field or a menu in a row's `#end` slot is a descendant too,\n // and its caret or its own list must keep the arrows and Home/End.\n if (!(event.target as Element | null)?.matches(ROW_SELECTOR)) return\n arrowNavigate(\n event,\n root,\n () => [...root.querySelectorAll<HTMLElement>(ROW_SELECTOR)].filter((el) => reachable(el, root)),\n { vertical: true },\n )\n}\n</script>\n\n<template>\n <nav\n ref=\"rootEl\"\n class=\"v-side-nav v-control\"\n :data-size=\"size\"\n :data-compact=\"compact ? '' : undefined\"\n :aria-label=\"ariaLabel\"\n @keydown=\"onKeydown\"\n >\n <ul class=\"v-side-nav-list\">\n <slot />\n </ul>\n </nav>\n</template>\n\n<style>\n@layer vectis.components {\n .v-side-nav {\n /* Every level inherits it. */\n --side-nav-indent: calc(var(--vectis-icon-size) + var(--control-gap));\n\n font-family: var(--vectis-text-family);\n }\n\n /*\n * They are laid out as flex columns and not as ordinary blocks, which removes margin\n * collapsing entirely; otherwise a group's margin could escape a branch that is closed, and\n * therefore of zero height, and push the rows apart under it.\n */\n .v-side-nav-list,\n .v-side-nav-children,\n .v-side-nav-group-list {\n display: flex;\n flex-direction: column;\n margin: 0;\n padding: 0;\n list-style: none;\n }\n}\n</style>\n"],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"VSideNavigation.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/VSideNavigation/VSideNavigation.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @keyboard @core\n/**\n * A sidebar's navigation: a tree of links shown in place rather than in a panel, its\n * branches foldable. Written out level by level with its subcomponents, never from an\n * `items` prop.\n *\n * Real `<ul>`/`<li>` markup, where VMenu uses plain containers, and the difference is\n * meaningful: the ARIA menu pattern forbids lists, admitting only `menuitem` and `group`,\n * whereas in a navigation the counting and the nesting ARE the information. \"List of 4\n * items, item 2, itself a list of 3\" is a screen reader describing the site's structure.\n *\n * The folding is native `<details>`: state, keyboard, exclusivity between neighbouring\n * sections and animation all come from the browser. The only behavioural JS is arrow-key\n * focus movement.\n */\n\nimport { provide, ref, useId } from 'vue'\n\nimport { expand_more as expandMoreIcon } from '../VIcon/icons/expand_more'\nimport type { IconSource } from '../VIcon/types'\nimport { sideNavigationKey } from './context'\n\nimport { arrowNavigate } from '../../utils/arrowNav'\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useMessages } from '../../i18n/state'\n\n/** The height of the rows: 32 or 40 pixels. */\nexport type SideNavigationSize = 'sm' | 'md'\n\ninterface SideNavigationProps {\n /**\n * What screen readers announce for this navigation. A page often has several (a\n * main one, a sidebar, a footer) and this is what tells them apart. It falls back\n * to the design system dictionary.\n */\n label?: string\n /** The height of the rows, 32 or 40 pixels, inherited by every level. */\n size?: SideNavigationSize\n /**\n * Takes 4px off the height of every row. It is a density setting and NOT a collapsed\n * icon-only rail, which this component does not offer.\n */\n compact?: boolean\n /**\n * Keeps a single section open at a time WITHIN EACH LEVEL, which the browser does on\n * its own. It is off by default: a sidebar normally lets several sections stay open.\n */\n exclusive?: boolean\n /** The chevron of a closed section: an icon name, or an explicit render. */\n expandIcon?: IconSource\n /**\n * The chevron of an open section. Leave it out and the closed one is simply rotated\n * by 180°.\n */\n collapseIcon?: IconSource\n}\n\nconst props = withDefaults(defineProps<SideNavigationProps>(), {\n label: undefined,\n size: 'md',\n compact: false,\n exclusive: false,\n expandIcon: () => expandMoreIcon,\n collapseIcon: undefined,\n})\n\ndefineSlots<{\n /** The first level of the tree: items, groups and separators. */\n default(): unknown\n}>()\n\nconst m = useMessages()\nconst ariaLabel = useAriaLabel(() => props.label ?? m.value.sideNavigation.label)\n\n// The name shared by the first level's sections. Each item mints another for its own\n// children, which is what keeps the exclusivity local to a level (see context.ts).\nconst rootName = useId()\n\nprovide(sideNavigationKey, {\n get name() {\n return props.exclusive ? rootName : undefined\n },\n get exclusive() {\n return props.exclusive\n },\n get expandIcon() {\n return props.expandIcon\n },\n get collapseIcon() {\n return props.collapseIcon\n },\n})\n\nconst rootEl = ref<HTMLElement | null>(null)\n\n// @keyboard @a11y\n/**\n * What the arrow keys may move to: the header of a branch, and the link of a leaf.\n *\n * Both forms of disabling have to be excluded, since `:disabled` only ever matches a\n * button — an inert link and a disabled branch header are marked with `aria-disabled`\n * instead, exactly as in VMenu's panel.\n */\nconst ROW_SELECTOR = ':is(summary, .v-side-nav-action):not(:disabled):not([aria-disabled=\"true\"])'\n\n// @keyboard @a11y\n/**\n * Whether a row can actually be reached: everything inside a CLOSED branch is skipped,\n * except that branch's own header, which stays focusable.\n *\n * TRAP — this cannot be left to the shared helper, which skips whatever is not\n * displayed. The content of a closed disclosure element is not hidden that way: the\n * browser passes over it by a rule of its own, and it still reports itself as\n * displayed. Walking the ancestors is the only reliable answer, and it also spares one\n * style computation per row.\n */\nfunction reachable(el: HTMLElement, root: HTMLElement): boolean {\n for (\n let child: HTMLElement = el, parent = el.parentElement;\n parent && child !== root;\n child = parent, parent = parent.parentElement\n ) {\n if (parent.tagName === 'DETAILS' && !(parent as HTMLDetailsElement).open) {\n if (child.tagName !== 'SUMMARY') return false\n }\n }\n return true\n}\n\n// @keyboard @a11y\n/*\n * The component's only behavioural JavaScript, and it exists because nothing native\n * moves the focus from one link to the next.\n *\n * It follows the design system's contract: the arrows MOVE the focus and never\n * activate anything. Every visible row also stays a stop in the tab order — the\n * VToggle model — which is what the disclosure navigation pattern calls for.\n */\nfunction onKeydown(event: KeyboardEvent) {\n const root = rootEl.value\n if (!root || event.defaultPrevented) return\n // Only a key pressed ON a row: a field or a menu in a row's `#end` slot is a descendant\n // too, and its caret or its own list must keep the arrows and Home/End.\n if (!(event.target as Element | null)?.matches(ROW_SELECTOR)) return\n arrowNavigate(\n event,\n root,\n () => [...root.querySelectorAll<HTMLElement>(ROW_SELECTOR)].filter((el) => reachable(el, root)),\n { vertical: true },\n )\n}\n</script>\n\n<template>\n <nav\n ref=\"rootEl\"\n class=\"v-side-nav v-control\"\n :data-size=\"size\"\n :data-compact=\"compact ? '' : undefined\"\n :aria-label=\"ariaLabel\"\n @keydown=\"onKeydown\"\n >\n <ul class=\"v-side-nav-list\">\n <slot />\n </ul>\n </nav>\n</template>\n\n<style>\n@layer vectis.components {\n .v-side-nav {\n /*\n * How much one level of the tree is indented by: exactly the room a leading icon\n * occupies, the icon plus the gap after it. That is what makes a subitem's label\n * start on the SAME VERTICAL as its parent's, whether or not the parent has an\n * icon.\n *\n * Both measurements come from the shared size class set on this very element, so\n * the indent follows the size scale with no table of its own, and a consumer who\n * changes the icon size sees it follow. Every level inherits it.\n */\n --side-nav-indent: calc(var(--vectis-icon-size) + var(--control-gap));\n\n font-family: var(--vectis-text-family);\n }\n\n /*\n * The three lists of the tree are stripped of their bullets and their padding here,\n * once, rather than in each of the three components that render one. Nothing can be\n * arbitrated wrongly by doing so: these classes exist nowhere else in the design\n * system.\n *\n * They are laid out as flex columns and not as ordinary blocks, which removes margin\n * collapsing entirely — otherwise a group's margin could escape a branch that is\n * closed, and therefore of zero height, and push the rows apart under it.\n */\n .v-side-nav-list,\n .v-side-nav-children,\n .v-side-nav-group-list {\n display: flex;\n flex-direction: column;\n margin: 0;\n padding: 0;\n list-style: none;\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;qCAwGM,IAAe;;;;;;;;;;;;;;;;;EA9CrB,IAAM,IAAQ,GAcR,IAAI,EAAY,GAChB,IAAY,QAAmB,EAAM,SAAS,EAAE,MAAM,eAAe,KAAK,GAI1E,IAAW,EAAM;EAEvB,EAAQ,GAAmB;GACzB,IAAI,OAAO;IACT,OAAO,EAAM,YAAY,IAAW,KAAA;GACtC;GACA,IAAI,YAAY;IACd,OAAO,EAAM;GACf;GACA,IAAI,aAAa;IACf,OAAO,EAAM;GACf;GACA,IAAI,eAAe;IACjB,OAAO,EAAM;GACf;EACF,CAAC;EAED,IAAM,IAAS,EAAwB,IAAI;EAuB3C,SAAS,EAAU,GAAiB,GAA4B;GAC9D,KACE,IAAI,IAAqB,GAAI,IAAS,EAAG,eACzC,KAAU,MAAU,GACpB,IAAQ,GAAQ,IAAS,EAAO,eAEhC,IAAI,EAAO,YAAY,aAAa,CAAE,EAA8B,QAC9D,EAAM,YAAY,WAAW,OAAO;GAG5C,OAAO;EACT;EAWA,SAAS,EAAU,GAAsB;GACvC,IAAM,IAAO,EAAO;GAChB,CAAC,KAAQ,EAAM,oBAGb,EAAM,QAA2B,QAAQ,CAAY,KAC3D,EACE,GACA,SACM,CAAC,GAAG,EAAK,iBAA8B,CAAY,CAAC,CAAC,CAAC,QAAQ,MAAO,EAAU,GAAI,CAAI,CAAC,GAC9F,EAAE,UAAU,GAAK,CACnB;EACF;yBAIE,EAWM,OAAA;YAVA;GAAJ,KAAI;GACJ,OAAM;GACL,aAAW,EAAA;GACX,gBAAc,EAAA,UAAO,KAAQ,KAAA;GAC7B,cAAY,EAAA,CAAA;GACH;MAEV,EAEK,MAFL,GAEK,CADH,EAAQ,EAAA,QAAA,SAAA,CAAA,CAAA,CAAA,GAAA,IAAA,CAAA"}
1
+ {"version":3,"file":"VSideNavigation.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/VSideNavigation/VSideNavigation.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @keyboard @core\n/**\n * Native details folds branches; JavaScript bridges open models and adds arrow navigation\n * without replacing native links or buttons.\n */\n\nimport { provide, ref, useId } from 'vue'\n\nimport { expand_more as expandMoreIcon } from '../VIcon/icons/expand_more'\nimport type { IconSource } from '../VIcon/types'\nimport { sideNavigationKey } from './context'\n\nimport { arrowNavigate } from '../../utils/arrowNav'\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useMessages } from '../../i18n/state'\n\n/** The height of the rows: 32 or 40 pixels. */\nexport type SideNavigationSize = 'sm' | 'md'\n\ninterface SideNavigationProps {\n /**\n * What screen readers announce for this navigation. A page often has several (a\n * main one, a sidebar, a footer) and this is what tells them apart. It falls back\n * to the design system dictionary.\n */\n label?: string\n /** The height of the rows, 32 or 40 pixels, inherited by every level. */\n size?: SideNavigationSize\n /**\n * Takes 4px off the height of every row. It is a density setting and not a collapsed\n * icon-only rail, which this component does not offer.\n */\n compact?: boolean\n /**\n * Keeps a single section open at a time WITHIN EACH LEVEL, which the browser does on\n * its own. It is off by default: a sidebar normally lets several sections stay open.\n */\n exclusive?: boolean\n /** The chevron of a closed section: an icon name, or an explicit render. */\n expandIcon?: IconSource\n /**\n * The chevron of an open section. Leave it out and the closed one is simply rotated\n * by 180°.\n */\n collapseIcon?: IconSource\n}\n\nconst props = withDefaults(defineProps<SideNavigationProps>(), {\n label: undefined,\n size: 'md',\n compact: false,\n exclusive: false,\n expandIcon: () => expandMoreIcon,\n collapseIcon: undefined,\n})\n\ndefineSlots<{\n /** The first level of the tree: items, groups and separators. */\n default(): unknown\n}>()\n\nconst m = useMessages()\nconst ariaLabel = useAriaLabel(() => props.label ?? m.value.sideNavigation.label)\n\n// The name shared by the first level's sections. Each item mints another for its own children,\n// which keeps the exclusivity local to a level (see context.ts).\nconst rootName = useId()\n\nprovide(sideNavigationKey, {\n get name() {\n return props.exclusive ? rootName : undefined\n },\n get exclusive() {\n return props.exclusive\n },\n get expandIcon() {\n return props.expandIcon\n },\n get collapseIcon() {\n return props.collapseIcon\n },\n})\n\nconst rootEl = ref<HTMLElement | null>(null)\n\n// @keyboard @a11y\n/**\n * What the arrow keys may move to: the header of a branch, and the link of a leaf. Both forms\n * of disabling have to be excluded, since `:disabled` only ever matches a button; an inert link\n * and a disabled branch header are marked with `aria-disabled` instead, exactly as in VMenu's\n * panel.\n */\nconst ROW_SELECTOR = ':is(summary, .v-side-nav-action):not(:disabled):not([aria-disabled=\"true\"])'\n\n// @keyboard @a11y\n/**\n * This cannot be left to the shared helper, which skips whatever is not displayed. The content\n * of a closed disclosure element is not hidden that way: the browser passes over it by a rule\n * of its own, and it still reports itself as displayed.\n */\nfunction reachable(el: HTMLElement, root: HTMLElement): boolean {\n for (\n let child: HTMLElement = el, parent = el.parentElement;\n parent && child !== root;\n child = parent, parent = parent.parentElement\n ) {\n if (parent.tagName === 'DETAILS' && !(parent as HTMLDetailsElement).open) {\n if (child.tagName !== 'SUMMARY') return false\n }\n }\n return true\n}\n\n// @keyboard @a11y\n/*\n * The component's only behavioural JavaScript, and it exists because nothing native moves the\n * focus from one link to the next. It follows the design system's contract: the arrows MOVE the\n * focus and never activate anything.\n */\nfunction onKeydown(event: KeyboardEvent) {\n const root = rootEl.value\n if (!root || event.defaultPrevented) return\n // Only a key pressed on a row: a field or a menu in a row's `#end` slot is a descendant too,\n // and its caret or its own list must keep the arrows and Home/End.\n if (!(event.target as Element | null)?.matches(ROW_SELECTOR)) return\n arrowNavigate(\n event,\n root,\n () => [...root.querySelectorAll<HTMLElement>(ROW_SELECTOR)].filter((el) => reachable(el, root)),\n { vertical: true },\n )\n}\n</script>\n\n<template>\n <nav\n ref=\"rootEl\"\n class=\"v-side-nav v-control\"\n :data-size=\"size\"\n :data-compact=\"compact ? '' : undefined\"\n :aria-label=\"ariaLabel\"\n @keydown=\"onKeydown\"\n >\n <ul class=\"v-side-nav-list\">\n <slot />\n </ul>\n </nav>\n</template>\n\n<style>\n@layer vectis.components {\n .v-side-nav {\n /* Every level inherits it. */\n --side-nav-indent: calc(var(--vectis-icon-size) + var(--control-gap));\n\n font-family: var(--vectis-text-family);\n }\n\n /*\n * They are laid out as flex columns and not as ordinary blocks, which removes margin\n * collapsing entirely; otherwise a group's margin could escape a branch that is closed, and\n * therefore of zero height, and push the rows apart under it.\n */\n .v-side-nav-list,\n .v-side-nav-children,\n .v-side-nav-group-list {\n display: flex;\n flex-direction: column;\n margin: 0;\n padding: 0;\n list-style: none;\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;qCA6FM,IAAe;;;;;;;;;;;;;;;;;EA7CrB,IAAM,IAAQ,GAcR,IAAI,EAAY,GAChB,IAAY,QAAmB,EAAM,SAAS,EAAE,MAAM,eAAe,KAAK,GAI1E,IAAW,EAAM;EAEvB,EAAQ,GAAmB;GACzB,IAAI,OAAO;IACT,OAAO,EAAM,YAAY,IAAW,KAAA;GACtC;GACA,IAAI,YAAY;IACd,OAAO,EAAM;GACf;GACA,IAAI,aAAa;IACf,OAAO,EAAM;GACf;GACA,IAAI,eAAe;IACjB,OAAO,EAAM;GACf;EACF,CAAC;EAED,IAAM,IAAS,EAAwB,IAAI;EAiB3C,SAAS,EAAU,GAAiB,GAA4B;GAC9D,KACE,IAAI,IAAqB,GAAI,IAAS,EAAG,eACzC,KAAU,MAAU,GACpB,IAAQ,GAAQ,IAAS,EAAO,eAEhC,IAAI,EAAO,YAAY,aAAa,CAAE,EAA8B,QAC9D,EAAM,YAAY,WAAW,OAAO;GAG5C,OAAO;EACT;EAQA,SAAS,EAAU,GAAsB;GACvC,IAAM,IAAO,EAAO;GAChB,CAAC,KAAQ,EAAM,oBAGb,EAAM,QAA2B,QAAQ,CAAY,KAC3D,EACE,GACA,SACM,CAAC,GAAG,EAAK,iBAA8B,CAAY,CAAC,CAAC,CAAC,QAAQ,MAAO,EAAU,GAAI,CAAI,CAAC,GAC9F,EAAE,UAAU,GAAK,CACnB;EACF;yBAIE,EAWM,OAAA;YAVA;GAAJ,KAAI;GACJ,OAAM;GACL,aAAW,EAAA;GACX,gBAAc,EAAA,UAAO,KAAQ,KAAA;GAC7B,cAAY,EAAA,CAAA;GACH;MAEV,EAEK,MAFL,GAEK,CADH,EAAQ,EAAA,QAAA,SAAA,CAAA,CAAA,CAAA,GAAA,IAAA,CAAA"}
@@ -1,9 +1,5 @@
1
1
  interface SideNavigationGroupProps {
2
- /**
3
- * The name of the section, replaced by the `#label` slot. One of the two is
4
- * REQUIRED: it is what names the sublist under it, and a section named by neither
5
- * points its `aria-labelledby` at an empty element.
6
- */
2
+ /** The name of the section, replaced by the `#label` slot. */
7
3
  label?: string;
8
4
  }
9
5
  type __VLS_Slots = {
@@ -1 +1 @@
1
- {"version":3,"file":"VSideNavigationGroup.js","names":[],"sources":["../../../src/components/VSideNavigation/VSideNavigationGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * A named section of the navigation — \"Workspace\", \"Settings\". The name is plain text:\n * it cannot be focused or clicked, and it names the sublist under it for assistive\n * technology.\n *\n * Unlike a menu group, it does NOT claim to be a group in ARIA terms. Such a role\n * cannot be a direct child of a list without breaking what that list is allowed to\n * contain. A NAMED sublist says exactly the same thing in strictly valid HTML — and it\n * gives a group the same shape as a branch, which is what keeps the styling uniform.\n *\n * A group is NOT a level of the hierarchy: it declares neither of the two variables\n * counting the depth, so that count passes through it untouched and the items inside\n * are indented as if the group were not there.\n */\n\nimport { useId } from 'vue'\n\ninterface SideNavigationGroupProps {\n /**\n * The name of the section, replaced by the `#label` slot. One of the two is\n * REQUIRED: it is what names the sublist under it, and a section named by neither\n * points its `aria-labelledby` at an empty element.\n */\n label?: string\n}\n\nwithDefaults(defineProps<SideNavigationGroupProps>(), {\n label: undefined,\n})\n\ndefineSlots<{\n /** The items belonging to this section. */\n default(): unknown\n /** A name made of markup, replacing the `label` prop. */\n label?(): unknown\n}>()\n\nconst labelId = useId()\n</script>\n\n<template>\n <li class=\"v-side-nav-group\">\n <span :id=\"labelId\" class=\"v-side-nav-group-label\"\n ><slot name=\"label\">{{ label }}</slot></span\n >\n <ul class=\"v-side-nav-group-list\" :aria-labelledby=\"labelId\">\n <slot />\n </ul>\n </li>\n</template>\n\n<style>\n@layer vectis.components {\n .v-side-nav-group + .v-side-nav-group,\n .v-side-nav-item + .v-side-nav-group {\n margin-block-start: var(--vectis-space-3);\n }\n\n /*\n * TRAP — the indent repeats the rows' computation rather than sharing a variable with\n * them: a custom property set higher up would be frozen at level zero when substituted.\n */\n .v-side-nav-group-label {\n display: flex;\n align-items: center;\n min-block-size: var(--control-height);\n padding-block: var(--vectis-space-1);\n padding-inline: calc(\n var(--control-padding-inline) + var(--side-nav-level, 0) * var(--side-nav-indent)\n )\n var(--control-padding-inline);\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 }\n}\n</style>\n"],"mappings":""}
1
+ {"version":3,"file":"VSideNavigationGroup.js","names":[],"sources":["../../../src/components/VSideNavigation/VSideNavigationGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { useId } from 'vue'\n\ninterface SideNavigationGroupProps {\n /** The name of the section, replaced by the `#label` slot. */\n label?: string\n}\n\nwithDefaults(defineProps<SideNavigationGroupProps>(), {\n label: undefined,\n})\n\ndefineSlots<{\n /** The items belonging to this section. */\n default(): unknown\n /** A name made of markup, replacing the `label` prop. */\n label?(): unknown\n}>()\n\nconst labelId = useId()\n</script>\n\n<template>\n <li class=\"v-side-nav-group\">\n <span :id=\"labelId\" class=\"v-side-nav-group-label\"\n ><slot name=\"label\">{{ label }}</slot></span\n >\n <ul class=\"v-side-nav-group-list\" :aria-labelledby=\"labelId\">\n <slot />\n </ul>\n </li>\n</template>\n\n<style>\n@layer vectis.components {\n .v-side-nav-group + .v-side-nav-group,\n .v-side-nav-item + .v-side-nav-group {\n margin-block-start: var(--vectis-space-3);\n }\n\n /*\n * The indent repeats the rows' computation rather than sharing a variable with them: a custom\n * property set higher up would be frozen at level zero when substituted.\n */\n .v-side-nav-group-label {\n display: flex;\n align-items: center;\n min-block-size: var(--control-height);\n padding-block: var(--vectis-space-1);\n padding-inline: calc(\n var(--control-padding-inline) + var(--side-nav-level, 0) * var(--side-nav-indent)\n )\n var(--control-padding-inline);\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 }\n}\n</style>\n"],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"VSideNavigationGroup.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/VSideNavigation/VSideNavigationGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * A named section of the navigation — \"Workspace\", \"Settings\". The name is plain text:\n * it cannot be focused or clicked, and it names the sublist under it for assistive\n * technology.\n *\n * Unlike a menu group, it does NOT claim to be a group in ARIA terms. Such a role\n * cannot be a direct child of a list without breaking what that list is allowed to\n * contain. A NAMED sublist says exactly the same thing in strictly valid HTML — and it\n * gives a group the same shape as a branch, which is what keeps the styling uniform.\n *\n * A group is NOT a level of the hierarchy: it declares neither of the two variables\n * counting the depth, so that count passes through it untouched and the items inside\n * are indented as if the group were not there.\n */\n\nimport { useId } from 'vue'\n\ninterface SideNavigationGroupProps {\n /**\n * The name of the section, replaced by the `#label` slot. One of the two is\n * REQUIRED: it is what names the sublist under it, and a section named by neither\n * points its `aria-labelledby` at an empty element.\n */\n label?: string\n}\n\nwithDefaults(defineProps<SideNavigationGroupProps>(), {\n label: undefined,\n})\n\ndefineSlots<{\n /** The items belonging to this section. */\n default(): unknown\n /** A name made of markup, replacing the `label` prop. */\n label?(): unknown\n}>()\n\nconst labelId = useId()\n</script>\n\n<template>\n <li class=\"v-side-nav-group\">\n <span :id=\"labelId\" class=\"v-side-nav-group-label\"\n ><slot name=\"label\">{{ label }}</slot></span\n >\n <ul class=\"v-side-nav-group-list\" :aria-labelledby=\"labelId\">\n <slot />\n </ul>\n </li>\n</template>\n\n<style>\n@layer vectis.components {\n .v-side-nav-group + .v-side-nav-group,\n .v-side-nav-item + .v-side-nav-group {\n margin-block-start: var(--vectis-space-3);\n }\n\n /*\n * TRAP — the indent repeats the rows' computation rather than sharing a variable with\n * them: a custom property set higher up would be frozen at level zero when substituted.\n */\n .v-side-nav-group-label {\n display: flex;\n align-items: center;\n min-block-size: var(--control-height);\n padding-block: var(--vectis-space-1);\n padding-inline: calc(\n var(--control-padding-inline) + var(--side-nav-level, 0) * var(--side-nav-indent)\n )\n var(--control-padding-inline);\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 }\n}\n</style>\n"],"mappings":";;;;;;EAsCA,IAAM,IAAU,EAAM;yBAIpB,EAOK,MAPL,GAOK,CANH,EAEC,QAAA;GAFM,IAAI,EAAA,CAAA;GAAS,OAAM;MACvB,EAAqC,EAAA,QAAA,SAAA,CAAA,SAAA,CAAA,EAAA,EAAf,EAAA,KAAK,GAAA,CAAA,CAAA,CAAA,CAAA,GAAA,GAAA,CAAA,GAE9B,EAEK,MAAA;GAFD,OAAM;GAAyB,mBAAiB,EAAA,CAAA;MAClD,EAAQ,EAAA,QAAA,SAAA,CAAA,GAAA,GAAA,CAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"VSideNavigationGroup.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/VSideNavigation/VSideNavigationGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { useId } from 'vue'\n\ninterface SideNavigationGroupProps {\n /** The name of the section, replaced by the `#label` slot. */\n label?: string\n}\n\nwithDefaults(defineProps<SideNavigationGroupProps>(), {\n label: undefined,\n})\n\ndefineSlots<{\n /** The items belonging to this section. */\n default(): unknown\n /** A name made of markup, replacing the `label` prop. */\n label?(): unknown\n}>()\n\nconst labelId = useId()\n</script>\n\n<template>\n <li class=\"v-side-nav-group\">\n <span :id=\"labelId\" class=\"v-side-nav-group-label\"\n ><slot name=\"label\">{{ label }}</slot></span\n >\n <ul class=\"v-side-nav-group-list\" :aria-labelledby=\"labelId\">\n <slot />\n </ul>\n </li>\n</template>\n\n<style>\n@layer vectis.components {\n .v-side-nav-group + .v-side-nav-group,\n .v-side-nav-item + .v-side-nav-group {\n margin-block-start: var(--vectis-space-3);\n }\n\n /*\n * The indent repeats the rows' computation rather than sharing a variable with them: a custom\n * property set higher up would be frozen at level zero when substituted.\n */\n .v-side-nav-group-label {\n display: flex;\n align-items: center;\n min-block-size: var(--control-height);\n padding-block: var(--vectis-space-1);\n padding-inline: calc(\n var(--control-padding-inline) + var(--side-nav-level, 0) * var(--side-nav-indent)\n )\n var(--control-padding-inline);\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 }\n}\n</style>\n"],"mappings":";;;;;;EAmBA,IAAM,IAAU,EAAM;yBAIpB,EAOK,MAPL,GAOK,CANH,EAEC,QAAA;GAFM,IAAI,EAAA,CAAA;GAAS,OAAM;MACvB,EAAqC,EAAA,QAAA,SAAA,CAAA,SAAA,CAAA,EAAA,EAAf,EAAA,KAAK,GAAA,CAAA,CAAA,CAAA,CAAA,GAAA,GAAA,CAAA,GAE9B,EAEK,MAAA;GAFD,OAAM;GAAyB,mBAAiB,EAAA,CAAA;MAClD,EAAQ,EAAA,QAAA,SAAA,CAAA,GAAA,GAAA,CAAA,CAAA,CAAA"}
@@ -24,11 +24,7 @@ interface SideNavigationItemProps {
24
24
  * keyboard path.
25
25
  */
26
26
  disabled?: boolean;
27
- /**
28
- * Renders a branch already open. Only its initial value is read: the browser owns the
29
- * state from then on, so changing this prop later will not fold a branch the reader
30
- * has opened. Bind `v-model:open` to drive it instead.
31
- */
27
+ /** Renders a branch already open. Bind `v-model:open` to drive it instead. */
32
28
  defaultOpen?: boolean;
33
29
  }
34
30
  type __VLS_Props = SideNavigationItemProps;
@@ -1 +1 @@
1
- {"version":3,"file":"VSideNavigationItem.js","names":[],"sources":["../../../src/components/VSideNavigation/VSideNavigationItem.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * One row of a sidebar navigation, in one of two shapes depending on whether it was given\n * subitems — and the difference runs deeper than it looks.\n *\n * A BRANCH is a `<details>`, so its open state, the toggle keyboard, the exclusivity with a\n * neighbouring section and the animation all come from the browser. Its row IS the\n * `<summary>`, which must contain the whole line, `#end` included — hence the click handler\n * there, or anything put in it would fold the branch. The documented consequence is that\n * only NON-focusable content belongs in it: a control would be nested inside a control (WCAG\n * 4.1.2, axe `nested-interactive`), and a `<summary>`'s subtree also serves as its\n * accessible name, which some screen readers flatten.\n *\n * A LEAF is the opposite: the row is a plain container with the action stretched over it by\n * an absolute `::after`, so the whole row is clickable while `#end` stays a SIBLING of the\n * action rather than inside it — which is what keeps a real control there legitimate.\n *\n * The branch's open state and its disabled summary go through `useDetailsOpen`, shared with\n * VAccordionItem.\n */\n\nimport { computed, h, inject, onBeforeUpdate, provide, ref, renderSlot, useId, useSlots } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport { expand_more as expandMoreIcon } from '../VIcon/icons/expand_more'\nimport type { IconSource } from '../VIcon/types'\nimport { sideNavigationKey } from './context'\n\nimport { useDetailsOpen } from '../../composables/useDetailsOpen'\nimport { useInertLink } from '../../composables/useInertLink'\nimport { useRootAttrs } from '../../composables/useRootAttrs'\n\ninterface SideNavigationItemProps {\n /** What the row says, and where it goes. The default slot replaces it. */\n label?: string\n /** A second line under the label, for a status or a short explanation. */\n sublabel?: string\n /**\n * An icon before the label: an icon name, or an explicit render. The `#icon` slot\n * replaces it.\n */\n icon?: IconSource\n /**\n * Where this row leads, which makes it a link. It is IGNORED on a row that has\n * subitems: such a row opens and closes rather than navigating.\n */\n href?: string\n /**\n * Marks this row as the page currently being viewed. It is highlighted, and\n * announced as the current page (`aria-current`).\n */\n current?: boolean\n /**\n * Makes the row unusable: it greys out through the colour tokens and leaves the\n * keyboard path.\n */\n disabled?: boolean\n /**\n * Renders a branch already open. Only its initial value is read: the browser owns the\n * state from then on, so changing this prop later will not fold a branch the reader\n * has opened. Bind `v-model:open` to drive it instead.\n */\n defaultOpen?: boolean\n}\n\n// The root element is a list item, which is structure and not the control. Without\n// redirecting them, `target`, `rel`, `download` and the aria-* would land on that list\n// item instead of on the link or the branch header.\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<SideNavigationItemProps>(), {\n label: undefined,\n sublabel: undefined,\n icon: undefined,\n href: undefined,\n current: false,\n disabled: false,\n defaultOpen: false,\n})\n\n// TRAP — \"not bound\" is written as `null` and not `undefined`. A model typed as a plain\n// boolean is declared as such at runtime, and Vue casts an ABSENT boolean prop to `false`,\n// which would silently overwrite `defaultOpen` on every branch. The explicit default disarms that cast.\n/**\n * Whether the branch is open, when the consumer wants to drive or observe it. Left\n * unbound, the browser keeps that state to itself, `defaultOpen` giving only the initial\n * value. `null` means unbound.\n */\nconst open = defineModel<boolean | null>('open', { default: null })\n\nconst emit = defineEmits<{\n // TRAP — never declare a `click` emit alongside it. Vue removes a declared event from\n // the forwarded attributes, and a consumer's own `@click` would then stop reaching the\n // link entirely.\n /** A row WITHOUT subitems was activated, by click or by keyboard. */\n select: []\n}>()\n\ndefineSlots<{\n /**\n * The label of the row, replacing the `label` prop. One of the two is REQUIRED: a\n * navigation row must say where it goes.\n */\n default?(): unknown\n /** A second line made of markup, replacing the `sublabel` prop. */\n sublabel?(): unknown\n /** Free content before the label, which takes the place of `icon`. */\n icon?(): unknown\n /**\n * Free content at the end of the row, before the chevron: a counter, a badge. On a\n * BRANCH it must not be focusable, a control inside the header being a control nested\n * inside another.\n */\n end?(): unknown\n /**\n * The subitems, which turn this row into a branch. Nesting is not limited. The slot\n * must be statically present or absent: whether a row is a branch is decided when it\n * is created.\n */\n children?(): unknown\n}>()\n\nconst { rootClass, rootStyle, forwardedAttrs } = useRootAttrs()\n\nconst slots = useSlots()\n/**\n * Whether this row has subitems, read from the mere PRESENCE of the slot — the same\n * device VMenuItem and VTabs use. The answer is the same on the server and in the\n * browser, so there is no registry to fill in and no hydration mismatch.\n *\n * The trade-off is that a slot present but empty still makes the row a branch, chevron\n * included, over an empty list.\n */\nconst hasChildren = computed(() => !!slots.children)\nconst tag = computed(() =>\n !hasChildren.value && props.href !== undefined ? ('a' as const) : ('button' as const),\n)\n\nconst parent = inject(sideNavigationKey, null)\n\n/**\n * Both chevrons are chosen on the navigation as a whole. The fallback is what keeps an\n * item rendering correctly when it is used outside one.\n */\nconst expandIcon = computed(() => parent?.expandIcon ?? expandMoreIcon)\nconst collapseIcon = computed(() => parent?.collapseIcon)\n\n// @ssr @core\n// Only a BRANCH has children to hand a context to, so a leaf — most rows of a sidebar —\n// mints no id and provides nothing. The test runs once, at setup: the server and the\n// client take the same path because they see the same slot, which is what keeps `useId`\n// in step across hydration, and also why the slot must not come and go later.\nif (slots.children) {\n // The name shared by THIS row's children. It is minted afresh at every level, and that\n // is what keeps \"one section open at a time\" local to a level instead of applying\n // across the whole document.\n const childrenName = useId()\n\n provide(sideNavigationKey, {\n get name() {\n return parent?.exclusive ? childrenName : undefined\n },\n get exclusive() {\n return parent?.exclusive ?? false\n },\n get expandIcon() {\n return expandIcon.value\n },\n get collapseIcon() {\n return collapseIcon.value\n },\n })\n}\n\nconst { openAttr, onToggle, onSummaryClick } = useDetailsOpen(open, {\n defaultOpen: () => props.defaultOpen,\n disabled: () => props.disabled,\n})\n\n// A link says \"page\"; a button, a branch header included, can only say \"true\".\nconst ariaCurrent = computed(() =>\n props.current ? (tag.value === 'a' ? 'page' : 'true') : undefined,\n)\n\n/*\n * The icon and the label column, identical in both row shapes. A functional component\n * rather than two copies of the markup, a Vue template having no reusable fragment.\n * `renderSlot` is what a compiled `<slot>` calls, so each fallback behaves exactly as it\n * would in the template.\n */\n// @core\n/*\n * TRAP — the tick is what makes RowBody follow the slots at all. A functional component\n * declaring no props is never updated by its parent's re-render, and `slots` is not\n * reactive, so a sublabel added behind a `v-if` or a label captured by a render function\n * stayed as first drawn. Every re-render of the item (which is what a new slot causes)\n * bumps it, and reading it is what re-renders RowBody: the `useSlotNodes` device.\n */\nconst slotTick = ref(0)\nonBeforeUpdate(() => slotTick.value++)\n\nconst RowBody = () => (\n void slotTick.value,\n [\n renderSlot(slots, 'icon', {}, () =>\n props.icon ? [h(VIcon, { class: 'v-side-nav-icon', ...iconProps(props.icon) })] : [],\n ),\n h('span', { class: 'v-side-nav-content' }, [\n h('span', { class: 'v-side-nav-label' }, [\n renderSlot(slots, 'default', {}, () => [props.label]),\n ]),\n props.sublabel !== undefined || slots.sublabel\n ? h('span', { class: 'v-side-nav-sublabel' }, [\n renderSlot(slots, 'sublabel', {}, () => [props.sublabel]),\n ])\n : null,\n ]),\n ]\n)\n\n/*\n * A branch's end slot sits INSIDE the header, so a click there would fold the branch.\n * Stopping the event from travelling would not help: folding is not a listener anyone\n * registered, it is the click's DEFAULT action, and only cancelling that prevents it.\n *\n * The exception is a click that already landed on something activable. There the click\n * belongs to that control, the branch is not concerned, and cancelling the default\n * would break its own behaviour — a link would stop navigating. The same filter as in\n * `useFieldPanel`, for the same reason.\n */\n// @core\nfunction onEndClick(event: MouseEvent) {\n const target = event.target as Element | null\n if (!target?.closest('button, a, input, select, textarea, [tabindex]')) event.preventDefault()\n}\n\n// A template ref on the item reaches the list item, a layout box; what is focused and\n// named is its row: the branch header, or the leaf's link or button.\nconst rowEl = ref<HTMLElement | null>(null)\nconst actionEl = ref<HTMLElement | null>(null)\nconst control = () => (hasChildren.value ? rowEl.value : actionEl.value)\ndefineExpose({\n /** Moves the focus to the row: the branch header, or the leaf's link or button. */\n focus: (options?: FocusOptions) => control()?.focus(options),\n /** That element, which is also where the consumer's attributes land. */\n get el() {\n return control()\n },\n})\n\n// @a11y\n// A leaf link has no `disabled`: the address, the consumer's click listeners and the\n// generic role of an `<a>` without `href` are handled by the shared inert link.\nconst link = useInertLink({\n href: () => (tag.value === 'a' ? props.href : undefined),\n inert: () => props.disabled,\n attrs: () => forwardedAttrs.value,\n})\n\n// @core\nfunction onActionClick(event: MouseEvent) {\n // A disabled button never receives the click at all; an inert link does, so it is\n // cancelled here.\n if (props.disabled) {\n event.preventDefault()\n return\n }\n emit('select')\n}\n</script>\n\n<template>\n <li class=\"v-side-nav-item\" :class=\"rootClass\" :style=\"rootStyle\">\n <details\n v-if=\"hasChildren\"\n class=\"v-side-nav-branch v-disclosure\"\n :name=\"parent?.name\"\n :open=\"openAttr\"\n :data-swap=\"collapseIcon ? '' : undefined\"\n @toggle=\"onToggle\"\n >\n <summary\n ref=\"rowEl\"\n class=\"v-side-nav-row\"\n :data-current=\"current ? '' : undefined\"\n :data-disabled=\"disabled ? '' : undefined\"\n :aria-current=\"ariaCurrent\"\n :aria-disabled=\"disabled || undefined\"\n :tabindex=\"disabled ? -1 : undefined\"\n v-bind=\"forwardedAttrs\"\n @click=\"onSummaryClick\"\n >\n <RowBody />\n <!-- This slot sits INSIDE the branch header, where ANY click folds the\n branch: without the handler, clicking a badge would close the section\n under it -->\n <span v-if=\"$slots.end\" class=\"v-side-nav-end\" @click=\"onEndClick\"\n ><slot name=\"end\"\n /></span>\n <VIcon class=\"v-side-nav-chevron v-disclosure-chevron\" v-bind=\"iconProps(expandIcon)\" />\n <!-- Both chevrons are always in the DOM; the open state decides which one\n shows, in CSS alone -->\n <VIcon\n v-if=\"collapseIcon\"\n class=\"v-side-nav-chevron v-side-nav-chevron-open v-disclosure-chevron v-disclosure-chevron-open\"\n v-bind=\"iconProps(collapseIcon)\"\n />\n </summary>\n <ul class=\"v-side-nav-children\">\n <slot name=\"children\" />\n </ul>\n </details>\n\n <div\n v-else\n class=\"v-side-nav-row\"\n :data-current=\"current ? '' : undefined\"\n :data-disabled=\"disabled ? '' : undefined\"\n >\n <component\n :is=\"tag\"\n ref=\"actionEl\"\n class=\"v-side-nav-action\"\n :type=\"tag === 'button' ? 'button' : undefined\"\n :disabled=\"tag === 'button' ? disabled : undefined\"\n :aria-disabled=\"link.isInertLink.value ? 'true' : undefined\"\n :aria-current=\"ariaCurrent\"\n v-bind=\"link.attrs.value\"\n :href=\"link.linkHref.value\"\n @click=\"onActionClick\"\n >\n <RowBody />\n </component>\n <span v-if=\"$slots.end\" class=\"v-side-nav-end\"><slot name=\"end\" /></span>\n </div>\n </li>\n</template>\n\n<style>\n@layer vectis.components {\n /*\n * How deep an item sits, counted entirely in CSS: no registry, nothing provided down\n * the tree, no inline style, and no `level` prop for the consumer to keep track of.\n * The markup gives two elements per level — the item, then the list of its children —\n * and each of them reads a name the other DECLARES.\n *\n * TRAP — the obvious one-name form, incrementing a variable by reading itself, is a\n * CYCLE as far as CSS is concerned, even though the value being read is the inherited\n * one. The property then falls to invalid, every read falls back to zero, and the\n * whole tree renders FLAT — with nothing in the console to say why. The two\n * alternating names are what avoid it.\n */\n .v-side-nav-item {\n --side-nav-parent-level: var(--side-nav-level, 0);\n }\n\n .v-side-nav-children {\n --side-nav-level: calc(var(--side-nav-parent-level) + 1);\n }\n\n .v-side-nav-row {\n /*\n * Every dimension comes from the variables the nav sets and this row inherits — it\n * is the only element carrying the shared size class. The icons follow with nothing\n * written for them, their own variables belonging to that same block.\n *\n * The type is composite, as in a menu row: the SIZE comes from the scale, but the\n * line height stays that of body text — a unitless ratio, so it still follows the\n * size — and the weight stays regular. The full `control` type role would set its\n * lines tight against each other, and a row may carry a second line under the label.\n *\n * The label and that second line TRUNCATE rather than wrap: a sidebar has a fixed\n * width, and a row that grew a line would break the rhythm of the list. VMenuItem\n * follows the same recipe.\n *\n * TRAP — the indent is computed HERE and not stored in a variable set higher up. A\n * custom property is substituted on the element that DECLARES it, so a padding\n * computed on the nav would be frozen at level zero for the whole tree.\n */\n\n /*\n * The corner takes the role every clickable box in the DS takes, so a brand that\n * squares its controls or rounds them into pills carries the sidebar along in the\n * one override.\n *\n * TRAP — the cap has to stay derived from --control-height. A browser scales down\n * any radius it cannot fit, so a row exactly one control tall already paints half\n * that height under a pill override; min() applies the same reduction to a row that\n * grew past it. Written bare, a row carrying a second line paints half of ITS OWN\n * height instead, and two rows of the same list come out with different corners. At\n * the shipped 6px this resolves to 6px on both sizes and under compact, so nothing\n * at the default value can see the line go — only the PillRadius play function can.\n *\n * The variable is what keeps the row and the stretched overlay below in step: that\n * overlay is positioned against this element, so the two are the same box, and its\n * ring is drawn on the radius found here.\n */\n --side-nav-row-radius: min(var(--vectis-radius-interactive), calc(var(--control-height) / 2));\n\n position: relative;\n display: flex;\n align-items: center;\n gap: var(--control-gap);\n min-block-size: var(--control-height);\n padding-block: var(--vectis-space-1);\n padding-inline: calc(\n var(--control-padding-inline) + var(--side-nav-level, 0) * var(--side-nav-indent)\n )\n var(--control-padding-inline);\n border-radius: var(--side-nav-row-radius);\n color: var(--vectis-color-text);\n font-size: var(--control-font-size);\n line-height: var(--vectis-text-body-md-leading);\n cursor: pointer;\n }\n\n .v-side-nav-action {\n /* On a leaf the link is a CHILD of the row, and the indent deliberately stays on\n the row itself: what has to run the full width is the hover background, not the\n link inside it. */\n flex: 1;\n min-inline-size: 0;\n display: flex;\n align-items: center;\n gap: var(--control-gap);\n padding: 0;\n border: none;\n background: transparent;\n color: inherit;\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n text-align: start;\n text-decoration: none;\n cursor: inherit;\n }\n\n /*\n * This is what stretches the link over the WHOLE row without having to wrap the end\n * slot inside it. It is an invisible box, positioned, so it is painted above the\n * chevron — which is not positioned — while passing UNDER the end slot, which is\n * positioned too and comes later in the document. That layering is exactly what\n * makes the whole row clickable while leaving a control in the end slot usable.\n */\n .v-side-nav-action::after {\n content: '';\n position: absolute;\n inset: 0;\n border-radius: var(--side-nav-row-radius);\n }\n\n .v-side-nav-content {\n flex: 1;\n min-inline-size: 0;\n display: flex;\n flex-direction: column;\n }\n\n .v-side-nav-label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .v-side-nav-sublabel {\n overflow: hidden;\n font-size: var(--vectis-text-caption-size);\n color: var(--vectis-color-text-muted);\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .v-side-nav-icon {\n flex: none;\n color: var(--vectis-color-text-muted);\n }\n\n /* Positioned on purpose: that is what paints it above the stretched link, and\n therefore what keeps whatever it holds clickable. */\n .v-side-nav-end {\n position: relative;\n flex: none;\n display: flex;\n align-items: center;\n gap: var(--vectis-space-1);\n }\n\n .v-side-nav-row:hover:not([data-disabled]) {\n background: var(--vectis-color-surface-muted);\n }\n\n /*\n * A branch header takes focus itself; a leaf only takes it through its link, and the\n * ring is then drawn on the stretched box so that it frames the whole row rather than\n * just the text.\n *\n * The ring is pulled INWARDS in both cases: the content of a branch is clipped so it\n * can be animated open, and a ring drawn outside the row would be cut off there.\n */\n .v-side-nav-row:focus-visible,\n .v-side-nav-action:focus-visible::after {\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-side-nav-action:focus-visible {\n outline: none;\n }\n\n /* The row of the page currently being viewed. */\n .v-side-nav-row[data-current] {\n background: var(--vectis-color-accent-surface);\n color: var(--vectis-color-accent-text);\n }\n\n .v-side-nav-row[data-current] .v-side-nav-label {\n font-weight: var(--vectis-text-label-weight);\n }\n\n .v-side-nav-row[data-current] .v-side-nav-icon,\n .v-side-nav-row[data-current] .v-side-nav-sublabel,\n .v-side-nav-row[data-current] .v-side-nav-chevron {\n color: inherit;\n }\n\n .v-side-nav-row[data-current]:not([data-disabled]):hover {\n /* The current row is already tinted, so its hover deepens that tint rather than\n replacing it with the neutral highlight — the VMenuItem idiom. */\n background: color-mix(\n in oklab,\n var(--vectis-color-accent-surface),\n var(--vectis-color-accent-text) 8%\n );\n }\n\n /* A CLOSED branch holding the current page keeps a mark of it, so the reader can see\n where they are without opening every section. The lookup is deliberately a\n descendant one: the page may be several levels down. */\n .v-side-nav-branch:not([open]):has(.v-side-nav-children [aria-current])\n > .v-side-nav-row:not([data-current], [data-disabled]) {\n color: var(--vectis-color-accent-text);\n }\n\n /* A disabled row greys out through the colour tokens, never through opacity. */\n .v-side-nav-row[data-disabled] {\n color: var(--vectis-color-text-subtle);\n cursor: not-allowed;\n }\n\n /* The icon and the second line default to a colour DARKER than the one a disabled\n label takes: left alone they would come out stronger than the label itself, so they\n inherit it instead. The chevron gets the same treatment from `styles/disclosure.css`. */\n .v-side-nav-row[data-disabled] .v-side-nav-icon,\n .v-side-nav-row[data-disabled] .v-side-nav-sublabel {\n color: inherit;\n }\n\n /* Forced colours flatten the current row's tint to `Canvas` and its accent text to\n `CanvasText`, leaving a slightly bolder label as the only cue, and the mark on a closed\n branch is a colour alone. The current row takes the system selection pair, repeated to\n (0,4,0) above its own hover, and the closed branch underlines its label, a decoration\n the mode keeps. */\n @media (forced-colors: active) {\n .v-side-nav-row.v-side-nav-row.v-side-nav-row[data-current] {\n forced-color-adjust: none;\n background: Highlight;\n color: HighlightText;\n }\n\n .v-side-nav-row.v-side-nav-row.v-side-nav-row[data-current][data-disabled] {\n background: Canvas;\n color: GrayText;\n }\n\n .v-side-nav-branch:not([open]):has(.v-side-nav-children [aria-current])\n > .v-side-nav-row:not([data-current], [data-disabled])\n .v-side-nav-label {\n text-decoration: underline;\n }\n }\n\n /* The disclosure animation, the chevron's rotation or swap and the WebKit marker come\n from `styles/disclosure.css`, reduced-motion block included. */\n}\n</style>\n"],"mappings":""}
1
+ {"version":3,"file":"VSideNavigationItem.js","names":[],"sources":["../../../src/components/VSideNavigation/VSideNavigationItem.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Branches use native details and leaves use links or buttons. JavaScript synchronizes open\n * state, disables summaries and makes disabled links inert.\n */\n\nimport { computed, inject, provide, ref, useId, useSlots } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport { expand_more as expandMoreIcon } from '../VIcon/icons/expand_more'\nimport type { IconSource } from '../VIcon/types'\nimport { sideNavigationKey } from './context'\n\nimport { useDetailsOpen } from '../../composables/useDetailsOpen'\nimport { useInertLink } from '../../composables/useInertLink'\nimport { useRootAttrs } from '../../composables/useRootAttrs'\n\ninterface SideNavigationItemProps {\n /** What the row says, and where it goes. The default slot replaces it. */\n label?: string\n /** A second line under the label, for a status or a short explanation. */\n sublabel?: string\n /**\n * An icon before the label: an icon name, or an explicit render. The `#icon` slot\n * replaces it.\n */\n icon?: IconSource\n /**\n * Where this row leads, which makes it a link. It is IGNORED on a row that has\n * subitems: such a row opens and closes rather than navigating.\n */\n href?: string\n /**\n * Marks this row as the page currently being viewed. It is highlighted, and\n * announced as the current page (`aria-current`).\n */\n current?: boolean\n /**\n * Makes the row unusable: it greys out through the colour tokens and leaves the\n * keyboard path.\n */\n disabled?: boolean\n /** Renders a branch already open. Bind `v-model:open` to drive it instead. */\n defaultOpen?: boolean\n}\n\n// Without redirecting them, `target`, `rel`, `download` and the aria-* would land on that list\n// item instead of on the link or the branch header.\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<SideNavigationItemProps>(), {\n label: undefined,\n sublabel: undefined,\n icon: undefined,\n href: undefined,\n current: false,\n disabled: false,\n defaultOpen: false,\n})\n\n// \"not bound\" is written as `null` and not `undefined`. A model typed as a plain boolean is\n// declared as such at runtime, and Vue casts an ABSENT boolean prop to `false`, which would\n// silently overwrite `defaultOpen` on every branch.\n/**\n * Whether the branch is open, when the consumer wants to drive or observe it. Left\n * unbound, the browser keeps that state to itself, `defaultOpen` giving only the initial\n * value. `null` means unbound.\n */\nconst open = defineModel<boolean | null>('open', { default: null })\n\nconst emit = defineEmits<{\n // Never declare a `click` emit alongside it. Vue removes a declared event from the forwarded\n // attributes, and a consumer's own `@click` would then stop reaching the link entirely.\n /** A row WITHOUT subitems was activated, by click or by keyboard. */\n select: []\n}>()\n\ndefineSlots<{\n /**\n * The label of the row, replacing the `label` prop. One of the two is REQUIRED: a\n * navigation row must say where it goes.\n */\n default?(): unknown\n /** A second line made of markup, replacing the `sublabel` prop. */\n sublabel?(): unknown\n /** Free content before the label, which takes the place of `icon`. */\n icon?(): unknown\n /**\n * Free content at the end of the row, before the chevron: a counter, a badge. On a\n * BRANCH it must not be focusable, a control inside the header being a control nested\n * inside another.\n */\n end?(): unknown\n /**\n * The subitems, which turn this row into a branch. Nesting is not limited. The slot\n * must be statically present or absent: whether a row is a branch is decided when it\n * is created.\n */\n children?(): unknown\n}>()\n\nconst { rootClass, rootStyle, forwardedAttrs } = useRootAttrs()\n\nconst slots = useSlots()\nconst tag = computed(() => (props.href !== undefined ? 'a' : 'button'))\n\nconst parent = inject(sideNavigationKey, null)\n\n/**\n * Both chevrons are chosen on the navigation as a whole. The fallback is what keeps an\n * item rendering correctly when it is used outside one.\n */\nconst expandIcon = computed(() => parent?.expandIcon ?? expandMoreIcon)\nconst collapseIcon = computed(() => parent?.collapseIcon)\n\n// @ssr\n// Each level owns its exclusive group, including children supplied after the first render.\nconst childrenName = useId()\nprovide(sideNavigationKey, {\n get name() {\n return parent?.exclusive ? childrenName : undefined\n },\n get exclusive() {\n return parent?.exclusive ?? false\n },\n get expandIcon() {\n return expandIcon.value\n },\n get collapseIcon() {\n return collapseIcon.value\n },\n})\n\nconst { openAttr, onToggle, onSummaryClick } = useDetailsOpen(open, {\n defaultOpen: () => props.defaultOpen,\n disabled: () => props.disabled,\n})\n\n/*\n * Stopping the event from travelling would not help: folding is not a listener anyone\n * registered, it is the click's default action, and only cancelling that prevents it. The\n * exception is a click that already landed on something activable.\n */\n// @core\nfunction onEndClick(event: MouseEvent) {\n const target = event.target as Element | null\n if (!target?.closest('button, a, input, select, textarea, [tabindex]')) event.preventDefault()\n}\n\n// A template ref on the item reaches the list item, a layout box; what is focused and\n// named is its row: the branch header, or the leaf's link or button.\nconst rowEl = ref<HTMLElement | null>(null)\nconst actionEl = ref<HTMLElement | null>(null)\nconst control = () => (slots.children ? rowEl.value : actionEl.value)\ndefineExpose({\n /** Moves the focus to the row: the branch header, or the leaf's link or button. */\n focus: (options?: FocusOptions) => control()?.focus(options),\n /** That element, which is also where the consumer's attributes land. */\n get el() {\n return control()\n },\n})\n\n// @a11y\n// A leaf link has no `disabled`: the address, the consumer's click listeners and the\n// generic role of an `<a>` without `href` are handled by the shared inert link.\nconst link = useInertLink({\n href: () => (tag.value === 'a' ? props.href : undefined),\n inert: () => props.disabled,\n attrs: () => forwardedAttrs.value,\n})\n\n// @core\nfunction onActionClick(event: MouseEvent) {\n // A disabled button never receives the click at all; an inert link does, so it is\n // cancelled here.\n if (props.disabled) {\n event.preventDefault()\n return\n }\n emit('select')\n}\n</script>\n\n<template>\n <li class=\"v-side-nav-item\" :class=\"rootClass\" :style=\"rootStyle\">\n <details\n v-if=\"$slots.children\"\n class=\"v-side-nav-branch v-disclosure\"\n :name=\"parent?.name\"\n :open=\"openAttr\"\n :data-swap=\"collapseIcon ? '' : undefined\"\n @toggle=\"onToggle\"\n >\n <summary\n ref=\"rowEl\"\n class=\"v-side-nav-row\"\n :data-current=\"current ? '' : undefined\"\n :data-disabled=\"disabled ? '' : undefined\"\n :aria-current=\"current ? 'true' : undefined\"\n :aria-disabled=\"disabled || undefined\"\n :tabindex=\"disabled ? -1 : undefined\"\n v-bind=\"forwardedAttrs\"\n @click=\"onSummaryClick\"\n >\n <slot name=\"icon\">\n <VIcon v-if=\"icon\" class=\"v-side-nav-icon\" v-bind=\"iconProps(icon)\" />\n </slot>\n <span class=\"v-side-nav-content\">\n <span class=\"v-side-nav-label\"\n ><slot>{{ label }}</slot></span\n >\n <span v-if=\"sublabel !== undefined || $slots.sublabel\" class=\"v-side-nav-sublabel\">\n <slot name=\"sublabel\">{{ sublabel }}</slot>\n </span>\n </span>\n <!-- This slot sits INSIDE the branch header, where ANY click folds the\n branch: without the handler, clicking a badge would close the section\n under it -->\n <span v-if=\"$slots.end\" class=\"v-side-nav-end\" @click=\"onEndClick\"\n ><slot name=\"end\"\n /></span>\n <VIcon class=\"v-side-nav-chevron v-disclosure-chevron\" v-bind=\"iconProps(expandIcon)\" />\n <VIcon\n v-if=\"collapseIcon\"\n class=\"v-side-nav-chevron v-side-nav-chevron-open v-disclosure-chevron v-disclosure-chevron-open\"\n v-bind=\"iconProps(collapseIcon)\"\n />\n </summary>\n <ul class=\"v-side-nav-children\">\n <slot name=\"children\" />\n </ul>\n </details>\n\n <div\n v-else\n class=\"v-side-nav-row\"\n :data-current=\"current ? '' : undefined\"\n :data-disabled=\"disabled ? '' : undefined\"\n >\n <component\n :is=\"tag\"\n ref=\"actionEl\"\n class=\"v-side-nav-action\"\n :type=\"tag === 'button' ? 'button' : undefined\"\n :disabled=\"tag === 'button' ? disabled : undefined\"\n :aria-disabled=\"link.isInertLink.value ? 'true' : undefined\"\n :aria-current=\"current ? (tag === 'a' ? 'page' : 'true') : undefined\"\n v-bind=\"link.attrs.value\"\n :href=\"link.linkHref.value\"\n @click=\"onActionClick\"\n >\n <slot name=\"icon\">\n <VIcon v-if=\"icon\" class=\"v-side-nav-icon\" v-bind=\"iconProps(icon)\" />\n </slot>\n <span class=\"v-side-nav-content\">\n <span class=\"v-side-nav-label\"\n ><slot>{{ label }}</slot></span\n >\n <span v-if=\"sublabel !== undefined || $slots.sublabel\" class=\"v-side-nav-sublabel\">\n <slot name=\"sublabel\">{{ sublabel }}</slot>\n </span>\n </span>\n </component>\n <span v-if=\"$slots.end\" class=\"v-side-nav-end\"><slot name=\"end\" /></span>\n </div>\n </li>\n</template>\n\n<style>\n@layer vectis.components {\n /*\n * The obvious one-name form, incrementing a variable by reading itself, is a CYCLE as far as\n * CSS is concerned, even though the value being read is the inherited one. The property then\n * falls to invalid, every read falls back to zero, and the whole tree renders FLAT; with\n * nothing in the console to say why.\n */\n .v-side-nav-item {\n --side-nav-parent-level: var(--side-nav-level, 0);\n }\n\n .v-side-nav-children {\n --side-nav-level: calc(var(--side-nav-parent-level) + 1);\n }\n\n .v-side-nav-row {\n /*\n * The indent is computed here and not stored in a variable set higher up. A custom property\n * is substituted on the element that DECLARES it, so a padding computed on the nav would be\n * frozen at level zero for the whole tree.\n */\n\n /*\n * The cap has to stay derived from --control-height. A browser scales down any radius it\n * cannot fit, so a row exactly one control tall already paints half that height under a\n * pill override; min() applies the same reduction to a row that grew past it.\n */\n --side-nav-row-radius: min(var(--vectis-radius-interactive), calc(var(--control-height) / 2));\n\n position: relative;\n display: flex;\n align-items: center;\n gap: var(--control-gap);\n min-block-size: var(--control-height);\n padding-block: var(--vectis-space-1);\n padding-inline: calc(\n var(--control-padding-inline) + var(--side-nav-level, 0) * var(--side-nav-indent)\n )\n var(--control-padding-inline);\n border-radius: var(--side-nav-row-radius);\n color: var(--vectis-color-text);\n font-size: var(--control-font-size);\n line-height: var(--vectis-text-body-md-leading);\n cursor: pointer;\n }\n\n .v-side-nav-action {\n /* On a leaf the link is a CHILD of the row, and the indent deliberately stays on\n the row itself: what has to run the full width is the hover background, not the\n link inside it. */\n flex: 1;\n min-inline-size: 0;\n display: flex;\n align-items: center;\n gap: var(--control-gap);\n padding: 0;\n border: none;\n background: transparent;\n color: inherit;\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n text-align: start;\n text-decoration: none;\n cursor: inherit;\n }\n\n /*\n * This is what stretches the link over the whole row without having to wrap the end slot\n * inside it. It is an invisible box, positioned, so it is painted above the chevron; which is\n * not positioned; while passing UNDER the end slot, which is positioned too and comes later\n * in the document.\n */\n .v-side-nav-action::after {\n content: '';\n position: absolute;\n inset: 0;\n border-radius: var(--side-nav-row-radius);\n }\n\n .v-side-nav-content {\n flex: 1;\n min-inline-size: 0;\n display: flex;\n flex-direction: column;\n }\n\n .v-side-nav-label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .v-side-nav-sublabel {\n overflow: hidden;\n font-size: var(--vectis-text-caption-size);\n color: var(--vectis-color-text-muted);\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .v-side-nav-icon {\n flex: none;\n color: var(--vectis-color-text-muted);\n }\n\n /* Positioned on purpose: that is what paints it above the stretched link, and\n therefore what keeps whatever it holds clickable. */\n .v-side-nav-end {\n position: relative;\n flex: none;\n display: flex;\n align-items: center;\n gap: var(--vectis-space-1);\n }\n\n .v-side-nav-row:hover:not([data-disabled]) {\n background: var(--vectis-color-surface-muted);\n }\n\n /*\n * A branch header takes focus itself; a leaf only takes it through its link, and the\n * ring is then drawn on the stretched box so that it frames the whole row rather than\n * just the text.\n *\n * The ring is pulled INWARDS in both cases: the content of a branch is clipped so it\n * can be animated open, and a ring drawn outside the row would be cut off there.\n */\n .v-side-nav-row:focus-visible,\n .v-side-nav-action:focus-visible::after {\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-side-nav-action:focus-visible {\n outline: none;\n }\n\n .v-side-nav-row[data-current] {\n background: var(--vectis-color-accent-surface);\n color: var(--vectis-color-accent-text);\n }\n\n .v-side-nav-row[data-current] .v-side-nav-label {\n font-weight: var(--vectis-text-label-weight);\n }\n\n .v-side-nav-row[data-current] .v-side-nav-icon,\n .v-side-nav-row[data-current] .v-side-nav-sublabel,\n .v-side-nav-row[data-current] .v-side-nav-chevron {\n color: inherit;\n }\n\n .v-side-nav-row[data-current]:not([data-disabled]):hover {\n /*\n * The current row is already tinted, so its hover deepens that tint rather than replacing\n * it with the neutral highlight; the VMenuItem idiom.\n */\n background: color-mix(\n in oklab,\n var(--vectis-color-accent-surface),\n var(--vectis-color-accent-text) 8%\n );\n }\n\n /* A CLOSED branch holding the current page keeps a mark of it, so the reader can see\n where they are without opening every section. The lookup is deliberately a\n descendant one: the page may be several levels down. */\n .v-side-nav-branch:not([open]):has(.v-side-nav-children [aria-current])\n > .v-side-nav-row:not([data-current], [data-disabled]) {\n color: var(--vectis-color-accent-text);\n }\n\n /* A disabled row greys out through the colour tokens, never through opacity. */\n .v-side-nav-row[data-disabled] {\n color: var(--vectis-color-text-subtle);\n cursor: not-allowed;\n }\n\n /* The icon and the second line default to a colour DARKER than the one a disabled\n label takes: left alone they would come out stronger than the label itself, so they\n inherit it instead. The chevron gets the same treatment from `styles/disclosure.css`. */\n .v-side-nav-row[data-disabled] .v-side-nav-icon,\n .v-side-nav-row[data-disabled] .v-side-nav-sublabel {\n color: inherit;\n }\n\n /* Forced colours flatten the current row's tint to `Canvas` and its accent text to\n `CanvasText`, leaving a slightly bolder label as the only cue, and the mark on a closed\n branch is a colour alone. The current row takes the system selection pair, repeated to\n (0,4,0) above its own hover, and the closed branch underlines its label, a decoration\n the mode keeps. */\n @media (forced-colors: active) {\n .v-side-nav-row.v-side-nav-row.v-side-nav-row[data-current] {\n forced-color-adjust: none;\n background: Highlight;\n color: HighlightText;\n }\n\n .v-side-nav-row.v-side-nav-row.v-side-nav-row[data-current][data-disabled] {\n background: Canvas;\n color: GrayText;\n }\n\n .v-side-nav-branch:not([open]):has(.v-side-nav-children [aria-current])\n > .v-side-nav-row:not([data-current], [data-disabled])\n .v-side-nav-label {\n text-decoration: underline;\n }\n }\n\n /* The disclosure animation, the chevron's rotation or swap and the WebKit marker come\n from `styles/disclosure.css`, reduced-motion block included. */\n}\n</style>\n"],"mappings":""}