vectis-ui 0.1.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -6
- package/dist/components/VAccordion/VAccordion.css +1 -1
- package/dist/components/VAccordion/VAccordion.d.ts +9 -16
- package/dist/components/VAccordion/VAccordion.js.map +1 -1
- package/dist/components/VAccordion/VAccordion.vue_vue_type_script_setup_true_lang.js +3 -3
- package/dist/components/VAccordion/VAccordion.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VAccordion/VAccordionItem.css +1 -1
- package/dist/components/VAccordion/VAccordionItem.d.ts +33 -19
- package/dist/components/VAccordion/VAccordionItem.js.map +1 -1
- package/dist/components/VAccordion/VAccordionItem.vue_vue_type_script_setup_true_lang.js +50 -38
- package/dist/components/VAccordion/VAccordionItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VAccordion/context.d.ts +1 -8
- package/dist/components/VAccordion/context.js.map +1 -1
- package/dist/components/VAvatar/VAvatar.css +1 -1
- package/dist/components/VAvatar/VAvatar.d.ts +44 -29
- package/dist/components/VAvatar/VAvatar.js.map +1 -1
- package/dist/components/VAvatar/VAvatar.vue_vue_type_script_setup_true_lang.js +38 -35
- package/dist/components/VAvatar/VAvatar.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VAvatar/VAvatarGroup.d.ts +5 -16
- package/dist/components/VAvatar/VAvatarGroup.js.map +1 -1
- package/dist/components/VAvatar/VAvatarGroup.vue_vue_type_script_setup_true_lang.js +7 -7
- package/dist/components/VAvatar/VAvatarGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VAvatar/context.d.ts +6 -10
- package/dist/components/VAvatar/context.js.map +1 -1
- package/dist/components/VBadge/VBadge.css +1 -1
- package/dist/components/VBadge/VBadge.d.ts +31 -10
- package/dist/components/VBadge/VBadge.js.map +1 -1
- package/dist/components/VBadge/VBadge.vue_vue_type_script_setup_true_lang.js +39 -24
- package/dist/components/VBadge/VBadge.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VBreadcrumb/VBreadcrumb.css +1 -1
- package/dist/components/VBreadcrumb/VBreadcrumb.d.ts +4 -17
- package/dist/components/VBreadcrumb/VBreadcrumb.js.map +1 -1
- package/dist/components/VBreadcrumb/VBreadcrumb.vue_vue_type_script_setup_true_lang.js +23 -25
- package/dist/components/VBreadcrumb/VBreadcrumb.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VButton/VButton.css +1 -1
- package/dist/components/VButton/VButton.d.ts +30 -10
- package/dist/components/VButton/VButton.js.map +1 -1
- package/dist/components/VButton/VButton.vue_vue_type_script_setup_true_lang.js +39 -30
- package/dist/components/VButton/VButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VButton/VButtonGroup.css +1 -1
- package/dist/components/VButton/VButtonGroup.d.ts +76 -13
- package/dist/components/VButton/VButtonGroup.js.map +1 -1
- package/dist/components/VButton/VButtonGroup.vue_vue_type_script_setup_true_lang.js +74 -8
- package/dist/components/VButton/VButtonGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VButton/context.d.ts +30 -0
- package/dist/components/VButton/context.js +6 -0
- package/dist/components/VButton/context.js.map +1 -0
- package/dist/components/VCalendar/VCalendar.css +1 -1
- package/dist/components/VCalendar/VCalendar.d.ts +50 -36
- package/dist/components/VCalendar/VCalendar.js.map +1 -1
- package/dist/components/VCalendar/VCalendar.vue_vue_type_script_setup_true_lang.js +99 -85
- package/dist/components/VCalendar/VCalendar.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCalendar/VCalendarEvent.css +1 -1
- package/dist/components/VCalendar/VCalendarEvent.d.ts +5 -11
- package/dist/components/VCalendar/VCalendarEvent.js.map +1 -1
- package/dist/components/VCalendar/VCalendarEvent.vue_vue_type_script_setup_true_lang.js +7 -1
- package/dist/components/VCalendar/VCalendarEvent.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCalendar/VCalendarMonth.css +1 -1
- package/dist/components/VCalendar/VCalendarMonth.d.ts +10 -13
- package/dist/components/VCalendar/VCalendarMonth.js.map +1 -1
- package/dist/components/VCalendar/VCalendarMonth.vue_vue_type_script_setup_true_lang.js +183 -244
- package/dist/components/VCalendar/VCalendarMonth.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCalendar/VCalendarTimeGrid.css +1 -1
- package/dist/components/VCalendar/VCalendarTimeGrid.d.ts +15 -20
- package/dist/components/VCalendar/VCalendarTimeGrid.js.map +1 -1
- package/dist/components/VCalendar/VCalendarTimeGrid.vue_vue_type_script_setup_true_lang.js +385 -448
- package/dist/components/VCalendar/VCalendarTimeGrid.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCalendar/VCalendarYear.css +1 -1
- package/dist/components/VCalendar/VCalendarYear.js.map +1 -1
- package/dist/components/VCalendar/VCalendarYear.vue_vue_type_script_setup_true_lang.js +53 -49
- package/dist/components/VCalendar/VCalendarYear.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCalendar/gesture.d.ts +158 -0
- package/dist/components/VCalendar/gesture.js +170 -0
- package/dist/components/VCalendar/gesture.js.map +1 -0
- package/dist/components/VCalendar/keyboard.d.ts +9 -3
- package/dist/components/VCalendar/keyboard.js +2 -6
- package/dist/components/VCalendar/keyboard.js.map +1 -1
- package/dist/components/VCalendar/layout.d.ts +67 -54
- package/dist/components/VCalendar/layout.js +77 -69
- package/dist/components/VCalendar/layout.js.map +1 -1
- package/dist/components/VCalendar/timeGrid.d.ts +55 -0
- package/dist/components/VCalendar/timeGrid.js +71 -0
- package/dist/components/VCalendar/timeGrid.js.map +1 -0
- package/dist/components/VCalendar/types.d.ts +41 -16
- package/dist/components/VCarousel/VCarousel.css +1 -1
- package/dist/components/VCarousel/VCarousel.d.ts +21 -41
- package/dist/components/VCarousel/VCarousel.js.map +1 -1
- package/dist/components/VCarousel/VCarousel.vue_vue_type_script_setup_true_lang.js +157 -129
- package/dist/components/VCarousel/VCarousel.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCarousel/VCarouselItem.d.ts +0 -17
- package/dist/components/VCarousel/VCarouselItem.js.map +1 -1
- package/dist/components/VCarousel/VCarouselItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCarousel/context.d.ts +0 -12
- package/dist/components/VCarousel/context.js.map +1 -1
- package/dist/components/VCheckbox/VCheckbox.css +1 -1
- package/dist/components/VCheckbox/VCheckbox.d.ts +31 -16
- package/dist/components/VCheckbox/VCheckbox.js.map +1 -1
- package/dist/components/VCheckbox/VCheckbox.vue_vue_type_script_setup_true_lang.js +62 -29
- package/dist/components/VCheckbox/VCheckbox.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VChip/VChip.css +1 -1
- package/dist/components/VChip/VChip.d.ts +36 -26
- package/dist/components/VChip/VChip.js.map +1 -1
- package/dist/components/VChip/VChip.vue_vue_type_script_setup_true_lang.js +57 -48
- package/dist/components/VChip/VChip.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCombobox/VCombobox.css +1 -1
- package/dist/components/VCombobox/VCombobox.d.ts +127 -31
- package/dist/components/VCombobox/VCombobox.js.map +1 -1
- package/dist/components/VCombobox/VCombobox.vue_vue_type_script_setup_true_lang.js +336 -247
- package/dist/components/VCombobox/VCombobox.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCombobox/VComboboxGroup.css +1 -1
- package/dist/components/VCombobox/VComboboxGroup.d.ts +0 -9
- package/dist/components/VCombobox/VComboboxGroup.js.map +1 -1
- package/dist/components/VCombobox/VComboboxGroup.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/VCombobox/VComboboxGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCombobox/VComboboxOption.css +1 -1
- package/dist/components/VCombobox/VComboboxOption.d.ts +0 -15
- package/dist/components/VCombobox/VComboboxOption.js.map +1 -1
- package/dist/components/VCombobox/VComboboxOption.vue_vue_type_script_setup_true_lang.js +4 -4
- package/dist/components/VCombobox/VComboboxOption.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCombobox/VComboboxSeparator.js.map +1 -1
- package/dist/components/VCombobox/VComboboxSeparator.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCombobox/infiniteScroll.js.map +1 -1
- package/dist/components/VDataTable/VDataTable.css +1 -1
- package/dist/components/VDataTable/VDataTable.d.ts +50 -28
- package/dist/components/VDataTable/VDataTable.js.map +1 -1
- package/dist/components/VDataTable/VDataTable.vue_vue_type_script_setup_true_lang.js +183 -194
- package/dist/components/VDataTable/VDataTable.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VDateInput/VDateInput.css +1 -1
- package/dist/components/VDateInput/VDateInput.d.ts +90 -42
- package/dist/components/VDateInput/VDateInput.js.map +1 -1
- package/dist/components/VDateInput/VDateInput.vue_vue_type_script_setup_true_lang.js +159 -191
- package/dist/components/VDateInput/VDateInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VDatePicker/VDatePicker.css +1 -1
- package/dist/components/VDatePicker/VDatePicker.d.ts +61 -30
- package/dist/components/VDatePicker/VDatePicker.js.map +1 -1
- package/dist/components/VDatePicker/VDatePicker.vue_vue_type_script_setup_true_lang.js +243 -221
- package/dist/components/VDatePicker/VDatePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VDialog/VDialog.css +1 -1
- package/dist/components/VDialog/VDialog.d.ts +45 -33
- package/dist/components/VDialog/VDialog.js.map +1 -1
- package/dist/components/VDialog/VDialog.vue_vue_type_script_setup_true_lang.js +65 -64
- package/dist/components/VDialog/VDialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VDialog/VDialogAlert.d.ts +24 -20
- package/dist/components/VDialog/VDialogAlert.js.map +1 -1
- package/dist/components/VDialog/VDialogAlert.vue_vue_type_script_setup_true_lang.js +36 -25
- package/dist/components/VDialog/VDialogAlert.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VFileInput/VFileInput.css +1 -1
- package/dist/components/VFileInput/VFileInput.d.ts +78 -26
- package/dist/components/VFileInput/VFileInput.js.map +1 -1
- package/dist/components/VFileInput/VFileInput.vue_vue_type_script_setup_true_lang.js +144 -132
- package/dist/components/VFileInput/VFileInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VFilePicker/VFilePicker.css +1 -1
- package/dist/components/VFilePicker/VFilePicker.d.ts +47 -30
- package/dist/components/VFilePicker/VFilePicker.js.map +1 -1
- package/dist/components/VFilePicker/VFilePicker.vue_vue_type_script_setup_true_lang.js +166 -163
- package/dist/components/VFilePicker/VFilePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VFilePicker/fileKind.d.ts +2 -27
- package/dist/components/VFilePicker/fileKind.js +9 -8
- package/dist/components/VFilePicker/fileKind.js.map +1 -1
- package/dist/components/VHotkeys/VHotkeys.css +1 -1
- package/dist/components/VHotkeys/VHotkeys.d.ts +8 -30
- package/dist/components/VHotkeys/VHotkeys.js.map +1 -1
- package/dist/components/VHotkeys/VHotkeys.vue_vue_type_script_setup_true_lang.js +4 -4
- package/dist/components/VHotkeys/VHotkeys.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VHotkeys/platform.js.map +1 -1
- package/dist/components/VIcon/VIcon.css +1 -1
- package/dist/components/VIcon/VIcon.d.ts +15 -6
- package/dist/components/VIcon/VIcon.js.map +1 -1
- package/dist/components/VIcon/VIcon.vue_vue_type_script_setup_true_lang.js +45 -37
- package/dist/components/VIcon/VIcon.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VIcon/iconProps.js.map +1 -1
- package/dist/components/VIcon/icons/index.d.ts +1 -1
- package/dist/components/VIcon/icons/index.js.map +1 -1
- package/dist/components/VIcon/icons/names.d.ts +1 -1
- package/dist/components/VIcon/icons/names.js.map +1 -1
- package/dist/components/VIcon/resolver.d.ts +3 -3
- package/dist/components/VIcon/resolver.js.map +1 -1
- package/dist/components/VIcon/types.d.ts +12 -12
- package/dist/components/VIconButton/VIconButton.css +1 -1
- package/dist/components/VIconButton/VIconButton.d.ts +28 -11
- package/dist/components/VIconButton/VIconButton.js.map +1 -1
- package/dist/components/VIconButton/VIconButton.vue_vue_type_script_setup_true_lang.js +26 -20
- package/dist/components/VIconButton/VIconButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VInput/VInput.css +1 -1
- package/dist/components/VInput/VInput.d.ts +26 -7
- package/dist/components/VInput/VInput.js.map +1 -1
- package/dist/components/VInput/VInput.vue_vue_type_script_setup_true_lang.js +86 -75
- package/dist/components/VInput/VInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VInput/VInputGroup.css +2 -0
- package/dist/components/VInput/VInputGroup.d.ts +47 -0
- package/dist/components/VInput/VInputGroup.js +9 -0
- package/dist/components/VInput/VInputGroup.js.map +1 -0
- package/dist/components/VInput/VInputGroup.vue_vue_type_script_setup_true_lang.js +80 -0
- package/dist/components/VInput/VInputGroup.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VInput/context.d.ts +11 -0
- package/dist/components/VInput/context.js +6 -0
- package/dist/components/VInput/context.js.map +1 -0
- package/dist/components/VInputOTP/VInputOTP.css +1 -1
- package/dist/components/VInputOTP/VInputOTP.d.ts +37 -22
- package/dist/components/VInputOTP/VInputOTP.js.map +1 -1
- package/dist/components/VInputOTP/VInputOTP.vue_vue_type_script_setup_true_lang.js +98 -61
- package/dist/components/VInputOTP/VInputOTP.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VMenu/VMenu.d.ts +23 -30
- package/dist/components/VMenu/VMenu.js.map +1 -1
- package/dist/components/VMenu/VMenu.vue_vue_type_script_setup_true_lang.js +31 -27
- package/dist/components/VMenu/VMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VMenu/VMenuGroup.css +1 -1
- package/dist/components/VMenu/VMenuGroup.d.ts +12 -8
- package/dist/components/VMenu/VMenuGroup.js.map +1 -1
- package/dist/components/VMenu/VMenuGroup.vue_vue_type_script_setup_true_lang.js +11 -11
- package/dist/components/VMenu/VMenuGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VMenu/VMenuItem.css +1 -1
- package/dist/components/VMenu/VMenuItem.d.ts +11 -19
- package/dist/components/VMenu/VMenuItem.js.map +1 -1
- package/dist/components/VMenu/VMenuItem.vue_vue_type_script_setup_true_lang.js +65 -57
- package/dist/components/VMenu/VMenuItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VMenu/VMenuPanel.d.ts +14 -30
- package/dist/components/VMenu/VMenuPanel.js.map +1 -1
- package/dist/components/VMenu/VMenuPanel.vue_vue_type_script_setup_true_lang.js +43 -44
- package/dist/components/VMenu/VMenuPanel.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VMenu/context.d.ts +2 -6
- package/dist/components/VMenu/context.js.map +1 -1
- package/dist/components/VPagination/VPagination.css +1 -1
- package/dist/components/VPagination/VPagination.d.ts +60 -22
- package/dist/components/VPagination/VPagination.js.map +1 -1
- package/dist/components/VPagination/VPagination.vue_vue_type_script_setup_true_lang.js +113 -161
- package/dist/components/VPagination/VPagination.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VPopover/VPopover.css +1 -1
- package/dist/components/VPopover/VPopover.d.ts +26 -7
- package/dist/components/VPopover/VPopover.js.map +1 -1
- package/dist/components/VPopover/VPopover.vue_vue_type_script_setup_true_lang.js +43 -37
- package/dist/components/VPopover/VPopover.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VProgressCircular/VProgressCircular.css +1 -1
- package/dist/components/VProgressCircular/VProgressCircular.d.ts +15 -4
- package/dist/components/VProgressCircular/VProgressCircular.js.map +1 -1
- package/dist/components/VProgressCircular/VProgressCircular.vue_vue_type_script_setup_true_lang.js +32 -30
- package/dist/components/VProgressCircular/VProgressCircular.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VProgressLinear/VProgressLinear.css +1 -1
- package/dist/components/VProgressLinear/VProgressLinear.d.ts +23 -8
- package/dist/components/VProgressLinear/VProgressLinear.js.map +1 -1
- package/dist/components/VProgressLinear/VProgressLinear.vue_vue_type_script_setup_true_lang.js +34 -32
- package/dist/components/VProgressLinear/VProgressLinear.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VRadio/VRadio.css +1 -1
- package/dist/components/VRadio/VRadio.d.ts +36 -18
- package/dist/components/VRadio/VRadio.js.map +1 -1
- package/dist/components/VRadio/VRadio.vue_vue_type_script_setup_true_lang.js +55 -26
- package/dist/components/VRadio/VRadio.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSeparator/VSeparator.d.ts +4 -2
- package/dist/components/VSeparator/VSeparator.js.map +1 -1
- package/dist/components/VSeparator/VSeparator.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSideNavigation/VSideNavigation.css +1 -1
- package/dist/components/VSideNavigation/VSideNavigation.d.ts +5 -19
- package/dist/components/VSideNavigation/VSideNavigation.js.map +1 -1
- package/dist/components/VSideNavigation/VSideNavigation.vue_vue_type_script_setup_true_lang.js +5 -5
- package/dist/components/VSideNavigation/VSideNavigation.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSideNavigation/VSideNavigationGroup.css +1 -1
- package/dist/components/VSideNavigation/VSideNavigationGroup.d.ts +9 -17
- package/dist/components/VSideNavigation/VSideNavigationGroup.js.map +1 -1
- package/dist/components/VSideNavigation/VSideNavigationGroup.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/components/VSideNavigation/VSideNavigationGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSideNavigation/VSideNavigationItem.css +1 -1
- package/dist/components/VSideNavigation/VSideNavigationItem.d.ts +22 -30
- package/dist/components/VSideNavigation/VSideNavigationItem.js.map +1 -1
- package/dist/components/VSideNavigation/VSideNavigationItem.vue_vue_type_script_setup_true_lang.js +77 -87
- package/dist/components/VSideNavigation/VSideNavigationItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSideNavigation/context.d.ts +0 -14
- package/dist/components/VSideNavigation/context.js.map +1 -1
- package/dist/components/VSkeletonLoader/VSkeletonLoader.css +1 -1
- package/dist/components/VSkeletonLoader/VSkeletonLoader.d.ts +9 -9
- package/dist/components/VSkeletonLoader/VSkeletonLoader.js.map +1 -1
- package/dist/components/VSkeletonLoader/VSkeletonLoader.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSlider/VSlider.css +1 -1
- package/dist/components/VSlider/VSlider.d.ts +52 -27
- package/dist/components/VSlider/VSlider.js.map +1 -1
- package/dist/components/VSlider/VSlider.vue_vue_type_script_setup_true_lang.js +202 -118
- package/dist/components/VSlider/VSlider.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSnackbar/VSnackbar.css +1 -1
- package/dist/components/VSnackbar/VSnackbar.d.ts +0 -23
- package/dist/components/VSnackbar/VSnackbar.js.map +1 -1
- package/dist/components/VSnackbar/VSnackbar.vue_vue_type_script_setup_true_lang.js +38 -38
- package/dist/components/VSnackbar/VSnackbar.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSnackbar/state.d.ts +0 -27
- package/dist/components/VSnackbar/state.js.map +1 -1
- package/dist/components/VSpinner/VSpinner.css +1 -1
- package/dist/components/VSpinner/VSpinner.d.ts +6 -6
- package/dist/components/VSpinner/VSpinner.js.map +1 -1
- package/dist/components/VSpinner/VSpinner.vue_vue_type_script_setup_true_lang.js +10 -9
- package/dist/components/VSpinner/VSpinner.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSwitch/VSwitch.css +1 -1
- package/dist/components/VSwitch/VSwitch.d.ts +35 -13
- package/dist/components/VSwitch/VSwitch.js.map +1 -1
- package/dist/components/VSwitch/VSwitch.vue_vue_type_script_setup_true_lang.js +62 -21
- package/dist/components/VSwitch/VSwitch.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTabs/VTab.css +1 -1
- package/dist/components/VTabs/VTab.d.ts +12 -12
- package/dist/components/VTabs/VTab.js.map +1 -1
- package/dist/components/VTabs/VTab.vue_vue_type_script_setup_true_lang.js +36 -24
- package/dist/components/VTabs/VTab.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTabs/VTabPanel.d.ts +2 -10
- package/dist/components/VTabs/VTabPanel.js.map +1 -1
- package/dist/components/VTabs/VTabPanel.vue_vue_type_script_setup_true_lang.js +4 -4
- package/dist/components/VTabs/VTabPanel.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTabs/VTabs.css +1 -1
- package/dist/components/VTabs/VTabs.d.ts +27 -18
- package/dist/components/VTabs/VTabs.js.map +1 -1
- package/dist/components/VTabs/VTabs.vue_vue_type_script_setup_true_lang.js +92 -81
- package/dist/components/VTabs/VTabs.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTabs/context.d.ts +9 -19
- package/dist/components/VTabs/context.js +1 -1
- package/dist/components/VTabs/context.js.map +1 -1
- package/dist/components/VTextarea/VTextarea.css +1 -1
- package/dist/components/VTextarea/VTextarea.d.ts +34 -6
- package/dist/components/VTextarea/VTextarea.js.map +1 -1
- package/dist/components/VTextarea/VTextarea.vue_vue_type_script_setup_true_lang.js +91 -74
- package/dist/components/VTextarea/VTextarea.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTimeInput/VTimeInput.css +1 -1
- package/dist/components/VTimeInput/VTimeInput.d.ts +123 -33
- package/dist/components/VTimeInput/VTimeInput.js.map +1 -1
- package/dist/components/VTimeInput/VTimeInput.vue_vue_type_script_setup_true_lang.js +294 -291
- package/dist/components/VTimeInput/VTimeInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTimeInput/search.d.ts +24 -0
- package/dist/components/VTimeInput/search.js +22 -0
- package/dist/components/VTimeInput/search.js.map +1 -0
- package/dist/components/VTimePicker/VTimePicker.css +1 -1
- package/dist/components/VTimePicker/VTimePicker.d.ts +51 -30
- package/dist/components/VTimePicker/VTimePicker.js.map +1 -1
- package/dist/components/VTimePicker/VTimePicker.vue_vue_type_script_setup_true_lang.js +216 -151
- package/dist/components/VTimePicker/VTimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTimePicker/limits.d.ts +88 -0
- package/dist/components/VTimePicker/limits.js +70 -0
- package/dist/components/VTimePicker/limits.js.map +1 -0
- package/dist/components/VToast/VToast.css +1 -1
- package/dist/components/VToast/VToast.d.ts +0 -10
- package/dist/components/VToast/VToast.js.map +1 -1
- package/dist/components/VToast/VToast.vue_vue_type_script_setup_true_lang.js +10 -10
- package/dist/components/VToast/VToast.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VToast/VToaster.css +1 -1
- package/dist/components/VToast/VToaster.d.ts +0 -17
- package/dist/components/VToast/VToaster.js.map +1 -1
- package/dist/components/VToast/VToaster.vue_vue_type_script_setup_true_lang.js +29 -28
- package/dist/components/VToast/VToaster.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VToast/state.d.ts +10 -19
- package/dist/components/VToast/state.js +1 -1
- package/dist/components/VToast/state.js.map +1 -1
- package/dist/components/VToggle/VToggle.css +1 -1
- package/dist/components/VToggle/VToggle.d.ts +56 -11
- package/dist/components/VToggle/VToggle.js.map +1 -1
- package/dist/components/VToggle/VToggle.vue_vue_type_script_setup_true_lang.js +80 -46
- package/dist/components/VToggle/VToggle.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VToggle/VToggleItem.d.ts +16 -2
- package/dist/components/VToggle/VToggleItem.js +0 -2
- package/dist/components/VToggle/VToggleItem.js.map +1 -1
- package/dist/components/VToggle/VToggleItem.vue_vue_type_script_setup_true_lang.js +23 -15
- package/dist/components/VToggle/VToggleItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VToggle/context.d.ts +4 -24
- package/dist/components/VToggle/context.js.map +1 -1
- package/dist/components/VTooltip/VTooltip.css +1 -1
- package/dist/components/VTooltip/VTooltip.d.ts +9 -33
- package/dist/components/VTooltip/VTooltip.js.map +1 -1
- package/dist/components/VTooltip/VTooltip.vue_vue_type_script_setup_true_lang.js +28 -24
- package/dist/components/VTooltip/VTooltip.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTypography/VTypography.js.map +1 -1
- package/dist/components/VTypography/VTypography.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/composables/useAriaLabel.d.ts +0 -17
- package/dist/composables/useAriaLabel.js.map +1 -1
- package/dist/composables/useClearable.d.ts +42 -0
- package/dist/composables/useClearable.js +19 -0
- package/dist/composables/useClearable.js.map +1 -0
- package/dist/composables/useControlShape.d.ts +22 -0
- package/dist/composables/useControlShape.js +13 -0
- package/dist/composables/useControlShape.js.map +1 -0
- package/dist/composables/useDetailsOpen.d.ts +22 -0
- package/dist/composables/useDetailsOpen.js +21 -0
- package/dist/composables/useDetailsOpen.js.map +1 -0
- package/dist/composables/useFieldIds.d.ts +0 -15
- package/dist/composables/useFieldIds.js +8 -7
- package/dist/composables/useFieldIds.js.map +1 -1
- package/dist/composables/useFieldPanel.d.ts +21 -18
- package/dist/composables/useFieldPanel.js +43 -23
- package/dist/composables/useFieldPanel.js.map +1 -1
- package/dist/composables/useFileDrop.d.ts +0 -22
- package/dist/composables/useFileDrop.js.map +1 -1
- package/dist/composables/useFileField.d.ts +45 -17
- package/dist/composables/useFileField.js +40 -20
- package/dist/composables/useFileField.js.map +1 -1
- package/dist/composables/useFocusoutDismiss.d.ts +0 -15
- package/dist/composables/useFocusoutDismiss.js.map +1 -1
- package/dist/composables/useIconClickHandlers.d.ts +29 -14
- package/dist/composables/useIconClickHandlers.js +15 -5
- package/dist/composables/useIconClickHandlers.js.map +1 -1
- package/dist/composables/useInertLink.d.ts +20 -0
- package/dist/composables/useInertLink.js +23 -0
- package/dist/composables/useInertLink.js.map +1 -0
- package/dist/composables/useMaskedField.d.ts +33 -10
- package/dist/composables/useMaskedField.js +45 -1
- package/dist/composables/useMaskedField.js.map +1 -1
- package/dist/composables/usePopover.d.ts +15 -1
- package/dist/composables/usePopover.js +23 -8
- package/dist/composables/usePopover.js.map +1 -1
- package/dist/composables/useProgressValue.d.ts +5 -8
- package/dist/composables/useProgressValue.js +6 -3
- package/dist/composables/useProgressValue.js.map +1 -1
- package/dist/composables/useRootAttrs.d.ts +12 -19
- package/dist/composables/useRootAttrs.js.map +1 -1
- package/dist/composables/useTimer.d.ts +8 -10
- package/dist/composables/useTimer.js.map +1 -1
- package/dist/i18n/en.d.ts +2 -10
- package/dist/i18n/en.js +18 -19
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/fr.d.ts +2 -18
- package/dist/i18n/fr.js +18 -19
- package/dist/i18n/fr.js.map +1 -1
- package/dist/i18n/state.d.ts +44 -47
- package/dist/i18n/state.js +20 -17
- package/dist/i18n/state.js.map +1 -1
- package/dist/i18n/types.d.ts +53 -44
- package/dist/icons.d.ts +3 -3
- package/dist/index.d.ts +43 -17
- package/dist/index.js +45 -44
- package/dist/styles.css +1 -1
- package/dist/tokens/css.js.map +1 -1
- package/dist/tokens/index.d.ts +5 -1
- package/dist/tokens/primitives.js.map +1 -1
- package/dist/tokens/semantic.d.ts +5 -1
- package/dist/tokens/semantic.js +6 -2
- package/dist/tokens/semantic.js.map +1 -1
- package/dist/tokens/themes/dark.js.map +1 -1
- package/dist/tokens/types.d.ts +7 -15
- package/dist/tokens/types.js.map +1 -1
- package/dist/tokens.json +25 -5
- package/dist/types.d.ts +24 -0
- package/dist/utils/array.d.ts +3 -6
- package/dist/utils/array.js.map +1 -1
- package/dist/utils/arrowNav.d.ts +17 -17
- package/dist/utils/arrowNav.js +5 -3
- package/dist/utils/arrowNav.js.map +1 -1
- package/dist/utils/chip.d.ts +11 -15
- package/dist/utils/chip.js.map +1 -1
- package/dist/utils/css.d.ts +22 -11
- package/dist/utils/css.js +5 -2
- package/dist/utils/css.js.map +1 -1
- package/dist/utils/date.d.ts +42 -19
- package/dist/utils/date.js +97 -98
- package/dist/utils/date.js.map +1 -1
- package/dist/utils/direction.d.ts +6 -12
- package/dist/utils/direction.js.map +1 -1
- package/dist/utils/env.d.ts +5 -6
- package/dist/utils/file.d.ts +46 -58
- package/dist/utils/file.js +43 -36
- package/dist/utils/file.js.map +1 -1
- package/dist/utils/focus.d.ts +8 -17
- package/dist/utils/focus.js.map +1 -1
- package/dist/utils/hostWarns.d.ts +12 -0
- package/dist/utils/hostWarns.js +6 -0
- package/dist/utils/hostWarns.js.map +1 -0
- package/dist/utils/ids.d.ts +10 -0
- package/dist/utils/ids.js +8 -0
- package/dist/utils/ids.js.map +1 -0
- package/dist/utils/matcher.d.ts +5 -9
- package/dist/utils/matcher.js.map +1 -1
- package/dist/utils/memo.d.ts +12 -0
- package/dist/utils/memo.js +9 -0
- package/dist/utils/memo.js.map +1 -0
- package/dist/utils/number.d.ts +3 -4
- package/dist/utils/number.js.map +1 -1
- package/dist/utils/text.d.ts +20 -9
- package/dist/utils/text.js +17 -3
- package/dist/utils/text.js.map +1 -1
- package/dist/utils/time.d.ts +53 -61
- package/dist/utils/time.js +49 -45
- package/dist/utils/time.js.map +1 -1
- package/dist/utils/vnode.d.ts +8 -15
- package/dist/utils/vnode.js.map +1 -1
- package/package.json +6 -6
- package/dist/components/VToggle/VToggleItem.css +0 -2
|
@@ -1,24 +1,4 @@
|
|
|
1
|
-
import { MenuPlacement } from './context.js';
|
|
2
|
-
/**
|
|
3
|
-
* A menu of actions, opened by a button and closed as soon as one is chosen. It
|
|
4
|
-
* follows the ARIA menu pattern, which is what tells a screen reader that these are
|
|
5
|
-
* commands rather than links or options in a list.
|
|
6
|
-
*
|
|
7
|
-
* It rests on the browser's own popover support: the panel closes on a click outside
|
|
8
|
-
* or on Escape without a line of code, and it positions itself in CSS against the
|
|
9
|
-
* button that opened it — the browser knows which one, since that button names the
|
|
10
|
-
* panel it opens.
|
|
11
|
-
*
|
|
12
|
-
* The JavaScript here is limited to what the platform does not do: keeping
|
|
13
|
-
* `v-model:open` and the browser's own state in step, moving the focus into the panel
|
|
14
|
-
* when it opens, and giving it back to the trigger when it closes. The keyboard inside
|
|
15
|
-
* the panel — the arrows moving from one command to the next — lives in VMenuPanel.
|
|
16
|
-
*
|
|
17
|
-
* How far the focus goes in depends on how the menu was opened. Opened from the
|
|
18
|
-
* keyboard it settles on the first command, ready to be chosen; opened with a mouse or
|
|
19
|
-
* a finger it stops at the panel, so that nothing is picked out for someone who has
|
|
20
|
-
* not asked for a choice yet — the arrows still enter the list from there.
|
|
21
|
-
*/
|
|
1
|
+
import { MenuPlacement, MenuSize } from './context.js';
|
|
22
2
|
interface MenuProps {
|
|
23
3
|
/**
|
|
24
4
|
* Where the panel opens relative to its trigger. The browser moves it to another
|
|
@@ -29,14 +9,15 @@ interface MenuProps {
|
|
|
29
9
|
* How tall the rows are: 32, 40 or 48 pixels. Submenus inherit it, so it is set
|
|
30
10
|
* once on the menu as a whole.
|
|
31
11
|
*/
|
|
32
|
-
size?:
|
|
12
|
+
size?: MenuSize;
|
|
33
13
|
/** Takes 4px off the height of every row, submenus included. */
|
|
34
14
|
compact?: boolean;
|
|
35
15
|
/**
|
|
36
|
-
* A width for the panel,
|
|
37
|
-
* `max-content`. It applies to the menu itself; submenus keep the
|
|
16
|
+
* A width for the panel: a number is read as pixels, a string as any CSS length or
|
|
17
|
+
* keyword — `16rem`, `max-content`. It applies to the menu itself; submenus keep the
|
|
18
|
+
* default width.
|
|
38
19
|
*/
|
|
39
|
-
width?: string;
|
|
20
|
+
width?: number | string;
|
|
40
21
|
/**
|
|
41
22
|
* Stops the panel from being narrower than the button that opened it, while leaving
|
|
42
23
|
* it free to grow wider for its content. Submenus are unaffected.
|
|
@@ -49,7 +30,7 @@ type __VLS_Props = MenuProps;
|
|
|
49
30
|
* attributes telling assistive technology that a menu is attached to this button and
|
|
50
31
|
* whether it is currently open.
|
|
51
32
|
*/
|
|
52
|
-
type MenuTriggerProps = {
|
|
33
|
+
export type MenuTriggerProps = {
|
|
53
34
|
popovertarget: string;
|
|
54
35
|
'aria-haspopup': 'menu';
|
|
55
36
|
'aria-expanded': boolean;
|
|
@@ -66,20 +47,32 @@ type __VLS_Slots = {
|
|
|
66
47
|
/** The contents of the menu: VMenuItem, VMenuGroup and VMenuSeparator. */
|
|
67
48
|
default(): unknown;
|
|
68
49
|
};
|
|
50
|
+
declare function openAtTrigger(): void;
|
|
69
51
|
type __VLS_ModelProps = {
|
|
52
|
+
/**
|
|
53
|
+
* Whether the menu is showing. It starts closed and is fed BY the panel, so the browser's
|
|
54
|
+
* own dismissal — a click outside, Escape, choosing a command — writes back to it.
|
|
55
|
+
*/
|
|
70
56
|
'open'?: boolean;
|
|
71
57
|
};
|
|
72
58
|
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
73
|
-
declare const __VLS_base: import('vue').DefineComponent<__VLS_PublicProps, {
|
|
59
|
+
declare const __VLS_base: import('vue').DefineComponent<__VLS_PublicProps, {
|
|
60
|
+
/** Opens the menu at once, without waiting for the model to come round. */
|
|
61
|
+
show: typeof openAtTrigger;
|
|
62
|
+
/** Closes it at once, submenus included. */
|
|
63
|
+
close: () => void | undefined;
|
|
64
|
+
/** The panel element, for what neither of the two above covers. */
|
|
65
|
+
el: import('vue').ComputedRef<HTMLElement | null>;
|
|
66
|
+
}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
74
67
|
"update:open": (value: boolean) => any;
|
|
75
68
|
}, string, import('vue').PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
76
69
|
"onUpdate:open"?: ((value: boolean) => any) | undefined;
|
|
77
70
|
}>, {
|
|
78
|
-
size:
|
|
71
|
+
size: MenuSize;
|
|
79
72
|
placement: MenuPlacement;
|
|
80
|
-
compact: boolean;
|
|
81
|
-
width: string;
|
|
82
73
|
matchTrigger: boolean;
|
|
74
|
+
compact: boolean;
|
|
75
|
+
width: number | string;
|
|
83
76
|
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
84
77
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
85
78
|
declare const _default: typeof __VLS_export;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VMenu.js","names":[],"sources":["../../../src/components/VMenu/VMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\
|
|
1
|
+
{"version":3,"file":"VMenu.js","names":[],"sources":["../../../src/components/VMenu/VMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @a11y @core\n/**\n * A menu of actions, opened by a button and closed as soon as one is chosen. It follows the\n * ARIA menu pattern, which is what tells a screen reader these are commands rather than\n * links or options.\n *\n * It rests on `popover=\"auto\"`: the panel light-dismisses without a line of code and\n * positions itself in CSS against its `popovertarget` invoker, which is its implicit anchor.\n *\n * The JS covers only what the platform does not — keeping `v-model:open` in step, moving\n * focus into the panel and handing it back to the trigger. The keyboard inside the panel\n * lives in VMenuPanel.\n *\n * HOW FAR the focus goes in depends on how the menu was opened: from the keyboard it settles\n * on the first command, ready to be chosen; by pointer it stops at the panel, so nothing is\n * singled out for someone who has not asked for a choice yet. The arrows still enter the\n * list from there.\n */\n\nimport { computed, provide, ref, useId } from 'vue'\n\nimport VMenuPanel from './VMenuPanel.vue'\nimport { menuInvoker, menuKey } from './context'\nimport type { MenuPlacement, MenuSize } from './context'\nimport { usePopoverModel } from '../../composables/usePopover'\nimport { isKeyboardFocus } from '../../utils/focus'\n\ninterface MenuProps {\n /**\n * Where the panel opens relative to its trigger. The browser moves it to another\n * side by itself when there is not enough room.\n */\n placement?: MenuPlacement\n /**\n * How tall the rows are: 32, 40 or 48 pixels. Submenus inherit it, so it is set\n * once on the menu as a whole.\n */\n size?: MenuSize\n /** Takes 4px off the height of every row, submenus included. */\n compact?: boolean\n /**\n * A width for the panel: a number is read as pixels, a string as any CSS length or\n * keyword — `16rem`, `max-content`. It applies to the menu itself; submenus keep the\n * default width.\n */\n width?: number | string\n /**\n * Stops the panel from being narrower than the button that opened it, while leaving\n * it free to grow wider for its content. Submenus are unaffected.\n */\n matchTrigger?: boolean\n}\n\n// Deliberately not assigned to a variable: the template reads the props directly.\nwithDefaults(defineProps<MenuProps>(), {\n placement: 'bottom-start',\n size: 'sm',\n compact: false,\n width: undefined,\n matchTrigger: false,\n})\n\n/**\n * Whether the menu is showing. It starts closed and is fed BY the panel, so the browser's\n * own dismissal — a click outside, Escape, choosing a command — writes back to it.\n */\nconst open = defineModel<boolean>('open', { default: false })\n\n/**\n * What the trigger has to carry: the link to the panel it opens, and the two\n * attributes telling assistive technology that a menu is attached to this button and\n * whether it is currently open.\n */\nexport type MenuTriggerProps = {\n popovertarget: string\n 'aria-haspopup': 'menu'\n 'aria-expanded': boolean\n 'aria-controls': string\n}\n\ndefineSlots<{\n /**\n * The button that opens the menu. Bind the `triggerProps` it receives onto it —\n * that is what wires the two together.\n */\n trigger(props: { triggerProps: MenuTriggerProps }): unknown\n /** The contents of the menu: VMenuItem, VMenuGroup and VMenuSeparator. */\n default(): unknown\n}>()\n\nconst panelRef = ref<InstanceType<typeof VMenuPanel> | null>(null)\nconst menuId = useId()\n\nconst triggerProps = computed<MenuTriggerProps>(() => ({\n popovertarget: menuId,\n 'aria-haspopup': 'menu',\n 'aria-expanded': open.value,\n 'aria-controls': menuId,\n}))\n\n// Closing this panel closes every submenu with it: they are rendered inside it, and\n// the browser closes a stack of popovers from the outside in.\nprovide(menuKey, { closeAll: () => panelRef.value?.close() })\n\n// @a11y — the focus half of the bridge: into the panel when it opens, back to the\n// trigger when it closes. Keeping the state in step alone would leave a keyboard user\n// stranded at the top of the page every time a menu opened or closed.\n//\n// WHERE it lands in the panel is the whole question, and the browser is the one that\n// answers it. In a menu the focus IS the highlight (see the rule in VMenuItem), so\n// taking the first item singles out a command — which is what someone arriving on the\n// arrows wants, and what someone who has just clicked never asked for. `:focus-visible`\n// is exactly that distinction, read off whatever holds the focus at this instant: the\n// trigger, since opening a popover through `popovertarget` does not move the focus.\n//\n// The pointer branch focuses the PANEL rather than nothing at all, and that is\n// structural: every key the menu answers to is listened for on the panel element, so\n// focus left outside it — on a trigger that is a DOM sibling — would silence the arrows,\n// Home/End and the Tab that closes the menu. Both ways of being wrong are mild and\n// symmetric: a misread pointer costs one extra keystroke, a misread keyboard gives back\n// the older behaviour.\nfunction onToggle(value: boolean) {\n open.value = value\n if (value) {\n if (isKeyboardFocus(document.activeElement)) panelRef.value?.focusFirst()\n else panelRef.value?.focusPanel()\n } else {\n // The browser's own dismissal — a click outside, Escape — leaves the focus\n // nowhere, on the page body. Only then is it handed back to the trigger: if the\n // focus has already moved somewhere else deliberately, it must be left alone.\n const active = document.activeElement\n if (!active || active === document.body || panelRef.value?.el?.contains(active)) {\n menuInvoker(menuId)?.focus()\n }\n }\n}\n\n/*\n * TRAP — every opening that does not come from a click on the trigger has to NAME that\n * trigger. A popover opened through `popovertarget` takes its invoker as its implicit\n * anchor; opened from code with no `source`, it has no anchor at all and the browser\n * paints it at the corner of the viewport. Nothing errors, and the panel is otherwise\n * perfectly functional there.\n *\n * The invoker is searched for rather than held: it is rendered by the consumer, in a\n * slot this component cannot reach into.\n */\nfunction openAtTrigger() {\n panelRef.value?.show(menuInvoker(menuId) ?? undefined)\n}\n\n// The open state is the panel's, read back from it rather than copied here: the panel has\n// already recorded the browser's answer by the time it reports the toggle.\nusePopoverModel(\n open,\n () => panelRef.value?.shown ?? false,\n openAtTrigger,\n () => panelRef.value?.close(),\n)\n\n/*\n * The same trio VDialog, VDialogAlert and VPopover answer. It is a relay onto the panel,\n * which has held it all along: opening a menu from code was otherwise only possible through\n * the model, which inserts a tick where a focus move cannot afford one.\n */\ndefineExpose({\n /** Opens the menu at once, without waiting for the model to come round. */\n show: openAtTrigger,\n /** Closes it at once, submenus included. */\n close: () => panelRef.value?.close(),\n /** The panel element, for what neither of the two above covers. */\n el: computed(() => panelRef.value?.el ?? null),\n})\n</script>\n\n<template>\n <slot name=\"trigger\" :trigger-props=\"triggerProps\" />\n <VMenuPanel\n :id=\"menuId\"\n ref=\"panelRef\"\n :placement=\"placement\"\n :size=\"size\"\n :compact=\"compact\"\n :width=\"width\"\n :match-trigger=\"matchTrigger\"\n @toggle=\"onToggle\"\n >\n <slot />\n </VMenuPanel>\n</template>\n"],"mappings":""}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
1
|
+
import { usePopoverModel as e } from "../../composables/usePopover.js";
|
|
2
|
+
import { isKeyboardFocus as t } from "../../utils/focus.js";
|
|
3
|
+
import { menuInvoker as n, menuKey as r } from "./context.js";
|
|
4
|
+
import i from "./VMenuPanel.js";
|
|
5
|
+
import { Fragment as a, computed as o, createElementBlock as s, createVNode as c, defineComponent as l, mergeModels as u, openBlock as d, provide as f, ref as p, renderSlot as m, unref as h, useId as g, useModel as _, withCtx as v } from "vue";
|
|
5
6
|
//#region src/components/VMenu/VMenu.vue?vue&type=script&setup=true&lang.ts
|
|
6
|
-
var
|
|
7
|
+
var y = /*@__PURE__*/ l({
|
|
7
8
|
__name: "VMenu",
|
|
8
|
-
props: /*@__PURE__*/
|
|
9
|
+
props: /*@__PURE__*/ u({
|
|
9
10
|
placement: { default: "bottom-start" },
|
|
10
11
|
size: { default: "sm" },
|
|
11
12
|
compact: {
|
|
@@ -25,37 +26,40 @@ var b = /*@__PURE__*/ c({
|
|
|
25
26
|
openModifiers: {}
|
|
26
27
|
}),
|
|
27
28
|
emits: ["update:open"],
|
|
28
|
-
setup(
|
|
29
|
-
let
|
|
29
|
+
setup(l, { expose: u }) {
|
|
30
|
+
let y = _(l, "open"), b = p(null), x = g(), S = o(() => ({
|
|
30
31
|
popovertarget: x,
|
|
31
32
|
"aria-haspopup": "menu",
|
|
32
|
-
"aria-expanded":
|
|
33
|
+
"aria-expanded": y.value,
|
|
33
34
|
"aria-controls": x
|
|
34
35
|
}));
|
|
35
|
-
f(
|
|
36
|
-
function
|
|
37
|
-
if (
|
|
36
|
+
f(r, { closeAll: () => b.value?.close() });
|
|
37
|
+
function C(e) {
|
|
38
|
+
if (y.value = e, e) t(document.activeElement) ? b.value?.focusFirst() : b.value?.focusPanel();
|
|
38
39
|
else {
|
|
39
|
-
let
|
|
40
|
-
(!
|
|
40
|
+
let e = document.activeElement;
|
|
41
|
+
(!e || e === document.body || b.value?.el?.contains(e)) && n(x)?.focus();
|
|
41
42
|
}
|
|
42
43
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
function w() {
|
|
45
|
+
b.value?.show(n(x) ?? void 0);
|
|
46
|
+
}
|
|
47
|
+
return e(y, () => b.value?.shown ?? !1, w, () => b.value?.close()), u({
|
|
48
|
+
show: w,
|
|
49
|
+
close: () => b.value?.close(),
|
|
50
|
+
el: o(() => b.value?.el ?? null)
|
|
51
|
+
}), (e, t) => (d(), s(a, null, [m(e.$slots, "trigger", { triggerProps: S.value }), c(i, {
|
|
48
52
|
id: h(x),
|
|
49
53
|
ref_key: "panelRef",
|
|
50
54
|
ref: b,
|
|
51
|
-
placement:
|
|
52
|
-
size:
|
|
53
|
-
compact:
|
|
54
|
-
width:
|
|
55
|
-
"match-trigger":
|
|
56
|
-
onToggle:
|
|
55
|
+
placement: l.placement,
|
|
56
|
+
size: l.size,
|
|
57
|
+
compact: l.compact,
|
|
58
|
+
width: l.width,
|
|
59
|
+
"match-trigger": l.matchTrigger,
|
|
60
|
+
onToggle: C
|
|
57
61
|
}, {
|
|
58
|
-
default:
|
|
62
|
+
default: v(() => [m(e.$slots, "default")]),
|
|
59
63
|
_: 3
|
|
60
64
|
}, 8, [
|
|
61
65
|
"id",
|
|
@@ -68,6 +72,6 @@ var b = /*@__PURE__*/ c({
|
|
|
68
72
|
}
|
|
69
73
|
});
|
|
70
74
|
//#endregion
|
|
71
|
-
export {
|
|
75
|
+
export { y as default };
|
|
72
76
|
|
|
73
77
|
//# sourceMappingURL=VMenu.vue_vue_type_script_setup_true_lang.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VMenu.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/VMenu/VMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\
|
|
1
|
+
{"version":3,"file":"VMenu.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/VMenu/VMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @a11y @core\n/**\n * A menu of actions, opened by a button and closed as soon as one is chosen. It follows the\n * ARIA menu pattern, which is what tells a screen reader these are commands rather than\n * links or options.\n *\n * It rests on `popover=\"auto\"`: the panel light-dismisses without a line of code and\n * positions itself in CSS against its `popovertarget` invoker, which is its implicit anchor.\n *\n * The JS covers only what the platform does not — keeping `v-model:open` in step, moving\n * focus into the panel and handing it back to the trigger. The keyboard inside the panel\n * lives in VMenuPanel.\n *\n * HOW FAR the focus goes in depends on how the menu was opened: from the keyboard it settles\n * on the first command, ready to be chosen; by pointer it stops at the panel, so nothing is\n * singled out for someone who has not asked for a choice yet. The arrows still enter the\n * list from there.\n */\n\nimport { computed, provide, ref, useId } from 'vue'\n\nimport VMenuPanel from './VMenuPanel.vue'\nimport { menuInvoker, menuKey } from './context'\nimport type { MenuPlacement, MenuSize } from './context'\nimport { usePopoverModel } from '../../composables/usePopover'\nimport { isKeyboardFocus } from '../../utils/focus'\n\ninterface MenuProps {\n /**\n * Where the panel opens relative to its trigger. The browser moves it to another\n * side by itself when there is not enough room.\n */\n placement?: MenuPlacement\n /**\n * How tall the rows are: 32, 40 or 48 pixels. Submenus inherit it, so it is set\n * once on the menu as a whole.\n */\n size?: MenuSize\n /** Takes 4px off the height of every row, submenus included. */\n compact?: boolean\n /**\n * A width for the panel: a number is read as pixels, a string as any CSS length or\n * keyword — `16rem`, `max-content`. It applies to the menu itself; submenus keep the\n * default width.\n */\n width?: number | string\n /**\n * Stops the panel from being narrower than the button that opened it, while leaving\n * it free to grow wider for its content. Submenus are unaffected.\n */\n matchTrigger?: boolean\n}\n\n// Deliberately not assigned to a variable: the template reads the props directly.\nwithDefaults(defineProps<MenuProps>(), {\n placement: 'bottom-start',\n size: 'sm',\n compact: false,\n width: undefined,\n matchTrigger: false,\n})\n\n/**\n * Whether the menu is showing. It starts closed and is fed BY the panel, so the browser's\n * own dismissal — a click outside, Escape, choosing a command — writes back to it.\n */\nconst open = defineModel<boolean>('open', { default: false })\n\n/**\n * What the trigger has to carry: the link to the panel it opens, and the two\n * attributes telling assistive technology that a menu is attached to this button and\n * whether it is currently open.\n */\nexport type MenuTriggerProps = {\n popovertarget: string\n 'aria-haspopup': 'menu'\n 'aria-expanded': boolean\n 'aria-controls': string\n}\n\ndefineSlots<{\n /**\n * The button that opens the menu. Bind the `triggerProps` it receives onto it —\n * that is what wires the two together.\n */\n trigger(props: { triggerProps: MenuTriggerProps }): unknown\n /** The contents of the menu: VMenuItem, VMenuGroup and VMenuSeparator. */\n default(): unknown\n}>()\n\nconst panelRef = ref<InstanceType<typeof VMenuPanel> | null>(null)\nconst menuId = useId()\n\nconst triggerProps = computed<MenuTriggerProps>(() => ({\n popovertarget: menuId,\n 'aria-haspopup': 'menu',\n 'aria-expanded': open.value,\n 'aria-controls': menuId,\n}))\n\n// Closing this panel closes every submenu with it: they are rendered inside it, and\n// the browser closes a stack of popovers from the outside in.\nprovide(menuKey, { closeAll: () => panelRef.value?.close() })\n\n// @a11y — the focus half of the bridge: into the panel when it opens, back to the\n// trigger when it closes. Keeping the state in step alone would leave a keyboard user\n// stranded at the top of the page every time a menu opened or closed.\n//\n// WHERE it lands in the panel is the whole question, and the browser is the one that\n// answers it. In a menu the focus IS the highlight (see the rule in VMenuItem), so\n// taking the first item singles out a command — which is what someone arriving on the\n// arrows wants, and what someone who has just clicked never asked for. `:focus-visible`\n// is exactly that distinction, read off whatever holds the focus at this instant: the\n// trigger, since opening a popover through `popovertarget` does not move the focus.\n//\n// The pointer branch focuses the PANEL rather than nothing at all, and that is\n// structural: every key the menu answers to is listened for on the panel element, so\n// focus left outside it — on a trigger that is a DOM sibling — would silence the arrows,\n// Home/End and the Tab that closes the menu. Both ways of being wrong are mild and\n// symmetric: a misread pointer costs one extra keystroke, a misread keyboard gives back\n// the older behaviour.\nfunction onToggle(value: boolean) {\n open.value = value\n if (value) {\n if (isKeyboardFocus(document.activeElement)) panelRef.value?.focusFirst()\n else panelRef.value?.focusPanel()\n } else {\n // The browser's own dismissal — a click outside, Escape — leaves the focus\n // nowhere, on the page body. Only then is it handed back to the trigger: if the\n // focus has already moved somewhere else deliberately, it must be left alone.\n const active = document.activeElement\n if (!active || active === document.body || panelRef.value?.el?.contains(active)) {\n menuInvoker(menuId)?.focus()\n }\n }\n}\n\n/*\n * TRAP — every opening that does not come from a click on the trigger has to NAME that\n * trigger. A popover opened through `popovertarget` takes its invoker as its implicit\n * anchor; opened from code with no `source`, it has no anchor at all and the browser\n * paints it at the corner of the viewport. Nothing errors, and the panel is otherwise\n * perfectly functional there.\n *\n * The invoker is searched for rather than held: it is rendered by the consumer, in a\n * slot this component cannot reach into.\n */\nfunction openAtTrigger() {\n panelRef.value?.show(menuInvoker(menuId) ?? undefined)\n}\n\n// The open state is the panel's, read back from it rather than copied here: the panel has\n// already recorded the browser's answer by the time it reports the toggle.\nusePopoverModel(\n open,\n () => panelRef.value?.shown ?? false,\n openAtTrigger,\n () => panelRef.value?.close(),\n)\n\n/*\n * The same trio VDialog, VDialogAlert and VPopover answer. It is a relay onto the panel,\n * which has held it all along: opening a menu from code was otherwise only possible through\n * the model, which inserts a tick where a focus move cannot afford one.\n */\ndefineExpose({\n /** Opens the menu at once, without waiting for the model to come round. */\n show: openAtTrigger,\n /** Closes it at once, submenus included. */\n close: () => panelRef.value?.close(),\n /** The panel element, for what neither of the two above covers. */\n el: computed(() => panelRef.value?.el ?? null),\n})\n</script>\n\n<template>\n <slot name=\"trigger\" :trigger-props=\"triggerProps\" />\n <VMenuPanel\n :id=\"menuId\"\n ref=\"panelRef\"\n :placement=\"placement\"\n :size=\"size\"\n :compact=\"compact\"\n :width=\"width\"\n :match-trigger=\"matchTrigger\"\n @toggle=\"onToggle\"\n >\n <slot />\n </VMenuPanel>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmEA,IAAM,IAAO,EAAoB,GAAC,MAA0B,GAwBtD,IAAW,EAA4C,IAAI,GAC3D,IAAS,EAAM,GAEf,IAAe,SAAkC;GACrD,eAAe;GACf,iBAAiB;GACjB,iBAAiB,EAAK;GACtB,iBAAiB;EACnB,EAAE;EAIF,EAAQ,GAAS,EAAE,gBAAgB,EAAS,OAAO,MAAM,EAAE,CAAC;EAmB5D,SAAS,EAAS,GAAgB;GAEhC,IADA,EAAK,QAAQ,GACT,GACF,AAAI,EAAgB,SAAS,aAAa,IAAG,EAAS,OAAO,WAAW,IACnE,EAAS,OAAO,WAAW;QAC3B;IAIL,IAAM,IAAS,SAAS;IACxB,CAAI,CAAC,KAAU,MAAW,SAAS,QAAQ,EAAS,OAAO,IAAI,SAAS,CAAM,MAC5E,EAAY,CAAM,CAAC,EAAE,MAAM;GAE/B;EACF;EAYA,SAAS,IAAgB;GACvB,EAAS,OAAO,KAAK,EAAY,CAAM,KAAK,KAAA,CAAS;EACvD;SAIA,EACE,SACM,EAAS,OAAO,SAAS,IAC/B,SACM,EAAS,OAAO,MAAM,CAC9B,GAOA,EAAa;GAEX,MAAM;GAEN,aAAa,EAAS,OAAO,MAAM;GAEnC,IAAI,QAAe,EAAS,OAAO,MAAM,IAAI;EAC/C,CAAC,+BAIC,EAAqD,EAAA,QAAA,WAAA,EAA/B,cAAe,EAAA,MAAY,CAAA,GACjD,EAWa,GAAA;GAVV,IAAI,EAAA,CAAA;YACD;GAAJ,KAAI;GACH,WAAW,EAAA;GACX,MAAM,EAAA;GACN,SAAS,EAAA;GACT,OAAO,EAAA;GACP,iBAAe,EAAA;GACP;;oBAED,CAAR,EAAQ,EAAA,QAAA,SAAA,CAAA,CAAA"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
@layer vectis.reset, vectis.tokens, vectis.components, vectis.utilities;
|
|
2
|
-
@layer vectis.components{.v-menu-group{gap:var(--vectis-space-1);flex-direction:column;display:flex}
|
|
2
|
+
@layer vectis.components{.v-menu-group{gap:var(--vectis-space-1);flex-direction:column;display:flex}}
|
|
@@ -1,17 +1,21 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A named section inside a menu — "Sort by", "Recent files". The name is announced as
|
|
3
|
-
* the group's label rather than being read as one more item, and it is plain text: it
|
|
4
|
-
* cannot be chosen, and the arrow keys walk straight past it.
|
|
5
|
-
*/
|
|
6
1
|
interface MenuGroupProps {
|
|
7
|
-
/**
|
|
8
|
-
|
|
2
|
+
/**
|
|
3
|
+
* The name of the section, replaced by the `#label` slot. One of the two is REQUIRED:
|
|
4
|
+
* it is what names the group, and a section named by neither points its
|
|
5
|
+
* `aria-labelledby` at an empty element. It is a heading, not a command: nothing
|
|
6
|
+
* happens on click.
|
|
7
|
+
*/
|
|
8
|
+
label?: string;
|
|
9
9
|
}
|
|
10
10
|
type __VLS_Slots = {
|
|
11
11
|
/** The commands belonging to this section. */
|
|
12
12
|
default(): unknown;
|
|
13
|
+
/** A name made of markup, replacing the `label` prop. */
|
|
14
|
+
label?(): unknown;
|
|
13
15
|
};
|
|
14
|
-
declare const __VLS_base: import('vue').DefineComponent<MenuGroupProps, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<MenuGroupProps> & Readonly<{}>, {
|
|
16
|
+
declare const __VLS_base: import('vue').DefineComponent<MenuGroupProps, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<MenuGroupProps> & Readonly<{}>, {
|
|
17
|
+
label: string;
|
|
18
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
15
19
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
16
20
|
declare const _default: typeof __VLS_export;
|
|
17
21
|
export default _default;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VMenuGroup.js","names":[],"sources":["../../../src/components/VMenu/VMenuGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\
|
|
1
|
+
{"version":3,"file":"VMenuGroup.js","names":[],"sources":["../../../src/components/VMenu/VMenuGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @a11y @ssr — the whole script is a single generated id, and it exists only to tie\n// the group to its own label. It matches between server and client by construction,\n// Vue's `useId` guaranteeing exactly that.\n/**\n * A named section inside a menu — \"Sort by\", \"Recent files\". The name is announced as\n * the group's label rather than being read as one more item, and it is plain text: it\n * cannot be chosen, and the arrow keys walk straight past it.\n */\n\nimport { useId } from 'vue'\n\ninterface MenuGroupProps {\n /**\n * The name of the section, replaced by the `#label` slot. One of the two is REQUIRED:\n * it is what names the group, and a section named by neither points its\n * `aria-labelledby` at an empty element. It is a heading, not a command: nothing\n * happens on click.\n */\n label?: string\n}\n\nwithDefaults(defineProps<MenuGroupProps>(), {\n label: undefined,\n})\n\ndefineSlots<{\n /** The commands 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 <div role=\"group\" class=\"v-menu-group\" :aria-labelledby=\"labelId\">\n <span :id=\"labelId\" class=\"v-menu-group-label v-group-label\"\n ><slot name=\"label\">{{ label }}</slot></span\n >\n <slot />\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n .v-menu-group {\n display: flex;\n flex-direction: column;\n gap: var(--vectis-space-1);\n }\n}\n</style>\n"],"mappings":""}
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import { createElementBlock as e, createElementVNode as t,
|
|
1
|
+
import { createElementBlock as e, createElementVNode as t, createTextVNode as n, defineComponent as r, openBlock as i, renderSlot as a, toDisplayString as o, unref as s, useId as c } from "vue";
|
|
2
2
|
//#region src/components/VMenu/VMenuGroup.vue?vue&type=script&setup=true&lang.ts
|
|
3
|
-
var
|
|
3
|
+
var l = ["aria-labelledby"], u = ["id"], d = /*@__PURE__*/ r({
|
|
4
4
|
__name: "VMenuGroup",
|
|
5
|
-
props: { label: {} },
|
|
6
|
-
setup(
|
|
7
|
-
let
|
|
8
|
-
return (
|
|
5
|
+
props: { label: { default: void 0 } },
|
|
6
|
+
setup(r) {
|
|
7
|
+
let d = c();
|
|
8
|
+
return (c, f) => (i(), e("div", {
|
|
9
9
|
role: "group",
|
|
10
10
|
class: "v-menu-group",
|
|
11
|
-
"aria-labelledby":
|
|
11
|
+
"aria-labelledby": s(d)
|
|
12
12
|
}, [t("span", {
|
|
13
|
-
id:
|
|
14
|
-
class: "v-menu-group-label"
|
|
15
|
-
}, a(n.label),
|
|
13
|
+
id: s(d),
|
|
14
|
+
class: "v-menu-group-label v-group-label"
|
|
15
|
+
}, [a(c.$slots, "label", {}, () => [n(o(r.label), 1)])], 8, u), a(c.$slots, "default")], 8, l));
|
|
16
16
|
}
|
|
17
17
|
});
|
|
18
18
|
//#endregion
|
|
19
|
-
export {
|
|
19
|
+
export { d as default };
|
|
20
20
|
|
|
21
21
|
//# sourceMappingURL=VMenuGroup.vue_vue_type_script_setup_true_lang.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VMenuGroup.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/VMenu/VMenuGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\
|
|
1
|
+
{"version":3,"file":"VMenuGroup.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/VMenu/VMenuGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @a11y @ssr — the whole script is a single generated id, and it exists only to tie\n// the group to its own label. It matches between server and client by construction,\n// Vue's `useId` guaranteeing exactly that.\n/**\n * A named section inside a menu — \"Sort by\", \"Recent files\". The name is announced as\n * the group's label rather than being read as one more item, and it is plain text: it\n * cannot be chosen, and the arrow keys walk straight past it.\n */\n\nimport { useId } from 'vue'\n\ninterface MenuGroupProps {\n /**\n * The name of the section, replaced by the `#label` slot. One of the two is REQUIRED:\n * it is what names the group, and a section named by neither points its\n * `aria-labelledby` at an empty element. It is a heading, not a command: nothing\n * happens on click.\n */\n label?: string\n}\n\nwithDefaults(defineProps<MenuGroupProps>(), {\n label: undefined,\n})\n\ndefineSlots<{\n /** The commands 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 <div role=\"group\" class=\"v-menu-group\" :aria-labelledby=\"labelId\">\n <span :id=\"labelId\" class=\"v-menu-group-label v-group-label\"\n ><slot name=\"label\">{{ label }}</slot></span\n >\n <slot />\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n .v-menu-group {\n display: flex;\n flex-direction: column;\n gap: var(--vectis-space-1);\n }\n}\n</style>\n"],"mappings":";;;;;;EAiCA,IAAM,IAAU,EAAM;yBAIpB,EAKM,OAAA;GALD,MAAK;GAAQ,OAAM;GAAgB,mBAAiB,EAAA,CAAA;MACvD,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,EAAQ,EAAA,QAAA,SAAA,CAAA,GAAA,GAAA,CAAA"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
@layer vectis.reset, vectis.tokens, vectis.components, vectis.utilities;
|
|
2
|
-
@layer vectis.components{.v-menu-item{align-items:center;gap:var(--control-gap);
|
|
2
|
+
@layer vectis.components{.v-menu-item{align-items:center;gap:var(--control-gap);inline-size:100%;min-block-size:var(--control-height);padding-block:var(--vectis-space-1);padding-inline:var(--control-padding-inline);color:var(--vectis-color-text);border-radius:min(var(--vectis-radius-interactive), calc(var(--control-height) / 2));font-family:inherit;font-size:var(--control-font-size);line-height:var(--vectis-text-body-md-leading);text-align:start;cursor:pointer;background:0 0;border:none;text-decoration:none;display:flex}.v-menu-item-content{flex-direction:column;flex:1;min-inline-size:0;display:flex}.v-menu-item-label{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.v-menu-item-sublabel{font-size:var(--vectis-text-caption-size);color:var(--vectis-color-text-muted);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.v-menu-item-icon,.v-menu-item-chevron{color:var(--vectis-color-text-muted);flex:none}.v-menu-item:hover:not(:disabled,[aria-disabled=true]),.v-menu-item:focus,.v-menu-item[aria-expanded=true]{background:var(--vectis-color-surface-muted);outline:none}.v-menu-item[data-selected]{background:var(--vectis-color-accent-surface);color:var(--vectis-color-accent-text)}.v-menu-item[data-selected]:hover:not(:disabled,[aria-disabled=true]),.v-menu-item[data-selected]:focus,.v-menu-item[data-selected][aria-expanded=true]{background:color-mix(in oklab, var(--vectis-color-accent-surface), var(--vectis-color-accent-text) 8%)}.v-menu-item[data-tone=danger]{color:var(--vectis-color-danger-text)}.v-menu-item[data-tone=danger]:hover:not(:disabled,[aria-disabled=true]),.v-menu-item[data-tone=danger]:focus,.v-menu-item[data-tone=danger][aria-expanded=true]{background:var(--vectis-color-danger-surface)}.v-menu-item:disabled,.v-menu-item[aria-disabled=true]{color:var(--vectis-color-text-subtle);cursor:not-allowed;background:0 0}.v-menu-item:is([data-selected],[data-tone=danger],:disabled,[aria-disabled=true]) :is(.v-menu-item-icon,.v-menu-item-sublabel){color:inherit}}
|
|
@@ -1,21 +1,9 @@
|
|
|
1
1
|
import { IconSource } from '../VIcon/types.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* Given an `href` the item becomes a link. A link has no `disabled` attribute of its
|
|
7
|
-
* own, so a disabled one is made inert by hand: its address is removed, and
|
|
8
|
-
* `aria-disabled` tells assistive technology why it no longer responds.
|
|
9
|
-
*
|
|
10
|
-
* Given the `#submenu` slot it becomes the trigger of a nested panel, which is
|
|
11
|
-
* rendered INSIDE the parent one. That nesting is what buys the whole submenu
|
|
12
|
-
* behaviour from the browser: the panels form a stack, clicking outside closes all of
|
|
13
|
-
* them, and opening one branch closes its sibling.
|
|
14
|
-
*
|
|
15
|
-
* The JavaScript is limited to the two ways of opening a submenu the browser does not
|
|
16
|
-
* cover: the keyboard, and hovering long enough to show it was meant. A click already
|
|
17
|
-
* opens it natively.
|
|
3
|
+
* What a command means, in colour. It is the subset of VButton's tones a menu row can
|
|
4
|
+
* carry: an ordinary command, or a destructive one.
|
|
18
5
|
*/
|
|
6
|
+
export type MenuItemTone = 'neutral' | 'danger';
|
|
19
7
|
interface MenuItemProps {
|
|
20
8
|
/** What the command says. The default slot replaces it. */
|
|
21
9
|
label?: string;
|
|
@@ -34,10 +22,14 @@ interface MenuItemProps {
|
|
|
34
22
|
*/
|
|
35
23
|
selected?: boolean;
|
|
36
24
|
/**
|
|
37
|
-
*
|
|
38
|
-
* something belongs
|
|
25
|
+
* What the command means, in colour. `danger` marks it destructive — deleting
|
|
26
|
+
* something belongs there — and `neutral`, the default, is every other command.
|
|
27
|
+
*
|
|
28
|
+
* A row is an action, so it takes the vocabulary of one: the same word on the same
|
|
29
|
+
* prop as a VButton, rather than a boolean of its own. There is no `accent` here,
|
|
30
|
+
* a menu having no primary command among its rows.
|
|
39
31
|
*/
|
|
40
|
-
|
|
32
|
+
tone?: MenuItemTone;
|
|
41
33
|
/** Makes the item unusable: it no longer responds and the arrows skip over it. */
|
|
42
34
|
disabled?: boolean;
|
|
43
35
|
/**
|
|
@@ -67,7 +59,7 @@ declare const __VLS_base: import('vue').DefineComponent<MenuItemProps, {}, {}, {
|
|
|
67
59
|
onSelect?: (() => any) | undefined;
|
|
68
60
|
}>, {
|
|
69
61
|
label: string;
|
|
70
|
-
|
|
62
|
+
tone: MenuItemTone;
|
|
71
63
|
href: string;
|
|
72
64
|
disabled: boolean;
|
|
73
65
|
iconStart: IconSource;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VMenuItem.js","names":[],"sources":["../../../src/components/VMenu/VMenuItem.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, inject, ref, useId, useSlots } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport { chevron_right as chevronRightIcon } from '../VIcon/icons/chevron_right'\nimport type { IconSource } from '../VIcon/types'\nimport VMenuPanel from './VMenuPanel.vue'\nimport { menuKey, SUBMENU_HOVER_DELAY } from './context'\n\nimport { useTimer } from '../../composables/useTimer'\n\n/**\n * One command in a menu. The panel is what moves the focus between items, and\n * choosing one closes the whole menu, submenus included.\n *\n * Given an `href` the item becomes a link. A link has no `disabled` attribute of its\n * own, so a disabled one is made inert by hand: its address is removed, and\n * `aria-disabled` tells assistive technology why it no longer responds.\n *\n * Given the `#submenu` slot it becomes the trigger of a nested panel, which is\n * rendered INSIDE the parent one. That nesting is what buys the whole submenu\n * behaviour from the browser: the panels form a stack, clicking outside closes all of\n * them, and opening one branch closes its sibling.\n *\n * The JavaScript is limited to the two ways of opening a submenu the browser does not\n * cover: the keyboard, and hovering long enough to show it was meant. A click already\n * opens it natively.\n */\ninterface MenuItemProps {\n /** What the command says. The default slot replaces it. */\n label?: string\n /** A second line under the label, for a shortcut or a short explanation. */\n sublabel?: string\n /**\n * An icon before the label: an icon name, an image address, or an explicit render.\n * The `#start` slot replaces it.\n */\n iconStart?: IconSource\n /** An icon after the label, in the same forms. The `#end` slot replaces it. */\n iconEnd?: IconSource\n /**\n * Marks this item as the one currently in effect — the chosen sort order, the\n * active view. It is coloured and announced as such.\n */\n selected?: boolean\n /**\n * Marks the command as destructive, which colours it accordingly. Deleting\n * something belongs here.\n */\n danger?: boolean\n /** Makes the item unusable: it no longer responds and the arrows skip over it. */\n disabled?: boolean\n /**\n * Turns the item into a link pointing at this address, for a menu that navigates\n * rather than acts. A disabled link is made inert by hand.\n */\n href?: string\n}\n\n// With a submenu this component renders two elements — the item and the nested panel\n// — so there is no single root for Vue to put the consumer's attributes on. They are\n// placed on the item explicitly.\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<MenuItemProps>(), {\n label: undefined,\n sublabel: undefined,\n iconStart: undefined,\n iconEnd: undefined,\n selected: false,\n danger: false,\n disabled: false,\n href: undefined,\n})\n\nconst emit = defineEmits<{\n /**\n * The command was chosen, by click or by keyboard. It is emitted before the menu\n * closes, so the handler runs while the menu is still open.\n */\n select: []\n}>()\n\ndefineSlots<{\n /** The label, replacing the `label` prop. */\n default?(): unknown\n /** The second line, replacing the `sublabel` prop. */\n sublabel?(): unknown\n /** Free content before the label, which takes the place of `iconStart`. */\n start?(): unknown\n /** Free content after the label, which takes the place of `iconEnd`. */\n end?(): unknown\n /**\n * The contents of a submenu — items, groups and separators, this component\n * included, so menus may nest as deep as needed.\n */\n submenu?(): unknown\n}>()\n\nconst slots = useSlots()\nconst hasSubmenu = computed(() => !!slots.submenu)\nconst tag = computed(() =>\n !hasSubmenu.value && props.href !== undefined ? ('a' as const) : ('button' as const),\n)\n\nconst menu = inject(menuKey, null)\n\nfunction onClick() {\n if (props.disabled || hasSubmenu.value) return\n emit('select')\n menu?.closeAll()\n}\n\nconst subId = useId()\nconst subOpen = ref(false)\nconst subPanel = ref<InstanceType<typeof VMenuPanel> | null>(null)\n// TRAP — when a submenu is opened from code rather than by a click, the item must be\n// handed to the browser as the source of that opening. The implicit anchor is only\n// established natively, on click; without it the panel has nothing to position itself\n// against and lands at the corner of the viewport, with no error anywhere.\nconst itemEl = ref<HTMLElement | null>(null)\n\n// @keyboard\n// Opening a submenu from the keyboard, which the browser's own toggle does not cover\n// — it only reacts to a click.\nfunction onKeydown(event: KeyboardEvent) {\n if (!hasSubmenu.value || props.disabled) return\n if (!['ArrowRight', 'Enter', ' '].includes(event.key)) return\n // The button's native activation has to be stopped: it would fire a click of its\n // own, and that click would toggle the panel shut again right behind the opening\n // below.\n event.preventDefault()\n subPanel.value?.show(itemEl.value ?? undefined)\n subPanel.value?.focusFirst()\n}\n\n// A submenu opens on hover, but only once the pointer has stayed long enough to show\n// it was meant — otherwise every panel crossed on the way to another one would flash\n// open. ONE timer serves both directions, since opening and closing are mutually\n// exclusive: arming either always cancels the other.\nconst hoverTimer = useTimer()\n\n// @a11y @core\nfunction onPointerEnter() {\n if (props.disabled) return\n // Hovering also moves the focus, so that the mouse and the keyboard never highlight\n // two different items at once — in a menu there is only ever one current item.\n itemEl.value?.focus({ preventScroll: true })\n if (!hasSubmenu.value) return\n hoverTimer.start(() => subPanel.value?.show(itemEl.value ?? undefined), SUBMENU_HOVER_DELAY)\n}\n\n// @a11y @core — the test on where the focus currently is, is the accessibility half:\n// a pointer drifting off the item must not close a submenu a keyboard user is\n// standing inside.\nfunction onPointerLeave() {\n if (!hasSubmenu.value) return\n hoverTimer.start(() => {\n if (subPanel.value?.el?.contains(document.activeElement)) return\n subPanel.value?.hide()\n }, SUBMENU_HOVER_DELAY)\n}\n</script>\n\n<template>\n <component\n :is=\"tag\"\n ref=\"itemEl\"\n v-bind=\"$attrs\"\n role=\"menuitem\"\n tabindex=\"-1\"\n class=\"v-menu-item\"\n :type=\"tag === 'button' ? 'button' : undefined\"\n :disabled=\"tag === 'button' ? disabled : undefined\"\n :href=\"tag === 'a' && !disabled ? href : undefined\"\n :aria-disabled=\"tag === 'a' && disabled ? 'true' : undefined\"\n :data-danger=\"danger ? '' : undefined\"\n :data-selected=\"selected ? '' : undefined\"\n :aria-current=\"selected ? 'true' : undefined\"\n :aria-haspopup=\"hasSubmenu ? 'menu' : undefined\"\n :aria-expanded=\"hasSubmenu ? subOpen : undefined\"\n :aria-controls=\"hasSubmenu ? subId : undefined\"\n :popovertarget=\"hasSubmenu ? subId : undefined\"\n @click=\"onClick\"\n @keydown=\"onKeydown\"\n @pointerenter=\"onPointerEnter\"\n @pointerleave=\"onPointerLeave\"\n >\n <slot name=\"start\">\n <VIcon v-if=\"iconStart\" v-bind=\"iconProps(iconStart)\" />\n </slot>\n <span class=\"v-menu-item-content\">\n <span class=\"v-menu-item-label\"\n ><slot>{{ label }}</slot></span\n >\n <span v-if=\"sublabel !== undefined || $slots.sublabel\" class=\"v-menu-item-sublabel\">\n <slot name=\"sublabel\">{{ sublabel }}</slot>\n </span>\n </span>\n <!-- An item opening a submenu always shows the chevron announcing it, and never\n the end icon: the sideways opening is what the reader needs to be told -->\n <VIcon v-if=\"hasSubmenu\" :name=\"chevronRightIcon\" class=\"v-menu-item-chevron\" />\n <slot v-else name=\"end\">\n <VIcon v-if=\"iconEnd\" v-bind=\"iconProps(iconEnd)\" />\n </slot>\n </component>\n <VMenuPanel\n v-if=\"hasSubmenu\"\n :id=\"subId\"\n ref=\"subPanel\"\n placement=\"right-start\"\n submenu\n @toggle=\"subOpen = $event\"\n @pointerenter=\"hoverTimer.cancel()\"\n @pointerleave=\"onPointerLeave\"\n >\n <slot name=\"submenu\" />\n </VMenuPanel>\n</template>\n\n<style>\n@layer vectis.components {\n .v-menu-item {\n /*\n * Every dimension comes from the `--control-*` variables the root panel sets and\n * this row inherits — one size table for the whole design system. The icons follow\n * with nothing written for them, their own variables belonging to that same block.\n *\n * The type is the one composite part: the SIZE comes from the scale, but the line\n * height stays that of body text — a unitless ratio, so it still follows the size\n * — and the weight stays regular. The full `control` type role would mean a medium\n * weight and lines set tight against each other, which suits a single-line label\n * and not a row that may wrap and carry a second line under it.\n */\n display: flex;\n align-items: center;\n gap: var(--control-gap);\n width: 100%;\n min-height: var(--control-height);\n padding: var(--vectis-space-1) var(--control-padding-inline);\n border: none;\n background: transparent;\n color: var(--vectis-color-text);\n border-radius: var(--vectis-radius-sm);\n font-family: inherit;\n font-size: var(--control-font-size);\n line-height: var(--vectis-text-body-md-leading);\n text-align: start;\n text-decoration: none;\n cursor: pointer;\n }\n\n .v-menu-item-content {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n }\n\n .v-menu-item-sublabel {\n font-size: var(--vectis-text-caption-size);\n color: var(--vectis-color-text-muted);\n }\n\n .v-menu-item-chevron {\n color: var(--vectis-color-text-muted);\n }\n\n .v-menu-item-chevron:dir(rtl) {\n transform: scaleX(-1);\n }\n\n /* In a menu the focus IS the highlight, so it is drawn on `:focus` and not on\n `:focus-visible`: the focus is moved from code — by the arrows, and by hovering —\n and the browser would not call that a keyboard focus worth showing. */\n .v-menu-item:hover:not(:disabled, [aria-disabled='true']),\n .v-menu-item:focus {\n background: var(--vectis-color-surface-muted);\n outline: none;\n }\n\n /* While a submenu is open its parent item keeps the highlight, so the path followed\n through the levels stays visible. */\n .v-menu-item[aria-expanded='true'] {\n background: var(--vectis-color-surface-muted);\n }\n\n .v-menu-item[data-selected] {\n background: var(--vectis-color-accent-surface);\n color: var(--vectis-color-accent-text);\n }\n\n .v-menu-item[data-selected] .v-menu-item-sublabel {\n color: inherit;\n }\n\n .v-menu-item[data-selected]:hover:not(:disabled, [aria-disabled='true']),\n .v-menu-item[data-selected]:focus,\n .v-menu-item[data-selected][aria-expanded='true'] {\n /* The selected row is already tinted, so its hover deepens that tint rather than\n replacing it with the neutral highlight. */\n background: color-mix(\n in oklab,\n var(--vectis-color-accent-surface),\n var(--vectis-color-accent-text) 8%\n );\n }\n\n .v-menu-item[data-danger] {\n color: var(--vectis-color-danger-text);\n }\n\n .v-menu-item[data-danger] .v-menu-item-sublabel {\n color: inherit;\n }\n\n .v-menu-item[data-danger]:hover:not(:disabled, [aria-disabled='true']),\n .v-menu-item[data-danger]:focus,\n .v-menu-item[data-danger][aria-expanded='true'] {\n background: var(--vectis-color-danger-surface);\n }\n\n /* Both forms have to be matched: `:disabled` only ever applies to a `<button>`, and\n an item rendered as a link is made inert through `aria-disabled` instead. */\n .v-menu-item:disabled,\n .v-menu-item[aria-disabled='true'] {\n background: transparent;\n color: var(--vectis-color-text-subtle);\n cursor: not-allowed;\n }\n\n .v-menu-item:disabled .v-menu-item-sublabel,\n .v-menu-item[aria-disabled='true'] .v-menu-item-sublabel {\n color: inherit;\n }\n}\n</style>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"VMenuItem.js","names":[],"sources":["../../../src/components/VMenu/VMenuItem.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * One command in a menu. The panel moves the focus between items, and choosing one closes\n * the whole menu, submenus included.\n *\n * With an `href` it becomes a link, made inert by hand when disabled — a link has no\n * `disabled` attribute, so the address is removed and `aria-disabled` says why.\n *\n * With the `#submenu` slot it becomes the trigger of a nested panel rendered INSIDE the\n * parent one. That nesting is what buys the submenu behaviour from the browser: the panels\n * form a native stack, a click outside closes all of them, and opening one branch closes its\n * sibling.\n *\n * The JS covers only the two openings the browser does not: the keyboard, and a hover held\n * long enough to show it was meant. A click already opens it natively.\n */\n\nimport { inject, ref, useId } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport { chevron_right as chevronRightIcon } from '../VIcon/icons/chevron_right'\nimport type { IconSource } from '../VIcon/types'\nimport VMenuPanel from './VMenuPanel.vue'\nimport { menuKey, SUBMENU_HOVER_DELAY } from './context'\n\nimport { useTimer } from '../../composables/useTimer'\n\n/**\n * What a command means, in colour. It is the subset of VButton's tones a menu row can\n * carry: an ordinary command, or a destructive one.\n */\nexport type MenuItemTone = 'neutral' | 'danger'\n\ninterface MenuItemProps {\n /** What the command says. The default slot replaces it. */\n label?: string\n /** A second line under the label, for a shortcut or a short explanation. */\n sublabel?: string\n /**\n * An icon before the label: an icon name, an image address, or an explicit render.\n * The `#start` slot replaces it.\n */\n iconStart?: IconSource\n /** An icon after the label, in the same forms. The `#end` slot replaces it. */\n iconEnd?: IconSource\n /**\n * Marks this item as the one currently in effect — the chosen sort order, the\n * active view. It is coloured and announced as such.\n */\n selected?: boolean\n /**\n * What the command means, in colour. `danger` marks it destructive — deleting\n * something belongs there — and `neutral`, the default, is every other command.\n *\n * A row is an action, so it takes the vocabulary of one: the same word on the same\n * prop as a VButton, rather than a boolean of its own. There is no `accent` here,\n * a menu having no primary command among its rows.\n */\n tone?: MenuItemTone\n /** Makes the item unusable: it no longer responds and the arrows skip over it. */\n disabled?: boolean\n /**\n * Turns the item into a link pointing at this address, for a menu that navigates\n * rather than acts. A disabled link is made inert by hand.\n */\n href?: string\n}\n\n// With a submenu this component renders two elements — the item and the nested panel\n// — so there is no single root for Vue to put the consumer's attributes on. They are\n// placed on the item explicitly.\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<MenuItemProps>(), {\n label: undefined,\n sublabel: undefined,\n iconStart: undefined,\n iconEnd: undefined,\n selected: false,\n tone: 'neutral',\n disabled: false,\n href: undefined,\n})\n\nconst emit = defineEmits<{\n /**\n * The command was chosen, by click or by keyboard. It is emitted before the menu\n * closes, so the handler runs while the menu is still open.\n */\n select: []\n}>()\n\nconst slots = defineSlots<{\n /** The label, replacing the `label` prop. */\n default?(): unknown\n /** The second line, replacing the `sublabel` prop. */\n sublabel?(): unknown\n /** Free content before the label, which takes the place of `iconStart`. */\n start?(): unknown\n /** Free content after the label, which takes the place of `iconEnd`. */\n end?(): unknown\n /**\n * The contents of a submenu — items, groups and separators, this component\n * included, so menus may nest as deep as needed.\n */\n submenu?(): unknown\n}>()\n\n// TRAP — a function read by the template, never a `computed`: `slots` is not reactive, so a\n// computed would keep its first answer while a slot behind a `v-if` comes and goes.\nfunction hasSubmenu() {\n return !!slots.submenu\n}\nfunction tag() {\n return !hasSubmenu() && props.href !== undefined ? ('a' as const) : ('button' as const)\n}\n\nconst menu = inject(menuKey, null)\n\nfunction onClick() {\n if (props.disabled || hasSubmenu()) return\n emit('select')\n menu?.closeAll()\n}\n\nconst subId = useId()\nconst subOpen = ref(false)\nconst subPanel = ref<InstanceType<typeof VMenuPanel> | null>(null)\n// TRAP — when a submenu is opened from code rather than by a click, the item must be\n// handed to the browser as the source of that opening. The implicit anchor is only\n// established natively, on click; without it the panel has nothing to position itself\n// against and lands at the corner of the viewport, with no error anywhere.\nconst itemEl = ref<HTMLElement | null>(null)\n\n// @keyboard\n// Opening a submenu from the keyboard, which the browser's own toggle does not cover\n// — it only reacts to a click.\nfunction onKeydown(event: KeyboardEvent) {\n if (!hasSubmenu() || props.disabled) return\n if (!['ArrowRight', 'Enter', ' '].includes(event.key)) return\n // The button's native activation has to be stopped: it would fire a click of its\n // own, and that click would toggle the panel shut again right behind the opening\n // below.\n event.preventDefault()\n subPanel.value?.show(itemEl.value ?? undefined)\n subPanel.value?.focusFirst()\n}\n\n// A submenu opens on hover, but only once the pointer has stayed long enough to show\n// it was meant — otherwise every panel crossed on the way to another one would flash\n// open. ONE timer serves both directions, since opening and closing are mutually\n// exclusive: arming either always cancels the other.\nconst hoverTimer = useTimer()\n\n// @a11y @core\nfunction onPointerEnter() {\n if (props.disabled) return\n // Hovering also moves the focus, so that the mouse and the keyboard never highlight\n // two different items at once — in a menu there is only ever one current item.\n itemEl.value?.focus({ preventScroll: true })\n if (!hasSubmenu()) return\n hoverTimer.start(() => subPanel.value?.show(itemEl.value ?? undefined), SUBMENU_HOVER_DELAY)\n}\n\n// @a11y @core — the test on where the focus currently is, is the accessibility half:\n// a pointer drifting off the item must not close a submenu a keyboard user is\n// standing inside.\nfunction onPointerLeave() {\n if (!hasSubmenu()) return\n hoverTimer.start(() => {\n if (subPanel.value?.el?.contains(document.activeElement)) return\n subPanel.value?.close()\n }, SUBMENU_HOVER_DELAY)\n}\n</script>\n\n<template>\n <component\n :is=\"tag()\"\n ref=\"itemEl\"\n v-bind=\"$attrs\"\n role=\"menuitem\"\n tabindex=\"-1\"\n class=\"v-menu-item\"\n :type=\"tag() === 'button' ? 'button' : undefined\"\n :disabled=\"tag() === 'button' ? disabled : undefined\"\n :href=\"tag() === 'a' && !disabled ? href : undefined\"\n :aria-disabled=\"tag() === 'a' && disabled ? 'true' : undefined\"\n :data-tone=\"tone\"\n :data-selected=\"selected ? '' : undefined\"\n :aria-current=\"selected ? 'true' : undefined\"\n :aria-haspopup=\"hasSubmenu() ? 'menu' : undefined\"\n :aria-expanded=\"hasSubmenu() ? subOpen : undefined\"\n :aria-controls=\"hasSubmenu() ? subId : undefined\"\n :popovertarget=\"hasSubmenu() ? subId : undefined\"\n @click=\"onClick\"\n @keydown=\"onKeydown\"\n @pointerenter=\"onPointerEnter\"\n @pointerleave=\"onPointerLeave\"\n >\n <slot name=\"start\">\n <VIcon v-if=\"iconStart\" class=\"v-menu-item-icon\" v-bind=\"iconProps(iconStart)\" />\n </slot>\n <span class=\"v-menu-item-content\">\n <span class=\"v-menu-item-label\"\n ><slot>{{ label }}</slot></span\n >\n <span v-if=\"sublabel !== undefined || $slots.sublabel\" class=\"v-menu-item-sublabel\">\n <slot name=\"sublabel\">{{ sublabel }}</slot>\n </span>\n </span>\n <!-- An item opening a submenu always shows the chevron announcing it, and never\n the end icon: the sideways opening is what the reader needs to be told -->\n <VIcon v-if=\"hasSubmenu()\" :name=\"chevronRightIcon\" class=\"v-menu-item-chevron\" mirrored />\n <slot v-else name=\"end\">\n <VIcon v-if=\"iconEnd\" v-bind=\"iconProps(iconEnd)\" />\n </slot>\n </component>\n <VMenuPanel\n v-if=\"hasSubmenu()\"\n :id=\"subId\"\n ref=\"subPanel\"\n placement=\"right-start\"\n submenu\n @toggle=\"subOpen = $event\"\n @pointerenter=\"hoverTimer.cancel()\"\n @pointerleave=\"onPointerLeave\"\n >\n <slot name=\"submenu\" />\n </VMenuPanel>\n</template>\n\n<style>\n@layer vectis.components {\n .v-menu-item {\n /*\n * Every dimension comes from the `--control-*` variables the root panel sets and\n * this row inherits — one size table for the whole design system. The icons follow\n * with nothing written for them, their own variables belonging to that same block.\n *\n * The type is the one composite part: the SIZE comes from the scale, but the line\n * height stays that of body text — a unitless ratio, so it still follows the size\n * — and the weight stays regular. The full `control` type role would mean a medium\n * weight and lines set tight against each other, and a row may carry a second line\n * under its label.\n *\n * The label and that second line TRUNCATE rather than wrap, the VSideNavigationItem\n * recipe: the panel has a ceiling, and a command that grew a line would break the\n * rhythm of the list. `width` on VMenu is the way to give long labels more room.\n *\n * The corner is VSideNavigationItem's: the control radius capped at half a control\n * height, so a pill override paints every row of a menu alike, a row carrying a\n * sublabel included, instead of rounding each one to half of its own height.\n */\n display: flex;\n align-items: center;\n gap: var(--control-gap);\n inline-size: 100%;\n min-block-size: var(--control-height);\n padding-block: var(--vectis-space-1);\n padding-inline: var(--control-padding-inline);\n border: none;\n background: transparent;\n color: var(--vectis-color-text);\n border-radius: min(var(--vectis-radius-interactive), calc(var(--control-height) / 2));\n font-family: inherit;\n font-size: var(--control-font-size);\n line-height: var(--vectis-text-body-md-leading);\n text-align: start;\n text-decoration: none;\n cursor: pointer;\n }\n\n .v-menu-item-content {\n flex: 1;\n min-inline-size: 0;\n display: flex;\n flex-direction: column;\n }\n\n .v-menu-item-label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .v-menu-item-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 /* The start icon is muted, as on every row of the design system (VSideNavigationItem,\n VAccordionItem): the label carries the command, the icon only helps find it. */\n .v-menu-item-icon,\n .v-menu-item-chevron {\n flex: none;\n color: var(--vectis-color-text-muted);\n }\n\n /* In a menu the focus IS the highlight, so it is drawn on `:focus` and not on\n `:focus-visible`: the focus is moved from code — by the arrows, and by hovering —\n and the browser would not call that a keyboard focus worth showing. While a submenu is\n open its parent item keeps the highlight too, so the path followed through the levels\n stays visible. */\n .v-menu-item:hover:not(:disabled, [aria-disabled='true']),\n .v-menu-item:focus,\n .v-menu-item[aria-expanded='true'] {\n background: var(--vectis-color-surface-muted);\n outline: none;\n }\n\n .v-menu-item[data-selected] {\n background: var(--vectis-color-accent-surface);\n color: var(--vectis-color-accent-text);\n }\n\n .v-menu-item[data-selected]:hover:not(:disabled, [aria-disabled='true']),\n .v-menu-item[data-selected]:focus,\n .v-menu-item[data-selected][aria-expanded='true'] {\n /* The selected row is already tinted, so its hover deepens that tint rather than\n replacing it with the neutral highlight. */\n background: color-mix(\n in oklab,\n var(--vectis-color-accent-surface),\n var(--vectis-color-accent-text) 8%\n );\n }\n\n .v-menu-item[data-tone='danger'] {\n color: var(--vectis-color-danger-text);\n }\n\n .v-menu-item[data-tone='danger']:hover:not(:disabled, [aria-disabled='true']),\n .v-menu-item[data-tone='danger']:focus,\n .v-menu-item[data-tone='danger'][aria-expanded='true'] {\n background: var(--vectis-color-danger-surface);\n }\n\n /* Both forms have to be matched: `:disabled` only ever applies to a `<button>`, and\n an item rendered as a link is made inert through `aria-disabled` instead. */\n .v-menu-item:disabled,\n .v-menu-item[aria-disabled='true'] {\n background: transparent;\n color: var(--vectis-color-text-subtle);\n cursor: not-allowed;\n }\n\n /* On a row painted in a colour of its own, the start icon and the second line take the\n label's colour rather than the muted grey: muted would clash with the selected and the\n danger tints, and on a disabled row it is DARKER than the subtle grey the label takes,\n so they would outshine it. Each `:is()` counts for its most specific member, which\n keeps the rule at (0,3,0), above the two (0,1,0) base rules. */\n .v-menu-item:is([data-selected], [data-tone='danger'], :disabled, [aria-disabled='true'])\n :is(.v-menu-item-icon, .v-menu-item-sublabel) {\n color: inherit;\n }\n}\n</style>\n"],"mappings":""}
|