vectis-ui 0.8.1 → 0.9.1
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 +3 -3
- package/dist/components/VAccordion/VAccordionItem.d.ts +4 -6
- package/dist/components/VAccordion/VAccordionItem.js.map +1 -1
- package/dist/components/VAccordion/VAccordionItem.vue_vue_type_script_setup_true_lang.js +21 -19
- package/dist/components/VAccordion/VAccordionItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VAccordion/context.d.ts +6 -1
- package/dist/components/VAccordion/context.js.map +1 -1
- package/dist/components/VAvatar/VAvatar.css +1 -1
- package/dist/components/VAvatar/VAvatar.d.ts +5 -3
- package/dist/components/VAvatar/VAvatar.js.map +1 -1
- package/dist/components/VAvatar/VAvatar.vue_vue_type_script_setup_true_lang.js +53 -39
- package/dist/components/VAvatar/VAvatar.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VAvatar/VAvatarGroup.d.ts +12 -3
- package/dist/components/VAvatar/VAvatarGroup.js.map +1 -1
- package/dist/components/VAvatar/VAvatarGroup.vue_vue_type_script_setup_true_lang.js +27 -20
- package/dist/components/VAvatar/VAvatarGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VAvatar/context.d.ts +2 -2
- package/dist/components/VAvatar/context.js.map +1 -1
- package/dist/components/VBadge/VBadge.css +1 -1
- package/dist/components/VBadge/VBadge.d.ts +8 -4
- package/dist/components/VBadge/VBadge.js.map +1 -1
- package/dist/components/VBadge/VBadge.vue_vue_type_script_setup_true_lang.js +6 -3
- package/dist/components/VBadge/VBadge.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VBreadcrumb/VBreadcrumb.d.ts +5 -4
- package/dist/components/VBreadcrumb/VBreadcrumb.js.map +1 -1
- package/dist/components/VBreadcrumb/VBreadcrumb.vue_vue_type_script_setup_true_lang.js +8 -3
- 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 +4 -1
- package/dist/components/VButton/VButton.js.map +1 -1
- package/dist/components/VButton/VButton.vue_vue_type_script_setup_true_lang.js +8 -7
- package/dist/components/VButton/VButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VButton/VButtonGroup.js.map +1 -1
- package/dist/components/VButton/VButtonGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCalendar/VCalendar.css +1 -1
- package/dist/components/VCalendar/VCalendar.d.ts +15 -6
- package/dist/components/VCalendar/VCalendar.js.map +1 -1
- package/dist/components/VCalendar/VCalendar.vue_vue_type_script_setup_true_lang.js +144 -126
- 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 +1 -1
- package/dist/components/VCalendar/VCalendarEvent.js.map +1 -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 +1 -1
- package/dist/components/VCalendar/VCalendarMonth.js.map +1 -1
- package/dist/components/VCalendar/VCalendarMonth.vue_vue_type_script_setup_true_lang.js +99 -90
- 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 +3 -3
- package/dist/components/VCalendar/VCalendarTimeGrid.js.map +1 -1
- package/dist/components/VCalendar/VCalendarTimeGrid.vue_vue_type_script_setup_true_lang.js +256 -246
- 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.d.ts +8 -1
- package/dist/components/VCalendar/VCalendarYear.js.map +1 -1
- package/dist/components/VCalendar/VCalendarYear.vue_vue_type_script_setup_true_lang.js +39 -32
- package/dist/components/VCalendar/VCalendarYear.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCalendar/color.d.ts +1 -1
- package/dist/components/VCalendar/color.js.map +1 -1
- package/dist/components/VCalendar/edgeStep.d.ts +3 -3
- package/dist/components/VCalendar/edgeStep.js +5 -0
- package/dist/components/VCalendar/edgeStep.js.map +1 -1
- package/dist/components/VCalendar/gesture.d.ts +10 -9
- package/dist/components/VCalendar/gesture.js +60 -45
- package/dist/components/VCalendar/gesture.js.map +1 -1
- package/dist/components/VCalendar/keyboard.d.ts +22 -5
- package/dist/components/VCalendar/keyboard.js +17 -16
- package/dist/components/VCalendar/keyboard.js.map +1 -1
- package/dist/components/VCalendar/layout.d.ts +47 -37
- package/dist/components/VCalendar/layout.js +47 -37
- package/dist/components/VCalendar/layout.js.map +1 -1
- package/dist/components/VCalendar/timeGrid.d.ts +4 -4
- package/dist/components/VCalendar/timeGrid.js +6 -6
- package/dist/components/VCalendar/timeGrid.js.map +1 -1
- package/dist/components/VCalendar/types.d.ts +5 -5
- package/dist/components/VCarousel/VCarousel.css +1 -1
- package/dist/components/VCarousel/VCarousel.d.ts +59 -38
- package/dist/components/VCarousel/VCarousel.js.map +1 -1
- package/dist/components/VCarousel/VCarousel.vue_vue_type_script_setup_true_lang.js +161 -132
- package/dist/components/VCarousel/VCarousel.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCarousel/VCarouselItem.d.ts +1 -1
- 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 +1 -1
- package/dist/components/VCarousel/context.js.map +1 -1
- package/dist/components/VCheckbox/VCheckbox.css +1 -1
- package/dist/components/VCheckbox/VCheckbox.d.ts +2 -2
- package/dist/components/VCheckbox/VCheckbox.js.map +1 -1
- package/dist/components/VCheckbox/VCheckbox.vue_vue_type_script_setup_true_lang.js +10 -8
- 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 +7 -2
- package/dist/components/VChip/VChip.js.map +1 -1
- package/dist/components/VChip/VChip.vue_vue_type_script_setup_true_lang.js +69 -55
- 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 +50 -36
- package/dist/components/VCombobox/VCombobox.js.map +1 -1
- package/dist/components/VCombobox/VCombobox.vue_vue_type_script_setup_true_lang.js +167 -161
- 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.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/infiniteScroll.d.ts +12 -3
- package/dist/components/VCombobox/infiniteScroll.js +18 -12
- package/dist/components/VCombobox/infiniteScroll.js.map +1 -1
- package/dist/components/VDataTable/VDataTable.css +1 -1
- package/dist/components/VDataTable/VDataTable.d.ts +55 -24
- package/dist/components/VDataTable/VDataTable.js.map +1 -1
- package/dist/components/VDataTable/VDataTable.vue_vue_type_script_setup_true_lang.js +192 -155
- 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 +15 -12
- package/dist/components/VDateInput/VDateInput.js.map +1 -1
- package/dist/components/VDateInput/VDateInput.vue_vue_type_script_setup_true_lang.js +180 -160
- package/dist/components/VDateInput/VDateInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VDateInput/mask.d.ts +95 -0
- package/dist/components/VDateInput/mask.js +118 -0
- package/dist/components/VDateInput/mask.js.map +1 -0
- package/dist/components/VDatePicker/VDatePicker.css +1 -1
- package/dist/components/VDatePicker/VDatePicker.d.ts +6 -5
- package/dist/components/VDatePicker/VDatePicker.js.map +1 -1
- package/dist/components/VDatePicker/VDatePicker.vue_vue_type_script_setup_true_lang.js +204 -173
- package/dist/components/VDatePicker/VDatePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VDatePicker/keyboard.d.ts +3 -3
- package/dist/components/VDatePicker/keyboard.js.map +1 -1
- package/dist/components/VDatePicker/names.d.ts +34 -0
- package/dist/components/VDatePicker/names.js +42 -0
- package/dist/components/VDatePicker/names.js.map +1 -0
- package/dist/components/VDialog/VDialog.css +1 -1
- package/dist/components/VDialog/VDialog.d.ts +2 -2
- package/dist/components/VDialog/VDialog.js.map +1 -1
- package/dist/components/VDialog/VDialog.vue_vue_type_script_setup_true_lang.js +63 -41
- package/dist/components/VDialog/VDialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VFileInput/VFileInput.d.ts +38 -25
- package/dist/components/VFileInput/VFileInput.js.map +1 -1
- package/dist/components/VFileInput/VFileInput.vue_vue_type_script_setup_true_lang.js +74 -71
- package/dist/components/VFileInput/VFileInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VFileInput/truncate.d.ts +4 -4
- package/dist/components/VFileInput/truncate.js.map +1 -1
- package/dist/components/VFilePicker/VFilePicker.css +1 -1
- package/dist/components/VFilePicker/VFilePicker.d.ts +54 -37
- package/dist/components/VFilePicker/VFilePicker.js.map +1 -1
- package/dist/components/VFilePicker/VFilePicker.vue_vue_type_script_setup_true_lang.js +152 -135
- package/dist/components/VFilePicker/VFilePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VFilePicker/fileKind.d.ts +2 -2
- package/dist/components/VFilePicker/fileKind.js.map +1 -1
- package/dist/components/VHotkeys/VHotkeys.css +1 -1
- package/dist/components/VHotkeys/VHotkeys.d.ts +10 -8
- package/dist/components/VHotkeys/VHotkeys.js.map +1 -1
- package/dist/components/VHotkeys/VHotkeys.vue_vue_type_script_setup_true_lang.js +22 -20
- package/dist/components/VHotkeys/VHotkeys.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VHotkeys/platform.d.ts +9 -7
- package/dist/components/VHotkeys/platform.js +41 -30
- package/dist/components/VHotkeys/platform.js.map +1 -1
- package/dist/components/VIcon/VIcon.css +1 -1
- package/dist/components/VIcon/VIcon.d.ts +6 -6
- package/dist/components/VIcon/VIcon.js.map +1 -1
- package/dist/components/VIcon/VIcon.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VIcon/iconProps.d.ts +4 -4
- 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 +23 -20
- package/dist/components/VIcon/resolver.js.map +1 -1
- package/dist/components/VIcon/types.d.ts +4 -4
- package/dist/components/VIconButton/VIconButton.d.ts +4 -4
- package/dist/components/VIconButton/VIconButton.js.map +1 -1
- package/dist/components/VIconButton/VIconButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VInput/VInput.d.ts +16 -8
- package/dist/components/VInput/VInput.js.map +1 -1
- package/dist/components/VInput/VInput.vue_vue_type_script_setup_true_lang.js +22 -16
- package/dist/components/VInput/VInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VInput/VInputGroup.css +1 -1
- package/dist/components/VInput/VInputGroup.js.map +1 -1
- package/dist/components/VInput/VInputGroup.vue_vue_type_script_setup_true_lang.js +43 -28
- package/dist/components/VInput/VInputGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VInputOTP/VInputOTP.css +1 -1
- package/dist/components/VInputOTP/VInputOTP.d.ts +3 -3
- package/dist/components/VInputOTP/VInputOTP.js.map +1 -1
- package/dist/components/VInputOTP/VInputOTP.vue_vue_type_script_setup_true_lang.js +152 -85
- package/dist/components/VInputOTP/VInputOTP.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VMenu/VMenu.d.ts +4 -4
- package/dist/components/VMenu/VMenu.js.map +1 -1
- 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.js.map +1 -1
- package/dist/components/VMenu/VMenuGroup.vue_vue_type_script_setup_true_lang.js +18 -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 +6 -6
- package/dist/components/VMenu/VMenuItem.js.map +1 -1
- package/dist/components/VMenu/VMenuItem.vue_vue_type_script_setup_true_lang.js +83 -69
- package/dist/components/VMenu/VMenuItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VMenu/VMenuPanel.css +1 -1
- package/dist/components/VMenu/VMenuPanel.d.ts +2 -2
- package/dist/components/VMenu/VMenuPanel.js.map +1 -1
- package/dist/components/VMenu/VMenuPanel.vue_vue_type_script_setup_true_lang.js +56 -55
- package/dist/components/VMenu/VMenuPanel.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VMenu/context.d.ts +2 -2
- package/dist/components/VMenu/context.js.map +1 -1
- package/dist/components/VPagination/VPagination.css +1 -1
- package/dist/components/VPagination/VPagination.d.ts +31 -9
- package/dist/components/VPagination/VPagination.js.map +1 -1
- package/dist/components/VPagination/VPagination.vue_vue_type_script_setup_true_lang.js +82 -52
- 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 +1 -1
- package/dist/components/VPopover/VPopover.js.map +1 -1
- 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 +12 -7
- package/dist/components/VProgressCircular/VProgressCircular.js.map +1 -1
- 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 +15 -10
- package/dist/components/VProgressLinear/VProgressLinear.js.map +1 -1
- 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.js.map +1 -1
- package/dist/components/VRadio/VRadio.vue_vue_type_script_setup_true_lang.js +3 -3
- package/dist/components/VRadio/VRadio.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSeparator/VSeparator.d.ts +1 -1
- 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.d.ts +2 -2
- package/dist/components/VSideNavigation/VSideNavigation.js.map +1 -1
- package/dist/components/VSideNavigation/VSideNavigation.vue_vue_type_script_setup_true_lang.js +1 -1
- 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.js.map +1 -1
- package/dist/components/VSideNavigation/VSideNavigationGroup.vue_vue_type_script_setup_true_lang.js +1 -1
- 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 +12 -13
- package/dist/components/VSideNavigation/VSideNavigationItem.js.map +1 -1
- package/dist/components/VSideNavigation/VSideNavigationItem.vue_vue_type_script_setup_true_lang.js +87 -68
- package/dist/components/VSideNavigation/VSideNavigationItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSkeletonLoader/VSkeletonLoader.css +1 -1
- package/dist/components/VSkeletonLoader/VSkeletonLoader.d.ts +10 -7
- package/dist/components/VSkeletonLoader/VSkeletonLoader.js.map +1 -1
- package/dist/components/VSkeletonLoader/VSkeletonLoader.vue_vue_type_script_setup_true_lang.js +5 -5
- 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 +21 -7
- package/dist/components/VSlider/VSlider.js.map +1 -1
- package/dist/components/VSlider/VSlider.vue_vue_type_script_setup_true_lang.js +159 -140
- 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 +4 -4
- package/dist/components/VSnackbar/VSnackbar.js.map +1 -1
- package/dist/components/VSnackbar/VSnackbar.vue_vue_type_script_setup_true_lang.js +85 -59
- package/dist/components/VSnackbar/VSnackbar.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSnackbar/state.d.ts +7 -7
- package/dist/components/VSnackbar/state.js +13 -11
- package/dist/components/VSnackbar/state.js.map +1 -1
- package/dist/components/VSpinner/VSpinner.css +1 -1
- package/dist/components/VSpinner/VSpinner.js.map +1 -1
- 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 +1 -1
- package/dist/components/VSwitch/VSwitch.js.map +1 -1
- package/dist/components/VSwitch/VSwitch.vue_vue_type_script_setup_true_lang.js +4 -4
- 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 +4 -0
- package/dist/components/VTabs/VTab.js.map +1 -1
- package/dist/components/VTabs/VTab.vue_vue_type_script_setup_true_lang.js +9 -8
- package/dist/components/VTabs/VTab.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 +17 -7
- package/dist/components/VTabs/VTabs.js.map +1 -1
- package/dist/components/VTabs/VTabs.vue_vue_type_script_setup_true_lang.js +84 -77
- package/dist/components/VTabs/VTabs.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTextarea/VTextarea.d.ts +8 -8
- package/dist/components/VTextarea/VTextarea.js.map +1 -1
- package/dist/components/VTextarea/VTextarea.vue_vue_type_script_setup_true_lang.js +71 -69
- 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 +21 -12
- package/dist/components/VTimeInput/VTimeInput.js.map +1 -1
- package/dist/components/VTimeInput/VTimeInput.vue_vue_type_script_setup_true_lang.js +230 -206
- package/dist/components/VTimeInput/VTimeInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTimeInput/search.d.ts +17 -2
- package/dist/components/VTimeInput/search.js +19 -9
- package/dist/components/VTimeInput/search.js.map +1 -1
- package/dist/components/VTimePicker/VTimePicker.css +1 -1
- package/dist/components/VTimePicker/VTimePicker.d.ts +8 -7
- package/dist/components/VTimePicker/VTimePicker.js.map +1 -1
- package/dist/components/VTimePicker/VTimePicker.vue_vue_type_script_setup_true_lang.js +128 -106
- package/dist/components/VTimePicker/VTimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTimePicker/limits.d.ts +11 -4
- package/dist/components/VTimePicker/limits.js +3 -2
- package/dist/components/VTimePicker/limits.js.map +1 -1
- package/dist/components/VToast/VToast.css +1 -1
- package/dist/components/VToast/VToast.js.map +1 -1
- package/dist/components/VToast/VToast.vue_vue_type_script_setup_true_lang.js +33 -37
- package/dist/components/VToast/VToast.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VToast/VToaster.js.map +1 -1
- package/dist/components/VToast/VToaster.vue_vue_type_script_setup_true_lang.js +91 -61
- package/dist/components/VToast/VToaster.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VToast/state.d.ts +8 -6
- package/dist/components/VToast/state.js +15 -13
- package/dist/components/VToast/state.js.map +1 -1
- package/dist/components/VToggle/VToggle.css +1 -1
- package/dist/components/VToggle/VToggle.d.ts +9 -4
- package/dist/components/VToggle/VToggle.js.map +1 -1
- package/dist/components/VToggle/VToggle.vue_vue_type_script_setup_true_lang.js +2 -1
- package/dist/components/VToggle/VToggle.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VToggle/VToggleItem.d.ts +4 -0
- package/dist/components/VToggle/VToggleItem.js.map +1 -1
- package/dist/components/VToggle/VToggleItem.vue_vue_type_script_setup_true_lang.js +5 -5
- package/dist/components/VToggle/VToggleItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTooltip/VTooltip.css +1 -1
- package/dist/components/VTooltip/VTooltip.d.ts +17 -10
- package/dist/components/VTooltip/VTooltip.js.map +1 -1
- package/dist/components/VTooltip/VTooltip.vue_vue_type_script_setup_true_lang.js +46 -26
- package/dist/components/VTooltip/VTooltip.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTypography/VTypography.css +1 -1
- package/dist/components/VTypography/VTypography.d.ts +6 -4
- 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.js +1 -1
- package/dist/composables/useAriaLabel.js.map +1 -1
- package/dist/composables/useClearable.d.ts +2 -2
- package/dist/composables/useClearable.js.map +1 -1
- package/dist/composables/useDetailsOpen.d.ts +3 -3
- package/dist/composables/useDetailsOpen.js +14 -12
- package/dist/composables/useDetailsOpen.js.map +1 -1
- package/dist/composables/useFieldIds.d.ts +2 -1
- package/dist/composables/useFieldIds.js +6 -5
- package/dist/composables/useFieldIds.js.map +1 -1
- package/dist/composables/useFieldPanel.d.ts +2 -2
- package/dist/composables/useFieldPanel.js +47 -37
- package/dist/composables/useFieldPanel.js.map +1 -1
- package/dist/composables/useFileDrop.js +3 -3
- package/dist/composables/useFileDrop.js.map +1 -1
- package/dist/composables/useFileField.d.ts +1 -1
- package/dist/composables/useFileField.js +62 -41
- package/dist/composables/useFileField.js.map +1 -1
- package/dist/composables/useIconClickHandlers.d.ts +3 -3
- package/dist/composables/useIconClickHandlers.js +14 -13
- package/dist/composables/useIconClickHandlers.js.map +1 -1
- package/dist/composables/useInertLink.js +12 -10
- package/dist/composables/useInertLink.js.map +1 -1
- package/dist/composables/useLiveAnnouncer.d.ts +5 -0
- package/dist/composables/useLiveAnnouncer.js +23 -0
- package/dist/composables/useLiveAnnouncer.js.map +1 -0
- package/dist/composables/useMaskedField.d.ts +5 -5
- package/dist/composables/useMaskedField.js.map +1 -1
- package/dist/composables/usePopover.d.ts +3 -3
- package/dist/composables/usePopover.js +6 -4
- package/dist/composables/usePopover.js.map +1 -1
- package/dist/composables/useProgressValue.js +11 -2
- package/dist/composables/useProgressValue.js.map +1 -1
- package/dist/composables/useRootAttrs.d.ts +1 -1
- package/dist/composables/useRootAttrs.js.map +1 -1
- package/dist/composables/useSlotNodes.d.ts +18 -0
- package/dist/composables/useSlotNodes.js +13 -0
- package/dist/composables/useSlotNodes.js.map +1 -0
- package/dist/composables/useTextLimit.d.ts +2 -1
- package/dist/composables/useTextLimit.js +2 -2
- package/dist/composables/useTextLimit.js.map +1 -1
- package/dist/composables/useTimer.d.ts +5 -0
- package/dist/composables/useTimer.js +22 -11
- package/dist/composables/useTimer.js.map +1 -1
- package/dist/i18n/en.js +1 -1
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/fr.js +14 -14
- package/dist/i18n/fr.js.map +1 -1
- package/dist/i18n/state.d.ts +7 -7
- package/dist/i18n/state.js +37 -28
- package/dist/i18n/state.js.map +1 -1
- package/dist/i18n/types.d.ts +12 -12
- package/dist/icons.d.ts +2 -2
- package/dist/index.d.ts +12 -11
- package/dist/styles.css +1 -1
- package/dist/tokens/css.d.ts +1 -1
- package/dist/tokens/css.js.map +1 -1
- package/dist/tokens/index.d.ts +6 -0
- package/dist/tokens/semantic.d.ts +6 -0
- package/dist/tokens/semantic.js +66 -60
- package/dist/tokens/semantic.js.map +1 -1
- package/dist/tokens/themes/dark.js +3 -3
- package/dist/tokens/themes/dark.js.map +1 -1
- package/dist/tokens.json +130 -66
- package/dist/types.d.ts +1 -1
- package/dist/utils/arrowNav.d.ts +4 -1
- package/dist/utils/arrowNav.js +7 -7
- package/dist/utils/arrowNav.js.map +1 -1
- package/dist/utils/chip.d.ts +1 -1
- package/dist/utils/chip.js.map +1 -1
- package/dist/utils/clock.d.ts +113 -0
- package/dist/utils/clock.js +84 -0
- package/dist/utils/clock.js.map +1 -0
- package/dist/utils/css.d.ts +6 -4
- package/dist/utils/css.js +2 -2
- package/dist/utils/css.js.map +1 -1
- package/dist/utils/date.d.ts +7 -102
- package/dist/utils/date.js +33 -160
- package/dist/utils/date.js.map +1 -1
- package/dist/utils/direction.d.ts +1 -1
- package/dist/utils/direction.js.map +1 -1
- package/dist/utils/env.d.ts +12 -3
- package/dist/utils/env.js +6 -0
- package/dist/utils/env.js.map +1 -0
- package/dist/utils/file.d.ts +3 -3
- package/dist/utils/file.js +1 -1
- package/dist/utils/file.js.map +1 -1
- package/dist/utils/focus.d.ts +1 -1
- package/dist/utils/focus.js.map +1 -1
- package/dist/utils/hostWarns.d.ts +1 -1
- package/dist/utils/hostWarns.js.map +1 -1
- package/dist/utils/ids.d.ts +1 -1
- package/dist/utils/ids.js.map +1 -1
- package/dist/utils/matcher.d.ts +2 -2
- package/dist/utils/matcher.js.map +1 -1
- package/dist/utils/memo.d.ts +1 -1
- package/dist/utils/memo.js.map +1 -1
- package/dist/utils/text.d.ts +3 -3
- package/dist/utils/text.js.map +1 -1
- package/dist/utils/time.d.ts +2 -101
- package/dist/utils/time.js +22 -98
- package/dist/utils/time.js.map +1 -1
- package/dist/utils/vnode.d.ts +5 -3
- package/dist/utils/vnode.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { AvatarSize } from './VAvatar.js';
|
|
2
|
+
/** What the `#overflow` slot receives. */
|
|
3
|
+
export interface AvatarGroupOverflowSlotProps {
|
|
4
|
+
/** How many avatars are hidden beyond `max`. */
|
|
5
|
+
count: number;
|
|
6
|
+
}
|
|
2
7
|
interface AvatarGroupProps {
|
|
3
8
|
/**
|
|
4
9
|
* How many avatars to show before the remaining ones are summed up as a single
|
|
@@ -20,6 +25,11 @@ interface AvatarGroupProps {
|
|
|
20
25
|
* background, which is what makes the ring read as a gap between two avatars.
|
|
21
26
|
*/
|
|
22
27
|
ringColor?: string;
|
|
28
|
+
/**
|
|
29
|
+
* The accessible name of the group, e.g. "Project members". A row of faces does not say on
|
|
30
|
+
* its own who these people are. A consumer `aria-label` or `aria-labelledby` wins over it.
|
|
31
|
+
*/
|
|
32
|
+
label?: string;
|
|
23
33
|
}
|
|
24
34
|
type __VLS_Slots = {
|
|
25
35
|
/** The VAvatars to stack. */
|
|
@@ -28,11 +38,10 @@ type __VLS_Slots = {
|
|
|
28
38
|
* Replaces the "+X" disc that stands for the avatars beyond `max`. It receives
|
|
29
39
|
* `count`, the number of avatars being hidden.
|
|
30
40
|
*/
|
|
31
|
-
overflow?(props:
|
|
32
|
-
count: number;
|
|
33
|
-
}): unknown;
|
|
41
|
+
overflow?(props: AvatarGroupOverflowSlotProps): unknown;
|
|
34
42
|
};
|
|
35
43
|
declare const __VLS_base: import('vue').DefineComponent<AvatarGroupProps, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<AvatarGroupProps> & Readonly<{}>, {
|
|
44
|
+
label: string;
|
|
36
45
|
size: AvatarSize;
|
|
37
46
|
compact: boolean;
|
|
38
47
|
ringColor: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VAvatarGroup.js","names":[],"sources":["../../../src/components/VAvatar/VAvatarGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @ssr @core — the number of avatars is read from the slot's VNODES through\n// `
|
|
1
|
+
{"version":3,"file":"VAvatarGroup.js","names":[],"sources":["../../../src/components/VAvatar/VAvatarGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @ssr @core — the number of avatars is read from the slot's VNODES through\n// `useSlotNodes`, never from a registry the children would fill at mount: such a\n// registry is empty during the server render and full on the client, which is a\n// hydration mismatch.\n/**\n * Several VAvatars stacked into an overlapping row — a team, the participants in a\n * conversation. Each disc bites into the one before it and, coming later in the document, is\n * painted over it: the browser's paint order does the work, with no positioning code. A ring\n * in `--avatar-ring-color` keeps the overlapping edges distinct.\n *\n * Two things need JS. Counting the avatars given and keeping only the first few, so the rest\n * can be summed up as one \"+N\" disc, is expressible in neither HTML nor CSS — and the count\n * comes from the slot's VNODES, never a registry, which would render 0 on the server and N\n * in the browser. And the group's size and density reach the avatars through provide/inject.\n */\n\nimport { computed, provide } from 'vue'\nimport type { StyleValue } from 'vue'\n\nimport VAvatar from './VAvatar.vue'\nimport type { AvatarSize } from './VAvatar.vue'\nimport { AVATAR_DEFAULT_SIZE, avatarGroupKey } from './context'\n\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useSlotNodes } from '../../composables/useSlotNodes'\n\n/** What the `#overflow` slot receives. */\nexport interface AvatarGroupOverflowSlotProps {\n /** How many avatars are hidden beyond `max`. */\n count: number\n}\n\ninterface AvatarGroupProps {\n /**\n * How many avatars to show before the remaining ones are summed up as a single\n * \"+X\" disc. Left out, or set to 0, every avatar is shown.\n */\n max?: number\n /**\n * The size given to the avatars inside the group. An avatar that sets a `size`\n * of its own keeps it.\n */\n size?: AvatarSize\n /**\n * Applies the reduced density to every avatar inside. Unlike `size` it is cumulative: an\n * avatar cannot opt back out of a compact group.\n */\n compact?: boolean\n /**\n * The colour of the ring drawn around each disc. It defaults to the page\n * background, which is what makes the ring read as a gap between two avatars.\n */\n ringColor?: string\n /**\n * The accessible name of the group, e.g. \"Project members\". A row of faces does not say on\n * its own who these people are. A consumer `aria-label` or `aria-labelledby` wins over it.\n */\n label?: string\n}\n\nconst props = withDefaults(defineProps<AvatarGroupProps>(), {\n max: undefined,\n size: undefined,\n compact: false,\n ringColor: undefined,\n label: undefined,\n})\n\nconst ariaLabel = useAriaLabel(() => props.label)\n\ndefineSlots<{\n /** The VAvatars to stack. */\n default?(): unknown\n /**\n * Replaces the \"+X\" disc that stands for the avatars beyond `max`. It receives\n * `count`, the number of avatars being hidden.\n */\n overflow?(props: AvatarGroupOverflowSlotProps): unknown\n}>()\n\nprovide(avatarGroupKey, {\n get size() {\n return props.size\n },\n get compact() {\n return props.compact\n },\n})\n\nconst items = useSlotNodes()\n// `max: 0` means \"no limit\", as documented, and so does a negative one: `slice(0, -1)` would\n// drop the LAST avatar and sum it into a \"+1\" disc.\nconst visibleItems = computed(() =>\n props.max !== undefined && props.max > 0 ? items.value.slice(0, props.max) : items.value,\n)\nconst overflowCount = computed(() => items.value.length - visibleItems.value.length)\n\n// A functional component is the only way to render VNodes that have already been\n// captured: <component :is> expects a component definition, not a vnode.\nconst VisibleAvatars = () => visibleItems.value\n\nconst rootStyle = computed<StyleValue>(() =>\n props.ringColor !== undefined ? { '--avatar-ring-color': props.ringColor } : undefined,\n)\n\n// The group carries v-control so that --control-height is defined at ITS level,\n// which keeps the overlap computable even when a child is wrapped — a VTooltip, for\n// instance, inserts a <span> between the group and the VAvatar. An avatar given a\n// size of its own redefines --control-height on itself, so its own overlap follows\n// that size rather than the group's.\nconst resolvedGroupSize = computed<AvatarSize>(() => props.size ?? AVATAR_DEFAULT_SIZE)\n</script>\n\n<template>\n <div\n class=\"v-avatar-group v-control\"\n role=\"group\"\n :aria-label=\"ariaLabel\"\n :style=\"rootStyle\"\n :data-size=\"resolvedGroupSize\"\n :data-compact=\"compact ? '' : undefined\"\n >\n <component :is=\"VisibleAvatars\" />\n <slot v-if=\"overflowCount > 0\" name=\"overflow\" :count=\"overflowCount\">\n <VAvatar>+{{ overflowCount }}</VAvatar>\n </slot>\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n .v-avatar-group {\n /* The separation ring, declared here so that every child .v-avatar inherits it. */\n --avatar-ring-color: var(--vectis-color-surface);\n display: inline-flex;\n align-items: center;\n }\n\n /* The overlap itself: each disc bites into the previous one by a fraction of its\n own height, and the DOM order is what makes the following one paint over it.\n The selector deliberately targets the direct child whatever it is — a bare\n VAvatar as well as a VTooltip wrapper — which is why --control-height has to\n come from the group; an avatar carrying its own size overrides it on itself.\n The ratio is unitless so it scales with whichever height applies. */\n .v-avatar-group > * + * {\n margin-inline-start: calc(var(--control-height) * -0.3);\n }\n\n /* On hover, or as soon as something inside it takes focus, a disc rises above its\n neighbours so it is seen whole rather than clipped by the next one. */\n .v-avatar-group > *:hover,\n .v-avatar-group > *:focus-within {\n z-index: 1;\n }\n}\n</style>\n"],"mappings":""}
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import n from "./
|
|
4
|
-
import
|
|
1
|
+
import { useAriaLabel as e } from "../../composables/useAriaLabel.js";
|
|
2
|
+
import { useSlotNodes as t } from "../../composables/useSlotNodes.js";
|
|
3
|
+
import { avatarGroupKey as n } from "./context.js";
|
|
4
|
+
import r from "./VAvatar.js";
|
|
5
|
+
import { computed as i, createBlock as a, createCommentVNode as o, createElementBlock as s, createTextVNode as c, createVNode as l, defineComponent as u, normalizeStyle as d, openBlock as f, provide as p, renderSlot as m, resolveDynamicComponent as h, toDisplayString as g, unref as _, withCtx as v } from "vue";
|
|
5
6
|
//#region src/components/VAvatar/VAvatarGroup.vue?vue&type=script&setup=true&lang.ts
|
|
6
|
-
var
|
|
7
|
+
var y = [
|
|
8
|
+
"aria-label",
|
|
9
|
+
"data-size",
|
|
10
|
+
"data-compact"
|
|
11
|
+
], b = /*@__PURE__*/ u({
|
|
7
12
|
__name: "VAvatarGroup",
|
|
8
13
|
props: {
|
|
9
14
|
max: { default: void 0 },
|
|
@@ -12,32 +17,34 @@ var v = ["data-size", "data-compact"], y = /*@__PURE__*/ l({
|
|
|
12
17
|
type: Boolean,
|
|
13
18
|
default: !1
|
|
14
19
|
},
|
|
15
|
-
ringColor: { default: void 0 }
|
|
20
|
+
ringColor: { default: void 0 },
|
|
21
|
+
label: { default: void 0 }
|
|
16
22
|
},
|
|
17
|
-
setup(
|
|
18
|
-
let
|
|
19
|
-
|
|
23
|
+
setup(u) {
|
|
24
|
+
let b = u, x = e(() => b.label);
|
|
25
|
+
p(n, {
|
|
20
26
|
get size() {
|
|
21
|
-
return
|
|
27
|
+
return b.size;
|
|
22
28
|
},
|
|
23
29
|
get compact() {
|
|
24
|
-
return
|
|
30
|
+
return b.compact;
|
|
25
31
|
}
|
|
26
32
|
});
|
|
27
|
-
let
|
|
28
|
-
return (e, t) => (
|
|
33
|
+
let S = t(), C = i(() => b.max !== void 0 && b.max > 0 ? S.value.slice(0, b.max) : S.value), w = i(() => S.value.length - C.value.length), T = () => C.value, E = i(() => b.ringColor === void 0 ? void 0 : { "--avatar-ring-color": b.ringColor }), D = i(() => b.size ?? "md");
|
|
34
|
+
return (e, t) => (f(), s("div", {
|
|
29
35
|
class: "v-avatar-group v-control",
|
|
30
36
|
role: "group",
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
"data-
|
|
34
|
-
|
|
35
|
-
|
|
37
|
+
"aria-label": _(x),
|
|
38
|
+
style: d(E.value),
|
|
39
|
+
"data-size": D.value,
|
|
40
|
+
"data-compact": u.compact ? "" : void 0
|
|
41
|
+
}, [(f(), a(h(T))), w.value > 0 ? m(e.$slots, "overflow", { count: w.value }, () => [l(r, null, {
|
|
42
|
+
default: v(() => [c("+" + g(w.value), 1)]),
|
|
36
43
|
_: 1
|
|
37
|
-
})], void 0, 0) :
|
|
44
|
+
})], void 0, 0) : o("", !0)], 12, y));
|
|
38
45
|
}
|
|
39
46
|
});
|
|
40
47
|
//#endregion
|
|
41
|
-
export {
|
|
48
|
+
export { b as default };
|
|
42
49
|
|
|
43
50
|
//# sourceMappingURL=VAvatarGroup.vue_vue_type_script_setup_true_lang.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VAvatarGroup.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/VAvatar/VAvatarGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @ssr @core — the number of avatars is read from the slot's VNODES through\n// `
|
|
1
|
+
{"version":3,"file":"VAvatarGroup.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/VAvatar/VAvatarGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @ssr @core — the number of avatars is read from the slot's VNODES through\n// `useSlotNodes`, never from a registry the children would fill at mount: such a\n// registry is empty during the server render and full on the client, which is a\n// hydration mismatch.\n/**\n * Several VAvatars stacked into an overlapping row — a team, the participants in a\n * conversation. Each disc bites into the one before it and, coming later in the document, is\n * painted over it: the browser's paint order does the work, with no positioning code. A ring\n * in `--avatar-ring-color` keeps the overlapping edges distinct.\n *\n * Two things need JS. Counting the avatars given and keeping only the first few, so the rest\n * can be summed up as one \"+N\" disc, is expressible in neither HTML nor CSS — and the count\n * comes from the slot's VNODES, never a registry, which would render 0 on the server and N\n * in the browser. And the group's size and density reach the avatars through provide/inject.\n */\n\nimport { computed, provide } from 'vue'\nimport type { StyleValue } from 'vue'\n\nimport VAvatar from './VAvatar.vue'\nimport type { AvatarSize } from './VAvatar.vue'\nimport { AVATAR_DEFAULT_SIZE, avatarGroupKey } from './context'\n\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useSlotNodes } from '../../composables/useSlotNodes'\n\n/** What the `#overflow` slot receives. */\nexport interface AvatarGroupOverflowSlotProps {\n /** How many avatars are hidden beyond `max`. */\n count: number\n}\n\ninterface AvatarGroupProps {\n /**\n * How many avatars to show before the remaining ones are summed up as a single\n * \"+X\" disc. Left out, or set to 0, every avatar is shown.\n */\n max?: number\n /**\n * The size given to the avatars inside the group. An avatar that sets a `size`\n * of its own keeps it.\n */\n size?: AvatarSize\n /**\n * Applies the reduced density to every avatar inside. Unlike `size` it is cumulative: an\n * avatar cannot opt back out of a compact group.\n */\n compact?: boolean\n /**\n * The colour of the ring drawn around each disc. It defaults to the page\n * background, which is what makes the ring read as a gap between two avatars.\n */\n ringColor?: string\n /**\n * The accessible name of the group, e.g. \"Project members\". A row of faces does not say on\n * its own who these people are. A consumer `aria-label` or `aria-labelledby` wins over it.\n */\n label?: string\n}\n\nconst props = withDefaults(defineProps<AvatarGroupProps>(), {\n max: undefined,\n size: undefined,\n compact: false,\n ringColor: undefined,\n label: undefined,\n})\n\nconst ariaLabel = useAriaLabel(() => props.label)\n\ndefineSlots<{\n /** The VAvatars to stack. */\n default?(): unknown\n /**\n * Replaces the \"+X\" disc that stands for the avatars beyond `max`. It receives\n * `count`, the number of avatars being hidden.\n */\n overflow?(props: AvatarGroupOverflowSlotProps): unknown\n}>()\n\nprovide(avatarGroupKey, {\n get size() {\n return props.size\n },\n get compact() {\n return props.compact\n },\n})\n\nconst items = useSlotNodes()\n// `max: 0` means \"no limit\", as documented, and so does a negative one: `slice(0, -1)` would\n// drop the LAST avatar and sum it into a \"+1\" disc.\nconst visibleItems = computed(() =>\n props.max !== undefined && props.max > 0 ? items.value.slice(0, props.max) : items.value,\n)\nconst overflowCount = computed(() => items.value.length - visibleItems.value.length)\n\n// A functional component is the only way to render VNodes that have already been\n// captured: <component :is> expects a component definition, not a vnode.\nconst VisibleAvatars = () => visibleItems.value\n\nconst rootStyle = computed<StyleValue>(() =>\n props.ringColor !== undefined ? { '--avatar-ring-color': props.ringColor } : undefined,\n)\n\n// The group carries v-control so that --control-height is defined at ITS level,\n// which keeps the overlap computable even when a child is wrapped — a VTooltip, for\n// instance, inserts a <span> between the group and the VAvatar. An avatar given a\n// size of its own redefines --control-height on itself, so its own overlap follows\n// that size rather than the group's.\nconst resolvedGroupSize = computed<AvatarSize>(() => props.size ?? AVATAR_DEFAULT_SIZE)\n</script>\n\n<template>\n <div\n class=\"v-avatar-group v-control\"\n role=\"group\"\n :aria-label=\"ariaLabel\"\n :style=\"rootStyle\"\n :data-size=\"resolvedGroupSize\"\n :data-compact=\"compact ? '' : undefined\"\n >\n <component :is=\"VisibleAvatars\" />\n <slot v-if=\"overflowCount > 0\" name=\"overflow\" :count=\"overflowCount\">\n <VAvatar>+{{ overflowCount }}</VAvatar>\n </slot>\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n .v-avatar-group {\n /* The separation ring, declared here so that every child .v-avatar inherits it. */\n --avatar-ring-color: var(--vectis-color-surface);\n display: inline-flex;\n align-items: center;\n }\n\n /* The overlap itself: each disc bites into the previous one by a fraction of its\n own height, and the DOM order is what makes the following one paint over it.\n The selector deliberately targets the direct child whatever it is — a bare\n VAvatar as well as a VTooltip wrapper — which is why --control-height has to\n come from the group; an avatar carrying its own size overrides it on itself.\n The ratio is unitless so it scales with whichever height applies. */\n .v-avatar-group > * + * {\n margin-inline-start: calc(var(--control-height) * -0.3);\n }\n\n /* On hover, or as soon as something inside it takes focus, a disc rises above its\n neighbours so it is seen whole rather than clipped by the next one. */\n .v-avatar-group > *:hover,\n .v-avatar-group > *:focus-within {\n z-index: 1;\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;EA6DA,IAAM,IAAQ,GAQR,IAAY,QAAmB,EAAM,KAAK;EAYhD,EAAQ,GAAgB;GACtB,IAAI,OAAO;IACT,OAAO,EAAM;GACf;GACA,IAAI,UAAU;IACZ,OAAO,EAAM;GACf;EACF,CAAC;EAED,IAAM,IAAQ,EAAa,GAGrB,IAAe,QACnB,EAAM,QAAQ,KAAA,KAAa,EAAM,MAAM,IAAI,EAAM,MAAM,MAAM,GAAG,EAAM,GAAG,IAAI,EAAM,KACrF,GACM,IAAgB,QAAe,EAAM,MAAM,SAAS,EAAa,MAAM,MAAM,GAI7E,UAAuB,EAAa,OAEpC,IAAY,QAChB,EAAM,cAAc,KAAA,IAAyD,KAAA,IAA7C,EAAE,uBAAuB,EAAM,UAAU,CAC3E,GAOM,IAAoB,QAA2B,EAAM,QAAA,IAA2B;yBAIpF,EAYM,OAAA;GAXJ,OAAM;GACN,MAAK;GACJ,cAAY,EAAA,CAAA;GACZ,OAAK,EAAE,EAAA,KAAS;GAChB,aAAW,EAAA;GACX,gBAAc,EAAA,UAAO,KAAQ,KAAA;YAE9B,EAAkC,EAAlB,CAAc,CAAA,IAClB,EAAA,QAAa,IAAzB,EAEO,EAAA,QAAA,YAAA,EAFyC,OAAO,EAAA,MAAa,SAE7D,CADL,EAAuC,GAAA,MAAA;oBAA7B,CAAA,EAAD,MAAC,EAAG,EAAA,KAAa,GAAA,CAAA,CAAA,CAAA"}
|
|
@@ -6,8 +6,8 @@ export interface AvatarGroupContext {
|
|
|
6
6
|
}
|
|
7
7
|
/**
|
|
8
8
|
* The size of an avatar that neither names one nor sits in a group that does. VAvatar and
|
|
9
|
-
* VAvatarGroup both read it
|
|
10
|
-
* overlap
|
|
9
|
+
* VAvatarGroup both read it: the group sets `--control-height` at its own level, for the
|
|
10
|
+
* overlap, so the two cannot disagree on what an unsized avatar measures.
|
|
11
11
|
*/
|
|
12
12
|
export declare const AVATAR_DEFAULT_SIZE: AvatarSize;
|
|
13
13
|
export declare const avatarGroupKey: InjectionKey<AvatarGroupContext>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","names":[],"sources":["../../../src/components/VAvatar/context.ts"],"sourcesContent":["/**\n * This is what a VAvatarGroup passes down to the VAvatars it contains. Sizing a\n * row of avatars is a decision that belongs to the row, so the group announces\n * its size and its compact density once and every avatar inside picks them up,\n * instead of the writer repeating the same two props on each one.\n *\n * The two members are arbitrated differently, and on purpose:\n *\n * - `size` is a fallback: an avatar that was given an explicit size keeps it, one that was\n * not takes the group's, and one that has neither falls back to\n * `AVATAR_DEFAULT_SIZE` (`props.size ?? group.size ?? AVATAR_DEFAULT_SIZE`).\n * - `compact` is CUMULATIVE, the VButtonGroup `disabled` model (`props.compact ||\n * group.compact`): a compact group has no avatar that can opt back out, and one avatar\n * set compact in a regular group is compact alone. A boolean prop defaulting to `false`\n * has no way to say \"no opinion\", so a fallback could never let the avatar refuse.\n */\n\nimport type { InjectionKey } from 'vue'\n\nimport type { AvatarSize } from './VAvatar.vue'\n\nexport interface AvatarGroupContext {\n size?: AvatarSize\n compact?: boolean\n}\n\n/**\n * The size of an avatar that neither names one nor sits in a group that does. VAvatar and\n * VAvatarGroup both read it
|
|
1
|
+
{"version":3,"file":"context.js","names":[],"sources":["../../../src/components/VAvatar/context.ts"],"sourcesContent":["/**\n * This is what a VAvatarGroup passes down to the VAvatars it contains. Sizing a\n * row of avatars is a decision that belongs to the row, so the group announces\n * its size and its compact density once and every avatar inside picks them up,\n * instead of the writer repeating the same two props on each one.\n *\n * The two members are arbitrated differently, and on purpose:\n *\n * - `size` is a fallback: an avatar that was given an explicit size keeps it, one that was\n * not takes the group's, and one that has neither falls back to\n * `AVATAR_DEFAULT_SIZE` (`props.size ?? group.size ?? AVATAR_DEFAULT_SIZE`).\n * - `compact` is CUMULATIVE, the VButtonGroup `disabled` model (`props.compact ||\n * group.compact`): a compact group has no avatar that can opt back out, and one avatar\n * set compact in a regular group is compact alone. A boolean prop defaulting to `false`\n * has no way to say \"no opinion\", so a fallback could never let the avatar refuse.\n */\n\nimport type { InjectionKey } from 'vue'\n\nimport type { AvatarSize } from './VAvatar.vue'\n\nexport interface AvatarGroupContext {\n size?: AvatarSize\n compact?: boolean\n}\n\n/**\n * The size of an avatar that neither names one nor sits in a group that does. VAvatar and\n * VAvatarGroup both read it: the group sets `--control-height` at its own level, for the\n * overlap, so the two cannot disagree on what an unsized avatar measures.\n */\nexport const AVATAR_DEFAULT_SIZE: AvatarSize = 'md'\n\nexport const avatarGroupKey: InjectionKey<AvatarGroupContext> = Symbol('v-avatar-group')\n"],"mappings":";AAiCA,IAAa,IAAmD,OAAO,gBAAgB"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
@layer vectis.reset, vectis.tokens, vectis.components, vectis.utilities;
|
|
2
|
-
@layer vectis.components{.v-badge-host{align-items:center;gap:var(--vectis-space-2);display:inline-flex;position:relative}.v-badge{--vectis-icon-size:var(--vectis-icon-size-sm);--vectis-icon-opsz:20;--badge-ring-color:var(--vectis-color-surface)
|
|
2
|
+
@layer vectis.components{.v-badge-host{align-items:center;gap:var(--vectis-space-2);display:inline-flex;position:relative}.v-badge{--vectis-icon-size:var(--vectis-icon-size-sm);--vectis-icon-opsz:20;--badge-ring-color:var(--vectis-color-surface);height:var(--vectis-control-size-badge-h);min-width:var(--vectis-control-size-badge-h);padding-inline:var(--vectis-space-1);border-radius:var(--vectis-radius-pill);font-family:var(--vectis-text-family);font-size:var(--vectis-text-caption-size);font-weight:var(--vectis-text-control-weight);line-height:var(--vectis-text-control-leading);justify-content:center;align-items:center;display:inline-flex}@supports (color:contrast-color(red)){.v-badge.v-variant[data-variant=solid]{color:contrast-color(var(--tone-bg-solid))}}.v-badge.v-variant[data-dot]{background:var(--tone-bg-solid)}.v-badge[data-icon-only]{padding:0}.v-badge[data-dot]{width:var(--vectis-control-size-badge-dot);height:var(--vectis-control-size-badge-dot);min-width:0;padding:0}.v-badge[data-bordered]{box-shadow:0 0 0 var(--vectis-control-size-badge-ring) var(--badge-ring-color)}.v-badge-host[data-overlay]>.v-badge{--badge-overlay-x:25%;--badge-overlay-y:-25%;translate:var(--badge-overlay-x) var(--badge-overlay-y);z-index:1;position:absolute;inset-block:0 auto;inset-inline-end:0}.v-badge-host[data-overlay][data-overlay-position=bottom]>.v-badge{--badge-overlay-y:25%;inset-block:auto 0}.v-badge-host[data-overlay]:dir(rtl)>.v-badge{--badge-overlay-x:-25%}@media (forced-colors:active){.v-badge{outline:var(--vectis-control-border-width) solid CanvasText;outline-offset:calc(-1 * var(--vectis-control-border-width))}.v-badge.v-variant[data-dot]{forced-color-adjust:none;background:canvastext}}}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { IconSource } from '../VIcon/types.js';
|
|
2
|
+
/** How strongly the badge is painted: the full colour, or a tint of it. */
|
|
2
3
|
export type BadgeVariant = 'solid' | 'soft';
|
|
4
|
+
/** What the badge means, in colour. */
|
|
3
5
|
export type BadgeTone = 'neutral' | 'accent' | 'danger' | 'success' | 'warning';
|
|
6
|
+
/** The corner an overlaid badge is pinned to. */
|
|
4
7
|
export type BadgeOverlayPosition = 'top' | 'bottom';
|
|
5
8
|
interface BadgeProps {
|
|
6
9
|
/**
|
|
@@ -36,7 +39,7 @@ interface BadgeProps {
|
|
|
36
39
|
*/
|
|
37
40
|
icon?: IconSource;
|
|
38
41
|
/**
|
|
39
|
-
* Reduces the badge to a 10px dot with no content
|
|
42
|
+
* Reduces the badge to a 10px dot with no content, the discreet way to signal
|
|
40
43
|
* that something is new without saying how much.
|
|
41
44
|
*/
|
|
42
45
|
dot?: boolean;
|
|
@@ -47,8 +50,8 @@ interface BadgeProps {
|
|
|
47
50
|
overlay?: boolean;
|
|
48
51
|
/**
|
|
49
52
|
* Which corner an `overlay` badge is pinned to: the top one by default, the
|
|
50
|
-
* bottom one for a marker that belongs at the foot of its target
|
|
51
|
-
* under an avatar
|
|
53
|
+
* bottom one for a marker that belongs at the foot of its target, such as a presence dot
|
|
54
|
+
* under an avatar. The horizontal side follows the reading
|
|
52
55
|
* direction and is not configurable. It does nothing without `overlay`.
|
|
53
56
|
*/
|
|
54
57
|
overlayPosition?: BadgeOverlayPosition;
|
|
@@ -69,7 +72,8 @@ interface BadgeProps {
|
|
|
69
72
|
type __VLS_Slots = {
|
|
70
73
|
/**
|
|
71
74
|
* The element the badge belongs to. Without it the badge stands on its own; with
|
|
72
|
-
* it, the badge is placed beside the element, or in its corner under `overlay
|
|
75
|
+
* it, the badge is placed beside the element, or in its corner under `overlay`, and is
|
|
76
|
+
* hidden from assistive technology: say the count in the element's own name.
|
|
73
77
|
*/
|
|
74
78
|
default?(): unknown;
|
|
75
79
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VBadge.js","names":[],"sources":["../../../src/components/VBadge/VBadge.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @core\n/**\n * A small pill carrying one piece of information at a glance: a count of unread\n * items, or a single icon. It is never interactive — there is nothing to click and\n * nothing to focus — and it either stands on its own, sits next to an element, or\n * is pinned to one of that element's corners.\n *\n * It is made of HTML and CSS alone. The only JavaScript decides what to render:\n * whether a target element was given at all, capping the counter at \"99+\", and\n * handing the two colours a consumer may choose to the stylesheet as\n * `--custom-color` and `--badge-ring-color`.\n */\nimport { computed, h } from 'vue'\nimport type { FunctionalComponent } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport type { IconSource } from '../VIcon/types'\n\nimport { customColorStyle } from '../../utils/css'\n\nexport type BadgeVariant = 'solid' | 'soft'\nexport type BadgeTone = 'neutral' | 'accent' | 'danger' | 'success' | 'warning'\nexport type BadgeOverlayPosition = 'top' | 'bottom'\n\ninterface BadgeProps {\n /**\n * How strongly the badge is painted: filled with the full colour (`solid`, the\n * default), or a tinted background with the text in the colour (`soft`), for a\n * count that should not draw the eye. A `dot` is always solid: with no content to\n * tint, a soft dot would be a pale disc barely distinguishable from the page.\n */\n variant?: BadgeVariant\n /**\n * The meaning the badge carries, expressed as a colour. A solid badge is filled\n * with it and its text adapts to stay readable; a soft one is tinted with it and\n * writes its text in it.\n */\n tone?: BadgeTone\n /**\n * A colour of your own (hex, CSS name or `oklch()`), which replaces the tone. On a\n * solid badge, browsers that support `contrast-color()` turn the text black or\n * white by themselves; everywhere else it falls back to white, so with a light\n * colour the contrast is yours to check. A soft badge derives its background and\n * text from that colour mixed with the theme's surface and text.\n */\n color?: string\n /**\n * The number to display. Anything above 99 is shown as \"99+\", so that a busy\n * counter cannot stretch the pill indefinitely.\n */\n count?: number\n /**\n * A single icon shown instead of a number: an icon name, or an explicit render\n * (the VIcon contract). It takes precedence over `count`, and is ignored when the\n * badge is a `dot`.\n */\n icon?: IconSource\n /**\n * Reduces the badge to a 10px dot with no content — the discreet way to signal\n * that something is new without saying how much.\n */\n dot?: boolean\n /**\n * Pins the badge to a corner of the target element instead of placing it beside\n * it. It does nothing when the badge has no target.\n */\n overlay?: boolean\n /**\n * Which corner an `overlay` badge is pinned to: the top one by default, the\n * bottom one for a marker that belongs at the foot of its target — a presence dot\n * under an avatar, for instance. The horizontal side follows the reading\n * direction and is not configurable. It does nothing without `overlay`.\n */\n overlayPosition?: BadgeOverlayPosition\n /**\n * Draws a 2px ring around the badge, in the colour of the surface behind it,\n * which detaches it from a busy target such as a picture. That colour defaults to\n * the page background and is named through `ringColor` on any other surface.\n */\n bordered?: boolean\n /**\n * The colour of the ring drawn by `bordered`. It defaults to the page background,\n * which is what makes the ring read as a gap around the badge; on another surface\n * (a card, a coloured banner), pass that surface's colour. It does nothing without\n * `bordered`.\n */\n ringColor?: string\n}\n\nconst props = withDefaults(defineProps<BadgeProps>(), {\n variant: 'solid',\n tone: 'accent',\n color: undefined,\n count: undefined,\n icon: undefined,\n overlayPosition: 'top',\n ringColor: undefined,\n // Written out although Vue casts an absent boolean to `false` on its own: left out,\n // `vue-component-meta` reports no default at all and the docs table's cell goes blank.\n dot: false,\n overlay: false,\n bordered: false,\n})\n\nconst slots = defineSlots<{\n /**\n * The element the badge belongs to. Without it the badge stands on its own; with\n * it, the badge is placed beside the element, or in its corner under `overlay`.\n */\n default?(): 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 hasTarget() {\n return slots.default !== undefined\n}\n\n/** The counter as it is actually displayed: anything past 99 becomes \"99+\". */\nconst displayCount = computed(() =>\n props.count !== undefined && props.count > 99 ? '99+' : props.count,\n)\n\n/*\n * The pill itself, written once. The template has two roots — one wrapping a target, one\n * standing alone — and both render the same badge; a functional component is the one way\n * to put the same markup in two places of a template without writing it twice.\n */\nconst Pill: FunctionalComponent = () =>\n h(\n 'span',\n {\n class: 'v-badge v-tone',\n 'data-variant': props.variant,\n 'data-tone': props.tone,\n 'data-custom': props.color !== undefined ? '' : undefined,\n 'data-dot': props.dot ? '' : undefined,\n 'data-icon-only': !props.dot && props.icon ? '' : undefined,\n 'data-bordered': props.bordered ? '' : undefined,\n style: [\n customColorStyle(props.color),\n props.ringColor !== undefined ? { '--badge-ring-color': props.ringColor } : undefined,\n ],\n },\n props.dot\n ? undefined\n : props.icon\n ? [h(VIcon, iconProps(props.icon))]\n : displayCount.value === undefined\n ? undefined\n : String(displayCount.value),\n )\n// TRAP — the empty list is not decoration. A functional component that declares no props lets\n// only `class`, `style` and listeners fall through, so a standalone badge, whose root this is,\n// would silently drop every other attribute a consumer set on VBadge (an `id`, a `data-*`).\nPill.props = []\n</script>\n\n<template>\n <span\n v-if=\"hasTarget()\"\n class=\"v-badge-host\"\n :data-overlay=\"overlay ? '' : undefined\"\n :data-overlay-position=\"overlayPosition\"\n >\n <slot />\n <Pill />\n </span>\n <Pill v-else />\n</template>\n\n<style>\n@layer vectis.components {\n .v-badge-host {\n position: relative;\n display: inline-flex;\n align-items: center;\n gap: var(--vectis-space-2); /* the space between the target and the badge, in inline mode */\n }\n\n .v-badge {\n --vectis-icon-size: var(--vectis-icon-size-sm);\n --vectis-icon-opsz: 20;\n /* The colour of the `bordered` ring: a bet on the page background, the only one a\n component can make since CSS cannot read what its parent paints. The `ringColor`\n prop overrides it inline for a badge sitting on anything else. */\n --badge-ring-color: var(--vectis-color-surface);\n /* The pill is the tone's solid pair, read from the shared table (`.v-tone`, set in the\n template). Its neutral is the text/surface inversion, which is what lets the\n fallback text and contrast-color() agree in both themes. */\n --badge-bg: var(--tone-bg-solid);\n --badge-text-fallback: var(--tone-text-solid);\n\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: var(--vectis-control-size-badge-h);\n /* A minimum width equal to the height, with a small padding on top, is what\n makes a one- or two-digit counter come out round rather than oval. */\n min-width: var(--vectis-control-size-badge-h);\n padding-inline: var(--vectis-space-1);\n border-radius: var(--vectis-radius-pill);\n background: var(--badge-bg);\n font-family: var(--vectis-text-family);\n font-size: var(--vectis-text-caption-size);\n font-weight: var(--vectis-text-control-weight);\n line-height: var(--vectis-text-control-leading);\n color: var(--badge-text-fallback);\n }\n\n @supports (color: contrast-color(red)) {\n .v-badge {\n color: contrast-color(var(--badge-bg));\n }\n }\n\n /* A custom colour replaces the tone: at (0,2,0) it beats the base rule's mapping\n whatever the order the two are written in. */\n .v-badge[data-custom] {\n --badge-bg: var(--custom-color);\n --badge-text-fallback: var(--vectis-color-text-on-accent);\n }\n\n /* The soft pair of the same table. The text is the tone's own colour rather than\n contrast-color(): the black or white that function picks reads on a pale tint, but\n says nothing of the tone. At (0,3,0) it beats the `@supports` rule above whatever\n the order. A dot is left out: with no content, a soft dot is a pale disc on the\n page, which a presence marker cannot afford. */\n .v-badge[data-variant='soft']:not([data-dot]) {\n --badge-bg: var(--tone-bg-soft);\n\n color: var(--tone-text-tinted);\n }\n\n /* A custom colour's soft pair, derived as VChip derives its own, so the same value\n gives a soft chip and a soft badge the same tint in both themes. */\n .v-badge[data-variant='soft'][data-custom]:not([data-dot]) {\n --badge-bg: color-mix(in oklab, var(--custom-color), var(--vectis-color-surface) 85%);\n\n color: color-mix(in oklab, var(--custom-color), var(--vectis-color-text) 30%);\n }\n\n .v-badge[data-icon-only] {\n padding: 0;\n }\n\n .v-badge[data-dot] {\n width: var(--vectis-control-size-badge-dot);\n height: var(--vectis-control-size-badge-dot);\n min-width: 0;\n padding: 0;\n }\n\n .v-badge[data-bordered] {\n box-shadow: 0 0 0 var(--vectis-control-size-badge-ring) var(--badge-ring-color);\n }\n\n /* The tuck-in offset is a ratio of the badge's own size, so it stays proportionate\n across the pill, the dot and the icon. Each half of it is held in its own\n variable: the corner and the reading direction each flip ONE axis, and writing\n the whole `translate` again in each branch would make the two multiply — four\n rules to keep in step by hand for two independent decisions. */\n .v-badge-host[data-overlay] > .v-badge {\n --badge-overlay-x: 25%;\n --badge-overlay-y: -25%;\n\n position: absolute;\n inset-block: 0 auto;\n inset-inline-end: 0;\n translate: var(--badge-overlay-x) var(--badge-overlay-y);\n /* TRAP — an overlaid badge deliberately leaves its target's box, so it lands on\n whatever sits beside it, and the host opens no stacking context of its own\n (`position: relative` with `z-index: auto`). Left at `auto` the badge is painted\n with the other positioned boxes in TREE ORDER, which means anything positioned\n after it covers it: inside a VButtonGroup, where every segment is positioned, the\n badge on one segment disappears under the borders of the next. The lift takes it\n past that step, and no further: the segment it leans into comes later in tree\n order, so that segment's focus ring, raised to this same level, is still drawn\n over the badge rather than under it. */\n z-index: 1;\n }\n\n .v-badge-host[data-overlay][data-overlay-position='bottom'] > .v-badge {\n --badge-overlay-y: 25%;\n\n inset-block: auto 0;\n }\n\n /* In a right-to-left direction the logical corner moves to the left, so the\n horizontal half of the translation has to flip with it — `translate` is a\n physical property and knows nothing about direction. */\n .v-badge-host[data-overlay]:dir(rtl) > .v-badge {\n --badge-overlay-x: -25%;\n }\n}\n</style>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"VBadge.js","names":[],"sources":["../../../src/components/VBadge/VBadge.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @core\n/**\n * A small pill carrying one piece of information at a glance: a count of unread\n * items, or a single icon. It is never interactive — there is nothing to click and\n * nothing to focus — and it either stands on its own, sits next to an element, or\n * is pinned to one of that element's corners.\n *\n * It is made of HTML and CSS alone. The only JavaScript decides what to render:\n * whether a target element was given at all, capping the counter at \"99+\", and\n * handing the two colours a consumer may choose to the stylesheet as\n * `--custom-color` and `--badge-ring-color`.\n *\n * Beside a target the pill is `aria-hidden`: read on its own, \"3\" means nothing, and the\n * target is what a reader reaches, so the count belongs in the target's own name\n * (\"Notifications, 3 unread\") where it would otherwise be announced twice.\n */\nimport { computed, h } from 'vue'\nimport type { FunctionalComponent } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport type { IconSource } from '../VIcon/types'\n\nimport { customColorStyle } from '../../utils/css'\n\n/** How strongly the badge is painted: the full colour, or a tint of it. */\nexport type BadgeVariant = 'solid' | 'soft'\n/** What the badge means, in colour. */\nexport type BadgeTone = 'neutral' | 'accent' | 'danger' | 'success' | 'warning'\n/** The corner an overlaid badge is pinned to. */\nexport type BadgeOverlayPosition = 'top' | 'bottom'\n\ninterface BadgeProps {\n /**\n * How strongly the badge is painted: filled with the full colour (`solid`, the\n * default), or a tinted background with the text in the colour (`soft`), for a\n * count that should not draw the eye. A `dot` is always solid: with no content to\n * tint, a soft dot would be a pale disc barely distinguishable from the page.\n */\n variant?: BadgeVariant\n /**\n * The meaning the badge carries, expressed as a colour. A solid badge is filled\n * with it and its text adapts to stay readable; a soft one is tinted with it and\n * writes its text in it.\n */\n tone?: BadgeTone\n /**\n * A colour of your own (hex, CSS name or `oklch()`), which replaces the tone. On a\n * solid badge, browsers that support `contrast-color()` turn the text black or\n * white by themselves; everywhere else it falls back to white, so with a light\n * colour the contrast is yours to check. A soft badge derives its background and\n * text from that colour mixed with the theme's surface and text.\n */\n color?: string\n /**\n * The number to display. Anything above 99 is shown as \"99+\", so that a busy\n * counter cannot stretch the pill indefinitely.\n */\n count?: number\n /**\n * A single icon shown instead of a number: an icon name, or an explicit render\n * (the VIcon contract). It takes precedence over `count`, and is ignored when the\n * badge is a `dot`.\n */\n icon?: IconSource\n /**\n * Reduces the badge to a 10px dot with no content, the discreet way to signal\n * that something is new without saying how much.\n */\n dot?: boolean\n /**\n * Pins the badge to a corner of the target element instead of placing it beside\n * it. It does nothing when the badge has no target.\n */\n overlay?: boolean\n /**\n * Which corner an `overlay` badge is pinned to: the top one by default, the\n * bottom one for a marker that belongs at the foot of its target, such as a presence dot\n * under an avatar. The horizontal side follows the reading\n * direction and is not configurable. It does nothing without `overlay`.\n */\n overlayPosition?: BadgeOverlayPosition\n /**\n * Draws a 2px ring around the badge, in the colour of the surface behind it,\n * which detaches it from a busy target such as a picture. That colour defaults to\n * the page background and is named through `ringColor` on any other surface.\n */\n bordered?: boolean\n /**\n * The colour of the ring drawn by `bordered`. It defaults to the page background,\n * which is what makes the ring read as a gap around the badge; on another surface\n * (a card, a coloured banner), pass that surface's colour. It does nothing without\n * `bordered`.\n */\n ringColor?: string\n}\n\nconst props = withDefaults(defineProps<BadgeProps>(), {\n variant: 'solid',\n tone: 'accent',\n color: undefined,\n count: undefined,\n icon: undefined,\n overlayPosition: 'top',\n ringColor: undefined,\n // Written out although Vue casts an absent boolean to `false` on its own: left out,\n // `vue-component-meta` reports no default at all and the docs table's cell goes blank.\n dot: false,\n overlay: false,\n bordered: false,\n})\n\nconst slots = defineSlots<{\n /**\n * The element the badge belongs to. Without it the badge stands on its own; with\n * it, the badge is placed beside the element, or in its corner under `overlay`, and is\n * hidden from assistive technology: say the count in the element's own name.\n */\n default?(): 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 hasTarget() {\n return slots.default !== undefined\n}\n\n/**\n * The counter as it is actually displayed: a whole number, zero or more, and anything past 99\n * becomes \"99+\". A count that is not a number (a division by a total not yet known) draws\n * nothing rather than the word \"NaN\".\n */\nconst displayCount = computed(() => {\n const count = props.count\n if (count === undefined || !Number.isFinite(count)) return undefined\n return count > 99 ? '99+' : Math.max(0, Math.trunc(count))\n})\n\n/*\n * The pill itself, written once. The template has two roots — one wrapping a target, one\n * standing alone — and both render the same badge; a functional component is the one way\n * to put the same markup in two places of a template without writing it twice.\n */\nconst Pill: FunctionalComponent = () =>\n h(\n 'span',\n {\n class: 'v-badge v-tone v-variant',\n 'data-variant': props.variant,\n 'data-tone': props.tone,\n 'data-custom': props.color !== undefined ? '' : undefined,\n 'data-dot': props.dot ? '' : undefined,\n 'data-icon-only': !props.dot && props.icon ? '' : undefined,\n 'data-bordered': props.bordered ? '' : undefined,\n style: [\n customColorStyle(props.color),\n props.ringColor !== undefined ? { '--badge-ring-color': props.ringColor } : undefined,\n ],\n },\n props.dot\n ? undefined\n : props.icon\n ? [h(VIcon, iconProps(props.icon))]\n : displayCount.value === undefined\n ? undefined\n : String(displayCount.value),\n )\n// TRAP — the empty list is not decoration. A functional component that declares no props lets\n// only `class`, `style` and listeners fall through, so a standalone badge, whose root this is,\n// would silently drop every other attribute a consumer set on VBadge (an `id`, a `data-*`).\nPill.props = []\n</script>\n\n<template>\n <span\n v-if=\"hasTarget()\"\n class=\"v-badge-host\"\n :data-overlay=\"overlay ? '' : undefined\"\n :data-overlay-position=\"overlayPosition\"\n >\n <slot />\n <Pill aria-hidden=\"true\" />\n </span>\n <Pill v-else />\n</template>\n\n<style>\n@layer vectis.components {\n .v-badge-host {\n position: relative;\n display: inline-flex;\n align-items: center;\n gap: var(--vectis-space-2); /* the space between the target and the badge, in inline mode */\n }\n\n /* The pill is painted by the shared `.v-variant` rules (styles/variants.css) over the\n tone table (`.v-tone`), both set in the template: `solid` is the tone's full colour,\n `soft` its tint with the text in the tone's own colour. A custom colour is the table's\n `[data-custom]` row, in styles/tones.css. */\n .v-badge {\n --vectis-icon-size: var(--vectis-icon-size-sm);\n --vectis-icon-opsz: 20;\n /* The colour of the `bordered` ring: a bet on the page background, the only one a\n component can make since CSS cannot read what its parent paints. The `ringColor`\n prop overrides it inline for a badge sitting on anything else. */\n --badge-ring-color: var(--vectis-color-surface);\n\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: var(--vectis-control-size-badge-h);\n /* A minimum width equal to the height, with a small padding on top, is what\n makes a one- or two-digit counter come out round rather than oval. */\n min-width: var(--vectis-control-size-badge-h);\n padding-inline: var(--vectis-space-1);\n border-radius: var(--vectis-radius-pill);\n font-family: var(--vectis-text-family);\n font-size: var(--vectis-text-caption-size);\n font-weight: var(--vectis-text-control-weight);\n line-height: var(--vectis-text-control-leading);\n }\n\n /* On a solid pill the text picks black or white against whatever the fill ended up\n with, where the function exists; elsewhere it keeps the table's `--tone-text-solid`.\n TRAP — the class is compounded to (0,3,0): `.v-variant[data-variant='solid']` sets\n `color` at (0,2,0) from another sheet, and a tie would be settled by sheet order. The\n soft pill keeps the tone's own text colour, which says the tone where black or white\n would not. */\n @supports (color: contrast-color(red)) {\n .v-badge.v-variant[data-variant='solid'] {\n color: contrast-color(var(--tone-bg-solid));\n }\n }\n\n /* A dot is always solid: with no content, a soft dot is a pale disc on the page, which a\n presence marker cannot afford. (0,3,0), above the soft variant's background. */\n .v-badge.v-variant[data-dot] {\n background: var(--tone-bg-solid);\n }\n\n .v-badge[data-icon-only] {\n padding: 0;\n }\n\n .v-badge[data-dot] {\n width: var(--vectis-control-size-badge-dot);\n height: var(--vectis-control-size-badge-dot);\n min-width: 0;\n padding: 0;\n }\n\n .v-badge[data-bordered] {\n box-shadow: 0 0 0 var(--vectis-control-size-badge-ring) var(--badge-ring-color);\n }\n\n /* The tuck-in offset is a ratio of the badge's own size, so it stays proportionate\n across the pill, the dot and the icon. Each half of it is held in its own\n variable: the corner and the reading direction each flip ONE axis, and writing\n the whole `translate` again in each branch would make the two multiply — four\n rules to keep in step by hand for two independent decisions. */\n .v-badge-host[data-overlay] > .v-badge {\n --badge-overlay-x: 25%;\n --badge-overlay-y: -25%;\n\n position: absolute;\n inset-block: 0 auto;\n inset-inline-end: 0;\n translate: var(--badge-overlay-x) var(--badge-overlay-y);\n /* TRAP — an overlaid badge deliberately leaves its target's box, so it lands on\n whatever sits beside it, and the host opens no stacking context of its own\n (`position: relative` with `z-index: auto`). Left at `auto` the badge is painted\n with the other positioned boxes in TREE ORDER, which means anything positioned\n after it covers it: inside a VButtonGroup, where every segment is positioned, the\n badge on one segment disappears under the borders of the next. The lift takes it\n past that step, and no further: the segment it leans into comes later in tree\n order, so that segment's focus ring, raised to this same level, is still drawn\n over the badge rather than under it. */\n z-index: 1;\n }\n\n .v-badge-host[data-overlay][data-overlay-position='bottom'] > .v-badge {\n --badge-overlay-y: 25%;\n\n inset-block: auto 0;\n }\n\n /* In a right-to-left direction the logical corner moves to the left, so the\n horizontal half of the translation has to flip with it — `translate` is a\n physical property and knows nothing about direction. */\n .v-badge-host[data-overlay]:dir(rtl) > .v-badge {\n --badge-overlay-x: -25%;\n }\n\n /* Forced colours repaint the background as Canvas and drop the ring, a shadow: the pill\n loses its shape, and a dot, which has nothing else, disappears altogether. The pill\n gets an edge, and the dot is filled in the text colour. */\n @media (forced-colors: active) {\n .v-badge {\n outline: var(--vectis-control-border-width) solid CanvasText;\n outline-offset: calc(-1 * var(--vectis-control-border-width));\n }\n\n .v-badge.v-variant[data-dot] {\n forced-color-adjust: none;\n background: CanvasText;\n }\n }\n}\n</style>\n"],"mappings":""}
|
|
@@ -31,8 +31,11 @@ var f = ["data-overlay", "data-overlay-position"], p = /*@__PURE__*/ s({
|
|
|
31
31
|
function h() {
|
|
32
32
|
return m.default !== void 0;
|
|
33
33
|
}
|
|
34
|
-
let g = r(() =>
|
|
35
|
-
|
|
34
|
+
let g = r(() => {
|
|
35
|
+
let e = p.count;
|
|
36
|
+
if (!(e === void 0 || !Number.isFinite(e))) return e > 99 ? "99+" : Math.max(0, Math.trunc(e));
|
|
37
|
+
}), _ = () => c("span", {
|
|
38
|
+
class: "v-badge v-tone v-variant",
|
|
36
39
|
"data-variant": p.variant,
|
|
37
40
|
"data-tone": p.tone,
|
|
38
41
|
"data-custom": p.color === void 0 ? void 0 : "",
|
|
@@ -46,7 +49,7 @@ var f = ["data-overlay", "data-overlay-position"], p = /*@__PURE__*/ s({
|
|
|
46
49
|
class: "v-badge-host",
|
|
47
50
|
"data-overlay": s.overlay ? "" : void 0,
|
|
48
51
|
"data-overlay-position": s.overlayPosition
|
|
49
|
-
}, [u(e.$slots, "default"), o(_)], 8, f)) : (l(), i(_, { key: 1 }));
|
|
52
|
+
}, [u(e.$slots, "default"), o(_, { "aria-hidden": "true" })], 8, f)) : (l(), i(_, { key: 1 }));
|
|
50
53
|
}
|
|
51
54
|
});
|
|
52
55
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VBadge.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/VBadge/VBadge.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @core\n/**\n * A small pill carrying one piece of information at a glance: a count of unread\n * items, or a single icon. It is never interactive — there is nothing to click and\n * nothing to focus — and it either stands on its own, sits next to an element, or\n * is pinned to one of that element's corners.\n *\n * It is made of HTML and CSS alone. The only JavaScript decides what to render:\n * whether a target element was given at all, capping the counter at \"99+\", and\n * handing the two colours a consumer may choose to the stylesheet as\n * `--custom-color` and `--badge-ring-color`.\n */\nimport { computed, h } from 'vue'\nimport type { FunctionalComponent } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport type { IconSource } from '../VIcon/types'\n\nimport { customColorStyle } from '../../utils/css'\n\nexport type BadgeVariant = 'solid' | 'soft'\nexport type BadgeTone = 'neutral' | 'accent' | 'danger' | 'success' | 'warning'\nexport type BadgeOverlayPosition = 'top' | 'bottom'\n\ninterface BadgeProps {\n /**\n * How strongly the badge is painted: filled with the full colour (`solid`, the\n * default), or a tinted background with the text in the colour (`soft`), for a\n * count that should not draw the eye. A `dot` is always solid: with no content to\n * tint, a soft dot would be a pale disc barely distinguishable from the page.\n */\n variant?: BadgeVariant\n /**\n * The meaning the badge carries, expressed as a colour. A solid badge is filled\n * with it and its text adapts to stay readable; a soft one is tinted with it and\n * writes its text in it.\n */\n tone?: BadgeTone\n /**\n * A colour of your own (hex, CSS name or `oklch()`), which replaces the tone. On a\n * solid badge, browsers that support `contrast-color()` turn the text black or\n * white by themselves; everywhere else it falls back to white, so with a light\n * colour the contrast is yours to check. A soft badge derives its background and\n * text from that colour mixed with the theme's surface and text.\n */\n color?: string\n /**\n * The number to display. Anything above 99 is shown as \"99+\", so that a busy\n * counter cannot stretch the pill indefinitely.\n */\n count?: number\n /**\n * A single icon shown instead of a number: an icon name, or an explicit render\n * (the VIcon contract). It takes precedence over `count`, and is ignored when the\n * badge is a `dot`.\n */\n icon?: IconSource\n /**\n * Reduces the badge to a 10px dot with no content — the discreet way to signal\n * that something is new without saying how much.\n */\n dot?: boolean\n /**\n * Pins the badge to a corner of the target element instead of placing it beside\n * it. It does nothing when the badge has no target.\n */\n overlay?: boolean\n /**\n * Which corner an `overlay` badge is pinned to: the top one by default, the\n * bottom one for a marker that belongs at the foot of its target — a presence dot\n * under an avatar, for instance. The horizontal side follows the reading\n * direction and is not configurable. It does nothing without `overlay`.\n */\n overlayPosition?: BadgeOverlayPosition\n /**\n * Draws a 2px ring around the badge, in the colour of the surface behind it,\n * which detaches it from a busy target such as a picture. That colour defaults to\n * the page background and is named through `ringColor` on any other surface.\n */\n bordered?: boolean\n /**\n * The colour of the ring drawn by `bordered`. It defaults to the page background,\n * which is what makes the ring read as a gap around the badge; on another surface\n * (a card, a coloured banner), pass that surface's colour. It does nothing without\n * `bordered`.\n */\n ringColor?: string\n}\n\nconst props = withDefaults(defineProps<BadgeProps>(), {\n variant: 'solid',\n tone: 'accent',\n color: undefined,\n count: undefined,\n icon: undefined,\n overlayPosition: 'top',\n ringColor: undefined,\n // Written out although Vue casts an absent boolean to `false` on its own: left out,\n // `vue-component-meta` reports no default at all and the docs table's cell goes blank.\n dot: false,\n overlay: false,\n bordered: false,\n})\n\nconst slots = defineSlots<{\n /**\n * The element the badge belongs to. Without it the badge stands on its own; with\n * it, the badge is placed beside the element, or in its corner under `overlay`.\n */\n default?(): 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 hasTarget() {\n return slots.default !== undefined\n}\n\n/** The counter as it is actually displayed: anything past 99 becomes \"99+\". */\nconst displayCount = computed(() =>\n props.count !== undefined && props.count > 99 ? '99+' : props.count,\n)\n\n/*\n * The pill itself, written once. The template has two roots — one wrapping a target, one\n * standing alone — and both render the same badge; a functional component is the one way\n * to put the same markup in two places of a template without writing it twice.\n */\nconst Pill: FunctionalComponent = () =>\n h(\n 'span',\n {\n class: 'v-badge v-tone',\n 'data-variant': props.variant,\n 'data-tone': props.tone,\n 'data-custom': props.color !== undefined ? '' : undefined,\n 'data-dot': props.dot ? '' : undefined,\n 'data-icon-only': !props.dot && props.icon ? '' : undefined,\n 'data-bordered': props.bordered ? '' : undefined,\n style: [\n customColorStyle(props.color),\n props.ringColor !== undefined ? { '--badge-ring-color': props.ringColor } : undefined,\n ],\n },\n props.dot\n ? undefined\n : props.icon\n ? [h(VIcon, iconProps(props.icon))]\n : displayCount.value === undefined\n ? undefined\n : String(displayCount.value),\n )\n// TRAP — the empty list is not decoration. A functional component that declares no props lets\n// only `class`, `style` and listeners fall through, so a standalone badge, whose root this is,\n// would silently drop every other attribute a consumer set on VBadge (an `id`, a `data-*`).\nPill.props = []\n</script>\n\n<template>\n <span\n v-if=\"hasTarget()\"\n class=\"v-badge-host\"\n :data-overlay=\"overlay ? '' : undefined\"\n :data-overlay-position=\"overlayPosition\"\n >\n <slot />\n <Pill />\n </span>\n <Pill v-else />\n</template>\n\n<style>\n@layer vectis.components {\n .v-badge-host {\n position: relative;\n display: inline-flex;\n align-items: center;\n gap: var(--vectis-space-2); /* the space between the target and the badge, in inline mode */\n }\n\n .v-badge {\n --vectis-icon-size: var(--vectis-icon-size-sm);\n --vectis-icon-opsz: 20;\n /* The colour of the `bordered` ring: a bet on the page background, the only one a\n component can make since CSS cannot read what its parent paints. The `ringColor`\n prop overrides it inline for a badge sitting on anything else. */\n --badge-ring-color: var(--vectis-color-surface);\n /* The pill is the tone's solid pair, read from the shared table (`.v-tone`, set in the\n template). Its neutral is the text/surface inversion, which is what lets the\n fallback text and contrast-color() agree in both themes. */\n --badge-bg: var(--tone-bg-solid);\n --badge-text-fallback: var(--tone-text-solid);\n\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: var(--vectis-control-size-badge-h);\n /* A minimum width equal to the height, with a small padding on top, is what\n makes a one- or two-digit counter come out round rather than oval. */\n min-width: var(--vectis-control-size-badge-h);\n padding-inline: var(--vectis-space-1);\n border-radius: var(--vectis-radius-pill);\n background: var(--badge-bg);\n font-family: var(--vectis-text-family);\n font-size: var(--vectis-text-caption-size);\n font-weight: var(--vectis-text-control-weight);\n line-height: var(--vectis-text-control-leading);\n color: var(--badge-text-fallback);\n }\n\n @supports (color: contrast-color(red)) {\n .v-badge {\n color: contrast-color(var(--badge-bg));\n }\n }\n\n /* A custom colour replaces the tone: at (0,2,0) it beats the base rule's mapping\n whatever the order the two are written in. */\n .v-badge[data-custom] {\n --badge-bg: var(--custom-color);\n --badge-text-fallback: var(--vectis-color-text-on-accent);\n }\n\n /* The soft pair of the same table. The text is the tone's own colour rather than\n contrast-color(): the black or white that function picks reads on a pale tint, but\n says nothing of the tone. At (0,3,0) it beats the `@supports` rule above whatever\n the order. A dot is left out: with no content, a soft dot is a pale disc on the\n page, which a presence marker cannot afford. */\n .v-badge[data-variant='soft']:not([data-dot]) {\n --badge-bg: var(--tone-bg-soft);\n\n color: var(--tone-text-tinted);\n }\n\n /* A custom colour's soft pair, derived as VChip derives its own, so the same value\n gives a soft chip and a soft badge the same tint in both themes. */\n .v-badge[data-variant='soft'][data-custom]:not([data-dot]) {\n --badge-bg: color-mix(in oklab, var(--custom-color), var(--vectis-color-surface) 85%);\n\n color: color-mix(in oklab, var(--custom-color), var(--vectis-color-text) 30%);\n }\n\n .v-badge[data-icon-only] {\n padding: 0;\n }\n\n .v-badge[data-dot] {\n width: var(--vectis-control-size-badge-dot);\n height: var(--vectis-control-size-badge-dot);\n min-width: 0;\n padding: 0;\n }\n\n .v-badge[data-bordered] {\n box-shadow: 0 0 0 var(--vectis-control-size-badge-ring) var(--badge-ring-color);\n }\n\n /* The tuck-in offset is a ratio of the badge's own size, so it stays proportionate\n across the pill, the dot and the icon. Each half of it is held in its own\n variable: the corner and the reading direction each flip ONE axis, and writing\n the whole `translate` again in each branch would make the two multiply — four\n rules to keep in step by hand for two independent decisions. */\n .v-badge-host[data-overlay] > .v-badge {\n --badge-overlay-x: 25%;\n --badge-overlay-y: -25%;\n\n position: absolute;\n inset-block: 0 auto;\n inset-inline-end: 0;\n translate: var(--badge-overlay-x) var(--badge-overlay-y);\n /* TRAP — an overlaid badge deliberately leaves its target's box, so it lands on\n whatever sits beside it, and the host opens no stacking context of its own\n (`position: relative` with `z-index: auto`). Left at `auto` the badge is painted\n with the other positioned boxes in TREE ORDER, which means anything positioned\n after it covers it: inside a VButtonGroup, where every segment is positioned, the\n badge on one segment disappears under the borders of the next. The lift takes it\n past that step, and no further: the segment it leans into comes later in tree\n order, so that segment's focus ring, raised to this same level, is still drawn\n over the badge rather than under it. */\n z-index: 1;\n }\n\n .v-badge-host[data-overlay][data-overlay-position='bottom'] > .v-badge {\n --badge-overlay-y: 25%;\n\n inset-block: auto 0;\n }\n\n /* In a right-to-left direction the logical corner moves to the left, so the\n horizontal half of the translation has to flip with it — `translate` is a\n physical property and knows nothing about direction. */\n .v-badge-host[data-overlay]:dir(rtl) > .v-badge {\n --badge-overlay-x: -25%;\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2FA,IAAM,IAAQ,GAeR,IAAQ,EAAA;EAUd,SAAS,IAAY;GACnB,OAAO,EAAM,YAAY,KAAA;EAC3B;EAGA,IAAM,IAAe,QACnB,EAAM,UAAU,KAAA,KAAa,EAAM,QAAQ,KAAK,QAAQ,EAAM,KAChE,GAOM,UACJ,EACE,QACA;GACE,OAAO;GACP,gBAAgB,EAAM;GACtB,aAAa,EAAM;GACnB,eAAe,EAAM,UAAU,KAAA,IAAiB,KAAA,IAAL;GAC3C,YAAY,EAAM,MAAM,KAAK,KAAA;GAC7B,kBAAkB,CAAC,EAAM,OAAO,EAAM,OAAO,KAAK,KAAA;GAClD,iBAAiB,EAAM,WAAW,KAAK,KAAA;GACvC,OAAO,CACL,EAAiB,EAAM,KAAK,GAC5B,EAAM,cAAc,KAAA,IAAwD,KAAA,IAA5C,EAAE,sBAAsB,EAAM,UAAU,CAC1E;EACF,GACA,EAAM,MACF,KAAA,IACA,EAAM,OACJ,CAAC,EAAE,GAAO,EAAU,EAAM,IAAI,CAAC,CAAC,IAChC,EAAa,UAAU,KAAA,IACrB,KAAA,IACA,OAAO,EAAa,KAAK,CACnC;SAIF,EAAK,QAAQ,CAAC,aAKJ,EAAS,KAAA,EAAA,GADjB,EAQO,QAAA;;GANL,OAAM;GACL,gBAAc,EAAA,UAAO,KAAQ,KAAA;GAC7B,yBAAuB,EAAA;MAExB,EAAQ,EAAA,QAAA,SAAA,GACR,EAAQ,CAAA,CAAA,GAAA,GAAA,CAAA,MAAA,EAAA,GAEV,EAAe,GAAA,EAAA,KAAA,EAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"VBadge.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/VBadge/VBadge.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @core\n/**\n * A small pill carrying one piece of information at a glance: a count of unread\n * items, or a single icon. It is never interactive — there is nothing to click and\n * nothing to focus — and it either stands on its own, sits next to an element, or\n * is pinned to one of that element's corners.\n *\n * It is made of HTML and CSS alone. The only JavaScript decides what to render:\n * whether a target element was given at all, capping the counter at \"99+\", and\n * handing the two colours a consumer may choose to the stylesheet as\n * `--custom-color` and `--badge-ring-color`.\n *\n * Beside a target the pill is `aria-hidden`: read on its own, \"3\" means nothing, and the\n * target is what a reader reaches, so the count belongs in the target's own name\n * (\"Notifications, 3 unread\") where it would otherwise be announced twice.\n */\nimport { computed, h } from 'vue'\nimport type { FunctionalComponent } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport type { IconSource } from '../VIcon/types'\n\nimport { customColorStyle } from '../../utils/css'\n\n/** How strongly the badge is painted: the full colour, or a tint of it. */\nexport type BadgeVariant = 'solid' | 'soft'\n/** What the badge means, in colour. */\nexport type BadgeTone = 'neutral' | 'accent' | 'danger' | 'success' | 'warning'\n/** The corner an overlaid badge is pinned to. */\nexport type BadgeOverlayPosition = 'top' | 'bottom'\n\ninterface BadgeProps {\n /**\n * How strongly the badge is painted: filled with the full colour (`solid`, the\n * default), or a tinted background with the text in the colour (`soft`), for a\n * count that should not draw the eye. A `dot` is always solid: with no content to\n * tint, a soft dot would be a pale disc barely distinguishable from the page.\n */\n variant?: BadgeVariant\n /**\n * The meaning the badge carries, expressed as a colour. A solid badge is filled\n * with it and its text adapts to stay readable; a soft one is tinted with it and\n * writes its text in it.\n */\n tone?: BadgeTone\n /**\n * A colour of your own (hex, CSS name or `oklch()`), which replaces the tone. On a\n * solid badge, browsers that support `contrast-color()` turn the text black or\n * white by themselves; everywhere else it falls back to white, so with a light\n * colour the contrast is yours to check. A soft badge derives its background and\n * text from that colour mixed with the theme's surface and text.\n */\n color?: string\n /**\n * The number to display. Anything above 99 is shown as \"99+\", so that a busy\n * counter cannot stretch the pill indefinitely.\n */\n count?: number\n /**\n * A single icon shown instead of a number: an icon name, or an explicit render\n * (the VIcon contract). It takes precedence over `count`, and is ignored when the\n * badge is a `dot`.\n */\n icon?: IconSource\n /**\n * Reduces the badge to a 10px dot with no content, the discreet way to signal\n * that something is new without saying how much.\n */\n dot?: boolean\n /**\n * Pins the badge to a corner of the target element instead of placing it beside\n * it. It does nothing when the badge has no target.\n */\n overlay?: boolean\n /**\n * Which corner an `overlay` badge is pinned to: the top one by default, the\n * bottom one for a marker that belongs at the foot of its target, such as a presence dot\n * under an avatar. The horizontal side follows the reading\n * direction and is not configurable. It does nothing without `overlay`.\n */\n overlayPosition?: BadgeOverlayPosition\n /**\n * Draws a 2px ring around the badge, in the colour of the surface behind it,\n * which detaches it from a busy target such as a picture. That colour defaults to\n * the page background and is named through `ringColor` on any other surface.\n */\n bordered?: boolean\n /**\n * The colour of the ring drawn by `bordered`. It defaults to the page background,\n * which is what makes the ring read as a gap around the badge; on another surface\n * (a card, a coloured banner), pass that surface's colour. It does nothing without\n * `bordered`.\n */\n ringColor?: string\n}\n\nconst props = withDefaults(defineProps<BadgeProps>(), {\n variant: 'solid',\n tone: 'accent',\n color: undefined,\n count: undefined,\n icon: undefined,\n overlayPosition: 'top',\n ringColor: undefined,\n // Written out although Vue casts an absent boolean to `false` on its own: left out,\n // `vue-component-meta` reports no default at all and the docs table's cell goes blank.\n dot: false,\n overlay: false,\n bordered: false,\n})\n\nconst slots = defineSlots<{\n /**\n * The element the badge belongs to. Without it the badge stands on its own; with\n * it, the badge is placed beside the element, or in its corner under `overlay`, and is\n * hidden from assistive technology: say the count in the element's own name.\n */\n default?(): 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 hasTarget() {\n return slots.default !== undefined\n}\n\n/**\n * The counter as it is actually displayed: a whole number, zero or more, and anything past 99\n * becomes \"99+\". A count that is not a number (a division by a total not yet known) draws\n * nothing rather than the word \"NaN\".\n */\nconst displayCount = computed(() => {\n const count = props.count\n if (count === undefined || !Number.isFinite(count)) return undefined\n return count > 99 ? '99+' : Math.max(0, Math.trunc(count))\n})\n\n/*\n * The pill itself, written once. The template has two roots — one wrapping a target, one\n * standing alone — and both render the same badge; a functional component is the one way\n * to put the same markup in two places of a template without writing it twice.\n */\nconst Pill: FunctionalComponent = () =>\n h(\n 'span',\n {\n class: 'v-badge v-tone v-variant',\n 'data-variant': props.variant,\n 'data-tone': props.tone,\n 'data-custom': props.color !== undefined ? '' : undefined,\n 'data-dot': props.dot ? '' : undefined,\n 'data-icon-only': !props.dot && props.icon ? '' : undefined,\n 'data-bordered': props.bordered ? '' : undefined,\n style: [\n customColorStyle(props.color),\n props.ringColor !== undefined ? { '--badge-ring-color': props.ringColor } : undefined,\n ],\n },\n props.dot\n ? undefined\n : props.icon\n ? [h(VIcon, iconProps(props.icon))]\n : displayCount.value === undefined\n ? undefined\n : String(displayCount.value),\n )\n// TRAP — the empty list is not decoration. A functional component that declares no props lets\n// only `class`, `style` and listeners fall through, so a standalone badge, whose root this is,\n// would silently drop every other attribute a consumer set on VBadge (an `id`, a `data-*`).\nPill.props = []\n</script>\n\n<template>\n <span\n v-if=\"hasTarget()\"\n class=\"v-badge-host\"\n :data-overlay=\"overlay ? '' : undefined\"\n :data-overlay-position=\"overlayPosition\"\n >\n <slot />\n <Pill aria-hidden=\"true\" />\n </span>\n <Pill v-else />\n</template>\n\n<style>\n@layer vectis.components {\n .v-badge-host {\n position: relative;\n display: inline-flex;\n align-items: center;\n gap: var(--vectis-space-2); /* the space between the target and the badge, in inline mode */\n }\n\n /* The pill is painted by the shared `.v-variant` rules (styles/variants.css) over the\n tone table (`.v-tone`), both set in the template: `solid` is the tone's full colour,\n `soft` its tint with the text in the tone's own colour. A custom colour is the table's\n `[data-custom]` row, in styles/tones.css. */\n .v-badge {\n --vectis-icon-size: var(--vectis-icon-size-sm);\n --vectis-icon-opsz: 20;\n /* The colour of the `bordered` ring: a bet on the page background, the only one a\n component can make since CSS cannot read what its parent paints. The `ringColor`\n prop overrides it inline for a badge sitting on anything else. */\n --badge-ring-color: var(--vectis-color-surface);\n\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: var(--vectis-control-size-badge-h);\n /* A minimum width equal to the height, with a small padding on top, is what\n makes a one- or two-digit counter come out round rather than oval. */\n min-width: var(--vectis-control-size-badge-h);\n padding-inline: var(--vectis-space-1);\n border-radius: var(--vectis-radius-pill);\n font-family: var(--vectis-text-family);\n font-size: var(--vectis-text-caption-size);\n font-weight: var(--vectis-text-control-weight);\n line-height: var(--vectis-text-control-leading);\n }\n\n /* On a solid pill the text picks black or white against whatever the fill ended up\n with, where the function exists; elsewhere it keeps the table's `--tone-text-solid`.\n TRAP — the class is compounded to (0,3,0): `.v-variant[data-variant='solid']` sets\n `color` at (0,2,0) from another sheet, and a tie would be settled by sheet order. The\n soft pill keeps the tone's own text colour, which says the tone where black or white\n would not. */\n @supports (color: contrast-color(red)) {\n .v-badge.v-variant[data-variant='solid'] {\n color: contrast-color(var(--tone-bg-solid));\n }\n }\n\n /* A dot is always solid: with no content, a soft dot is a pale disc on the page, which a\n presence marker cannot afford. (0,3,0), above the soft variant's background. */\n .v-badge.v-variant[data-dot] {\n background: var(--tone-bg-solid);\n }\n\n .v-badge[data-icon-only] {\n padding: 0;\n }\n\n .v-badge[data-dot] {\n width: var(--vectis-control-size-badge-dot);\n height: var(--vectis-control-size-badge-dot);\n min-width: 0;\n padding: 0;\n }\n\n .v-badge[data-bordered] {\n box-shadow: 0 0 0 var(--vectis-control-size-badge-ring) var(--badge-ring-color);\n }\n\n /* The tuck-in offset is a ratio of the badge's own size, so it stays proportionate\n across the pill, the dot and the icon. Each half of it is held in its own\n variable: the corner and the reading direction each flip ONE axis, and writing\n the whole `translate` again in each branch would make the two multiply — four\n rules to keep in step by hand for two independent decisions. */\n .v-badge-host[data-overlay] > .v-badge {\n --badge-overlay-x: 25%;\n --badge-overlay-y: -25%;\n\n position: absolute;\n inset-block: 0 auto;\n inset-inline-end: 0;\n translate: var(--badge-overlay-x) var(--badge-overlay-y);\n /* TRAP — an overlaid badge deliberately leaves its target's box, so it lands on\n whatever sits beside it, and the host opens no stacking context of its own\n (`position: relative` with `z-index: auto`). Left at `auto` the badge is painted\n with the other positioned boxes in TREE ORDER, which means anything positioned\n after it covers it: inside a VButtonGroup, where every segment is positioned, the\n badge on one segment disappears under the borders of the next. The lift takes it\n past that step, and no further: the segment it leans into comes later in tree\n order, so that segment's focus ring, raised to this same level, is still drawn\n over the badge rather than under it. */\n z-index: 1;\n }\n\n .v-badge-host[data-overlay][data-overlay-position='bottom'] > .v-badge {\n --badge-overlay-y: 25%;\n\n inset-block: auto 0;\n }\n\n /* In a right-to-left direction the logical corner moves to the left, so the\n horizontal half of the translation has to flip with it — `translate` is a\n physical property and knows nothing about direction. */\n .v-badge-host[data-overlay]:dir(rtl) > .v-badge {\n --badge-overlay-x: -25%;\n }\n\n /* Forced colours repaint the background as Canvas and drop the ring, a shadow: the pill\n loses its shape, and a dot, which has nothing else, disappears altogether. The pill\n gets an edge, and the dot is filled in the text colour. */\n @media (forced-colors: active) {\n .v-badge {\n outline: var(--vectis-control-border-width) solid CanvasText;\n outline-offset: calc(-1 * var(--vectis-control-border-width));\n }\n\n .v-badge.v-variant[data-dot] {\n forced-color-adjust: none;\n background: CanvasText;\n }\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkGA,IAAM,IAAQ,GAeR,IAAQ,EAAA;EAWd,SAAS,IAAY;GACnB,OAAO,EAAM,YAAY,KAAA;EAC3B;EAOA,IAAM,IAAe,QAAe;GAClC,IAAM,IAAQ,EAAM;GAChB,YAAU,KAAA,KAAa,CAAC,OAAO,SAAS,CAAK,IACjD,OAAO,IAAQ,KAAK,QAAQ,KAAK,IAAI,GAAG,KAAK,MAAM,CAAK,CAAC;EAC3D,CAAC,GAOK,UACJ,EACE,QACA;GACE,OAAO;GACP,gBAAgB,EAAM;GACtB,aAAa,EAAM;GACnB,eAAe,EAAM,UAAU,KAAA,IAAiB,KAAA,IAAL;GAC3C,YAAY,EAAM,MAAM,KAAK,KAAA;GAC7B,kBAAkB,CAAC,EAAM,OAAO,EAAM,OAAO,KAAK,KAAA;GAClD,iBAAiB,EAAM,WAAW,KAAK,KAAA;GACvC,OAAO,CACL,EAAiB,EAAM,KAAK,GAC5B,EAAM,cAAc,KAAA,IAAwD,KAAA,IAA5C,EAAE,sBAAsB,EAAM,UAAU,CAC1E;EACF,GACA,EAAM,MACF,KAAA,IACA,EAAM,OACJ,CAAC,EAAE,GAAO,EAAU,EAAM,IAAI,CAAC,CAAC,IAChC,EAAa,UAAU,KAAA,IACrB,KAAA,IACA,OAAO,EAAa,KAAK,CACnC;SAIF,EAAK,QAAQ,CAAC,aAKJ,EAAS,KAAA,EAAA,GADjB,EAQO,QAAA;;GANL,OAAM;GACL,gBAAc,EAAA,UAAO,KAAQ,KAAA;GAC7B,yBAAuB,EAAA;MAExB,EAAQ,EAAA,QAAA,SAAA,GACR,EAA2B,GAAA,EAArB,eAAY,OAAM,CAAA,CAAA,GAAA,GAAA,CAAA,MAAA,EAAA,GAE1B,EAAe,GAAA,EAAA,KAAA,EAAA,CAAA"}
|
|
@@ -8,8 +8,8 @@ export interface BreadcrumbItem {
|
|
|
8
8
|
*/
|
|
9
9
|
href: string;
|
|
10
10
|
/**
|
|
11
|
-
* An icon placed before the label:
|
|
12
|
-
*
|
|
11
|
+
* An icon placed before the label: an icon name, or an explicit render
|
|
12
|
+
* (`{ src: '/logo.svg' }`, `{ component }`…). A string is always a name.
|
|
13
13
|
*/
|
|
14
14
|
icon?: IconSource;
|
|
15
15
|
}
|
|
@@ -23,12 +23,13 @@ interface BreadcrumbProps {
|
|
|
23
23
|
label?: string;
|
|
24
24
|
/**
|
|
25
25
|
* The address of the page being displayed. The segment whose `href` matches it is
|
|
26
|
-
* the current one
|
|
26
|
+
* the current one, even when it is folded into the menu. A trailing slash, a query and
|
|
27
|
+
* a hash on either side make no difference, so a router's full path can be passed as is.
|
|
27
28
|
*/
|
|
28
29
|
currentPath?: string;
|
|
29
30
|
/**
|
|
30
31
|
* The icon drawn between two segments: an icon name, or an explicit render,
|
|
31
|
-
* exactly like an item's `icon`.
|
|
32
|
+
* exactly like an item's `icon`. It is mirrored in a right-to-left page.
|
|
32
33
|
*/
|
|
33
34
|
separatorIcon?: IconSource;
|
|
34
35
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VBreadcrumb.js","names":[],"sources":["../../../src/components/VBreadcrumb/VBreadcrumb.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @ssr @core\n/**\n * The path leading to the page being read, from the broadest section down to the current\n * one: a `<nav>` holding an `<ol>`, built entirely from the `items` prop. Nothing is read\n * from the browser, so the server and the client render the same thing.\n *\n * The separators are decorative `aria-hidden` icons, and the first is removed in CSS rather\n * than by a condition in the markup. The current page is found by comparing each address\n * with `currentPath`, carries `aria-current=\"page\"` and stays a working link, as the ARIA\n * practices recommend. Past `maxItems`, the middle segments fold into a VMenu behind an \"…\".\n */\n\nimport { computed } 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 { more_horiz as moreHorizIcon } from '../VIcon/icons/more_horiz'\nimport type { IconSource } from '../VIcon/types'\nimport VIconButton from '../VIconButton/VIconButton.vue'\nimport VMenu from '../VMenu/VMenu.vue'\nimport VMenuItem from '../VMenu/VMenuItem.vue'\n\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useMessages } from '../../i18n/state'\n\nexport interface BreadcrumbItem {\n /** The text shown for this segment. */\n label: string\n /**\n * Where the segment leads. It is also the value compared with `currentPath` to\n * decide which segment is the current page.\n */\n href: string\n /**\n * An icon placed before the label:
|
|
1
|
+
{"version":3,"file":"VBreadcrumb.js","names":[],"sources":["../../../src/components/VBreadcrumb/VBreadcrumb.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @ssr @core\n/**\n * The path leading to the page being read, from the broadest section down to the current\n * one: a `<nav>` holding an `<ol>`, built entirely from the `items` prop. Nothing is read\n * from the browser, so the server and the client render the same thing.\n *\n * The separators are decorative `aria-hidden` icons, and the first is removed in CSS rather\n * than by a condition in the markup. The current page is found by comparing each address\n * with `currentPath`, carries `aria-current=\"page\"` and stays a working link, as the ARIA\n * practices recommend. Past `maxItems`, the middle segments fold into a VMenu behind an \"…\".\n */\n\nimport { computed } 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 { more_horiz as moreHorizIcon } from '../VIcon/icons/more_horiz'\nimport type { IconSource } from '../VIcon/types'\nimport VIconButton from '../VIconButton/VIconButton.vue'\nimport VMenu from '../VMenu/VMenu.vue'\nimport VMenuItem from '../VMenu/VMenuItem.vue'\n\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useMessages } from '../../i18n/state'\n\nexport interface BreadcrumbItem {\n /** The text shown for this segment. */\n label: string\n /**\n * Where the segment leads. It is also the value compared with `currentPath` to\n * decide which segment is the current page.\n */\n href: string\n /**\n * An icon placed before the label: an icon name, or an explicit render\n * (`{ src: '/logo.svg' }`, `{ component }`…). A string is always a name.\n */\n icon?: IconSource\n}\n\ninterface BreadcrumbProps {\n /** The segments of the trail, ordered from the most general down to the deepest. */\n items: BreadcrumbItem[]\n /**\n * The name screen readers announce for this navigation. It falls back to the\n * wording of the DS dictionary, in the current language.\n */\n label?: string\n /**\n * The address of the page being displayed. The segment whose `href` matches it is\n * the current one, even when it is folded into the menu. A trailing slash, a query and\n * a hash on either side make no difference, so a router's full path can be passed as is.\n */\n currentPath?: string\n /**\n * The icon drawn between two segments: an icon name, or an explicit render,\n * exactly like an item's `icon`. It is mirrored in a right-to-left page.\n */\n separatorIcon?: IconSource\n /**\n * The length past which the trail folds: only the first segment, an \"…\" button and\n * the last two remain, the button opening a menu that lists the hidden segments\n * alone. Below 3 there would be nothing left to fold, so 3 is the effective\n * minimum.\n */\n maxItems?: number\n /**\n * The name screen readers announce for the \"…\" button. It falls back to the\n * wording of the DS dictionary.\n */\n ellipsisLabel?: string\n}\n\nconst props = withDefaults(defineProps<BreadcrumbProps>(), {\n label: undefined,\n currentPath: undefined,\n separatorIcon: () => chevronRightIcon,\n maxItems: undefined,\n ellipsisLabel: undefined,\n})\n\nconst m = useMessages()\nconst ariaLabel = useAriaLabel(() => props.label ?? m.value.breadcrumb.label)\nconst resolvedEllipsisLabel = computed(() => props.ellipsisLabel ?? m.value.breadcrumb.ellipsis)\n\n/**\n * Drops the query, the hash and a trailing slash, so that `/docs`, `/docs/` and a\n * router's full path `/docs?tab=2#intro` compare as the same page; the root `/` is left\n * alone. Pure string handling, hence safe to run on the server.\n */\nfunction normalize(path: string): string {\n const bare = path.replace(/[?#].*$/, '')\n return bare.length > 1 && bare.endsWith('/') ? bare.slice(0, -1) : bare\n}\n\n// Normalized once per change of the prop rather than once per segment on every render.\nconst normalizedCurrent = computed(() =>\n props.currentPath === undefined ? undefined : normalize(props.currentPath),\n)\n\n// @a11y\n// This is what feeds `aria-current=\"page\"`, the only marker telling assistive technology\n// where the trail ends, the folded segments of the menu included.\nfunction isCurrent(item: BreadcrumbItem): boolean {\n return normalizedCurrent.value !== undefined && normalize(item.href) === normalizedCurrent.value\n}\n\nconst truncated = computed(\n () => props.maxItems !== undefined && props.items.length > Math.max(props.maxItems, 3),\n)\n/** The segments folded into the menu: everything between the first and the last two. */\nconst hiddenItems = computed(() => (truncated.value ? props.items.slice(1, -2) : []))\n/**\n * The segments actually rendered in the list — when the trail is folded, the first\n * one followed by the last two.\n */\nconst visibleItems = computed(() =>\n truncated.value ? [props.items[0] as BreadcrumbItem, ...props.items.slice(-2)] : props.items,\n)\n</script>\n\n<template>\n <nav class=\"v-breadcrumb\" :aria-label=\"ariaLabel\">\n <ol class=\"v-breadcrumb-list\">\n <template v-for=\"(item, index) in visibleItems\" :key=\"item.href\">\n <li v-if=\"truncated && index === 1\" class=\"v-breadcrumb-item v-breadcrumb-ellipsis\">\n <VIcon class=\"v-breadcrumb-separator\" v-bind=\"iconProps(separatorIcon)\" mirrored />\n <VMenu>\n <template #trigger=\"{ triggerProps }\">\n <VIconButton\n size=\"sm\"\n :label=\"resolvedEllipsisLabel\"\n :icon=\"moreHorizIcon\"\n v-bind=\"triggerProps\"\n />\n </template>\n <VMenuItem\n v-for=\"hidden in hiddenItems\"\n :key=\"hidden.href\"\n :href=\"hidden.href\"\n :label=\"hidden.label\"\n :icon-start=\"hidden.icon\"\n :selected=\"isCurrent(hidden)\"\n :aria-current=\"isCurrent(hidden) ? 'page' : undefined\"\n />\n </VMenu>\n </li>\n <li class=\"v-breadcrumb-item\">\n <VIcon class=\"v-breadcrumb-separator\" v-bind=\"iconProps(separatorIcon)\" mirrored />\n <a\n class=\"v-breadcrumb-link\"\n :href=\"item.href\"\n :aria-current=\"isCurrent(item) ? 'page' : undefined\"\n >\n <VIcon v-if=\"item.icon\" v-bind=\"iconProps(item.icon)\" />\n {{ item.label }}\n </a>\n </li>\n </template>\n </ol>\n </nav>\n</template>\n\n<style>\n@layer vectis.components {\n /* The icon context is set here rather than through `.v-control`, which is the usual\n route: a trail has no `size` prop and no height to speak of, so the size scale would\n bring a table of five steps to pick one value from. */\n .v-breadcrumb {\n --vectis-icon-size: var(--vectis-icon-size-sm);\n --vectis-icon-opsz: 20;\n }\n\n .v-breadcrumb-list {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: var(--vectis-space-2);\n margin: 0;\n padding: 0;\n list-style: none;\n font-family: var(--vectis-text-family);\n font-size: var(--vectis-text-body-md-size);\n }\n\n .v-breadcrumb-item {\n display: inline-flex;\n align-items: center;\n gap: var(--vectis-space-2);\n color: var(--vectis-color-text-muted);\n }\n\n /* TRAP — every item renders its own leading separator and the first one is hidden HERE,\n which is what keeps the template free of an index test. Delete this rule and the trail\n opens on a stray chevron; both child combinators are load-bearing too, so wrapping an\n item or the list in anything puts that chevron straight back. */\n .v-breadcrumb-list > .v-breadcrumb-item:first-child > .v-breadcrumb-separator {\n display: none;\n }\n\n .v-breadcrumb-separator {\n color: var(--vectis-color-text-subtle);\n }\n\n /* The corner is only ever seen on the focus ring, which follows it. It is the control\n radius capped at half a line, the row recipe of VSideNavigationItem with the line\n standing in for a control height the link does not have: a label that wraps keeps\n the corner of a one-line one under a pill override. */\n .v-breadcrumb-link {\n display: inline-flex;\n align-items: center;\n gap: var(--vectis-space-1);\n color: var(--vectis-color-text-muted);\n text-decoration: none;\n border-radius: min(var(--vectis-radius-interactive), 0.5lh);\n transition: color var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n\n .v-breadcrumb-link:hover {\n color: var(--vectis-color-text);\n text-decoration: underline;\n }\n\n .v-breadcrumb-link:focus-visible {\n outline: var(--vectis-focus-ring-width) solid var(--vectis-focus-ring-color);\n outline-offset: var(--vectis-focus-ring-offset);\n }\n\n .v-breadcrumb-link[aria-current='page'] {\n color: var(--vectis-color-text);\n font-weight: var(--vectis-text-label-weight);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-breadcrumb-link {\n transition: none;\n }\n }\n}\n</style>\n"],"mappings":""}
|
|
@@ -25,7 +25,8 @@ var w = ["aria-label"], T = { class: "v-breadcrumb-list" }, E = {
|
|
|
25
25
|
setup(a) {
|
|
26
26
|
let _ = a, k = e(), A = i(() => _.label ?? k.value.breadcrumb.label), j = u(() => _.ellipsisLabel ?? k.value.breadcrumb.ellipsis);
|
|
27
27
|
function M(e) {
|
|
28
|
-
|
|
28
|
+
let t = e.replace(/[?#].*$/, "");
|
|
29
|
+
return t.length > 1 && t.endsWith("/") ? t.slice(0, -1) : t;
|
|
29
30
|
}
|
|
30
31
|
let N = u(() => _.currentPath === void 0 ? void 0 : M(_.currentPath));
|
|
31
32
|
function P(e) {
|
|
@@ -45,11 +46,15 @@ var w = ["aria-label"], T = { class: "v-breadcrumb-list" }, E = {
|
|
|
45
46
|
key: e.href,
|
|
46
47
|
href: e.href,
|
|
47
48
|
label: e.label,
|
|
48
|
-
"icon-start": e.icon
|
|
49
|
+
"icon-start": e.icon,
|
|
50
|
+
selected: P(e),
|
|
51
|
+
"aria-current": P(e) ? "page" : void 0
|
|
49
52
|
}, null, 8, [
|
|
50
53
|
"href",
|
|
51
54
|
"label",
|
|
52
|
-
"icon-start"
|
|
55
|
+
"icon-start",
|
|
56
|
+
"selected",
|
|
57
|
+
"aria-current"
|
|
53
58
|
]))), 128))]),
|
|
54
59
|
_: 1
|
|
55
60
|
})])) : f("", !0), m("li", D, [g(n, v({ class: "v-breadcrumb-separator" }, { ref_for: !0 }, S(t)(a.separatorIcon), { mirrored: "" }), null, 16), m("a", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VBreadcrumb.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/VBreadcrumb/VBreadcrumb.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @ssr @core\n/**\n * The path leading to the page being read, from the broadest section down to the current\n * one: a `<nav>` holding an `<ol>`, built entirely from the `items` prop. Nothing is read\n * from the browser, so the server and the client render the same thing.\n *\n * The separators are decorative `aria-hidden` icons, and the first is removed in CSS rather\n * than by a condition in the markup. The current page is found by comparing each address\n * with `currentPath`, carries `aria-current=\"page\"` and stays a working link, as the ARIA\n * practices recommend. Past `maxItems`, the middle segments fold into a VMenu behind an \"…\".\n */\n\nimport { computed } 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 { more_horiz as moreHorizIcon } from '../VIcon/icons/more_horiz'\nimport type { IconSource } from '../VIcon/types'\nimport VIconButton from '../VIconButton/VIconButton.vue'\nimport VMenu from '../VMenu/VMenu.vue'\nimport VMenuItem from '../VMenu/VMenuItem.vue'\n\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useMessages } from '../../i18n/state'\n\nexport interface BreadcrumbItem {\n /** The text shown for this segment. */\n label: string\n /**\n * Where the segment leads. It is also the value compared with `currentPath` to\n * decide which segment is the current page.\n */\n href: string\n /**\n * An icon placed before the label: a Material Symbols Rounded name, an icon URL,\n * or an explicit render (`{ src: '/logo.svg' }`, `{ component }`…).\n */\n icon?: IconSource\n}\n\ninterface BreadcrumbProps {\n /** The segments of the trail, ordered from the most general down to the deepest. */\n items: BreadcrumbItem[]\n /**\n * The name screen readers announce for this navigation. It falls back to the\n * wording of the DS dictionary, in the current language.\n */\n label?: string\n /**\n * The address of the page being displayed. The segment whose `href` matches it is\n * the current one; a trailing slash on either side makes no difference.\n */\n currentPath?: string\n /**\n * The icon drawn between two segments: an icon name, or an explicit render,\n * exactly like an item's `icon`.\n */\n separatorIcon?: IconSource\n /**\n * The length past which the trail folds: only the first segment, an \"…\" button and\n * the last two remain, the button opening a menu that lists the hidden segments\n * alone. Below 3 there would be nothing left to fold, so 3 is the effective\n * minimum.\n */\n maxItems?: number\n /**\n * The name screen readers announce for the \"…\" button. It falls back to the\n * wording of the DS dictionary.\n */\n ellipsisLabel?: string\n}\n\nconst props = withDefaults(defineProps<BreadcrumbProps>(), {\n label: undefined,\n currentPath: undefined,\n separatorIcon: () => chevronRightIcon,\n maxItems: undefined,\n ellipsisLabel: undefined,\n})\n\nconst m = useMessages()\nconst ariaLabel = useAriaLabel(() => props.label ?? m.value.breadcrumb.label)\nconst resolvedEllipsisLabel = computed(() => props.ellipsisLabel ?? m.value.breadcrumb.ellipsis)\n\n/**\n * Drops a trailing slash so that `/docs` and `/docs/` compare as the same page; the\n * root `/` is left alone. Pure string handling, hence safe to run on the server.\n */\nfunction normalize(path: string): string {\n return path.length > 1 && path.endsWith('/') ? path.slice(0, -1) : path\n}\n\n// Normalized once per change of the prop rather than once per segment on every render.\nconst normalizedCurrent = computed(() =>\n props.currentPath === undefined ? undefined : normalize(props.currentPath),\n)\n\n// @a11y — this is what feeds `aria-current=\"page\"`, the only marker telling\n// assistive technology where the trail ends.\nfunction isCurrent(item: BreadcrumbItem): boolean {\n return normalizedCurrent.value !== undefined && normalize(item.href) === normalizedCurrent.value\n}\n\nconst truncated = computed(\n () => props.maxItems !== undefined && props.items.length > Math.max(props.maxItems, 3),\n)\n/** The segments folded into the menu: everything between the first and the last two. */\nconst hiddenItems = computed(() => (truncated.value ? props.items.slice(1, -2) : []))\n/**\n * The segments actually rendered in the list — when the trail is folded, the first\n * one followed by the last two.\n */\nconst visibleItems = computed(() =>\n truncated.value ? [props.items[0] as BreadcrumbItem, ...props.items.slice(-2)] : props.items,\n)\n</script>\n\n<template>\n <nav class=\"v-breadcrumb\" :aria-label=\"ariaLabel\">\n <ol class=\"v-breadcrumb-list\">\n <template v-for=\"(item, index) in visibleItems\" :key=\"item.href\">\n <li v-if=\"truncated && index === 1\" class=\"v-breadcrumb-item v-breadcrumb-ellipsis\">\n <VIcon class=\"v-breadcrumb-separator\" v-bind=\"iconProps(separatorIcon)\" mirrored />\n <VMenu>\n <template #trigger=\"{ triggerProps }\">\n <VIconButton\n size=\"sm\"\n :label=\"resolvedEllipsisLabel\"\n :icon=\"moreHorizIcon\"\n v-bind=\"triggerProps\"\n />\n </template>\n <VMenuItem\n v-for=\"hidden in hiddenItems\"\n :key=\"hidden.href\"\n :href=\"hidden.href\"\n :label=\"hidden.label\"\n :icon-start=\"hidden.icon\"\n />\n </VMenu>\n </li>\n <li class=\"v-breadcrumb-item\">\n <VIcon class=\"v-breadcrumb-separator\" v-bind=\"iconProps(separatorIcon)\" mirrored />\n <a\n class=\"v-breadcrumb-link\"\n :href=\"item.href\"\n :aria-current=\"isCurrent(item) ? 'page' : undefined\"\n >\n <VIcon v-if=\"item.icon\" v-bind=\"iconProps(item.icon)\" />\n {{ item.label }}\n </a>\n </li>\n </template>\n </ol>\n </nav>\n</template>\n\n<style>\n@layer vectis.components {\n /* The icon context is set here rather than through `.v-control`, which is the usual\n route: a trail has no `size` prop and no height to speak of, so the size scale would\n bring a table of five steps to pick one value from. */\n .v-breadcrumb {\n --vectis-icon-size: var(--vectis-icon-size-sm);\n --vectis-icon-opsz: 20;\n }\n\n .v-breadcrumb-list {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: var(--vectis-space-2);\n margin: 0;\n padding: 0;\n list-style: none;\n font-family: var(--vectis-text-family);\n font-size: var(--vectis-text-body-md-size);\n }\n\n .v-breadcrumb-item {\n display: inline-flex;\n align-items: center;\n gap: var(--vectis-space-2);\n color: var(--vectis-color-text-muted);\n }\n\n /* TRAP — every item renders its own leading separator and the first one is hidden HERE,\n which is what keeps the template free of an index test. Delete this rule and the trail\n opens on a stray chevron; both child combinators are load-bearing too, so wrapping an\n item or the list in anything puts that chevron straight back. */\n .v-breadcrumb-list > .v-breadcrumb-item:first-child > .v-breadcrumb-separator {\n display: none;\n }\n\n .v-breadcrumb-separator {\n color: var(--vectis-color-text-subtle);\n }\n\n /* The corner is only ever seen on the focus ring, which follows it. It is the control\n radius capped at half a line, the row recipe of VSideNavigationItem with the line\n standing in for a control height the link does not have: a label that wraps keeps\n the corner of a one-line one under a pill override. */\n .v-breadcrumb-link {\n display: inline-flex;\n align-items: center;\n gap: var(--vectis-space-1);\n color: var(--vectis-color-text-muted);\n text-decoration: none;\n border-radius: min(var(--vectis-radius-interactive), 0.5lh);\n transition: color var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n\n .v-breadcrumb-link:hover {\n color: var(--vectis-color-text);\n text-decoration: underline;\n }\n\n .v-breadcrumb-link:focus-visible {\n outline: var(--vectis-focus-ring-width) solid var(--vectis-focus-ring-color);\n outline-offset: var(--vectis-focus-ring-offset);\n }\n\n .v-breadcrumb-link[aria-current='page'] {\n color: var(--vectis-color-text);\n font-weight: var(--vectis-text-label-weight);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-breadcrumb-link {\n transition: none;\n }\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;EA0EA,IAAM,IAAQ,GAQR,IAAI,EAAY,GAChB,IAAY,QAAmB,EAAM,SAAS,EAAE,MAAM,WAAW,KAAK,GACtE,IAAwB,QAAe,EAAM,iBAAiB,EAAE,MAAM,WAAW,QAAQ;EAM/F,SAAS,EAAU,GAAsB;GACvC,OAAO,EAAK,SAAS,KAAK,EAAK,SAAS,GAAG,IAAI,EAAK,MAAM,GAAG,EAAE,IAAI;EACrE;EAGA,IAAM,IAAoB,QACxB,EAAM,gBAAgB,KAAA,IAAY,KAAA,IAAY,EAAU,EAAM,WAAW,CAC3E;EAIA,SAAS,EAAU,GAA+B;GAChD,OAAO,EAAkB,UAAU,KAAA,KAAa,EAAU,EAAK,IAAI,MAAM,EAAkB;EAC7F;EAEA,IAAM,IAAY,QACV,EAAM,aAAa,KAAA,KAAa,EAAM,MAAM,SAAS,KAAK,IAAI,EAAM,UAAU,CAAC,CACvF,GAEM,IAAc,QAAgB,EAAU,QAAQ,EAAM,MAAM,MAAM,GAAG,EAAE,IAAI,CAAC,CAAE,GAK9E,IAAe,QACnB,EAAU,QAAQ,CAAC,EAAM,MAAM,IAAsB,GAAG,EAAM,MAAM,MAAM,EAAE,CAAC,IAAI,EAAM,KACzF;yBAIE,EAoCM,OAAA;GApCD,OAAM;GAAgB,cAAY,EAAA,CAAA;MACrC,EAkCK,MAlCL,GAkCK,EAAA,EAAA,EAAA,GAjCH,EAgCW,GAAA,MAAA,EAhCuB,EAAA,QAAhB,GAAM,wBAA8B,EAAK,KAAA,GAAA,CAC/C,EAAA,SAAa,MAAK,KAAA,EAAA,GAA5B,EAmBK,MAnBL,GAmBK,CAlBH,EAAmF,GAAnF,EAAmF,EAA5E,OAAM,yBAAwB,GAAA,EAAA,SAAA,GAAA,GAAS,EAAA,CAAA,CAAS,CAAC,EAAA,aAAa,GAAA,EAAG,UAAA,GAAQ,CAAA,GAAA,MAAA,EAAA,GAChF,EAgBQ,GAAA,MAAA;GAfK,SAAO,GAMd,EANkB,sBAAY,CAChC,EAKE,GALF,EAKE;IAJA,MAAK;IACJ,OAAO,EAAA;IACP,MAAM,EAAA,CAAA;uBACC,CAAY,GAAA,MAAA,IAAA,CAAA,SAAA,MAAA,CAAA,CAAA,CAAA;oBAIO,EAAA,EAAA,EAAA,GAD/B,EAME,GAAA,MAAA,EALiB,EAAA,QAAV,YADT,EAME,GAAA;IAJC,KAAK,EAAO;IACZ,MAAM,EAAO;IACb,OAAO,EAAO;IACd,cAAY,EAAO;;;;;;;qBAI1B,EAUK,MAVL,GAUK,CATH,EAAmF,GAAnF,EAAmF,EAA5E,OAAM,yBAAwB,GAAA,EAAA,SAAA,GAAA,GAAS,EAAA,CAAA,CAAS,CAAC,EAAA,aAAa,GAAA,EAAG,UAAA,GAAQ,CAAA,GAAA,MAAA,EAAA,GAChF,EAOI,KAAA;GANF,OAAM;GACL,MAAM,EAAK;GACX,gBAAc,EAAU,CAAI,IAAA,SAAa,KAAA;MAE7B,EAAK,QAAA,EAAA,GAAlB,EAAwD,GAAxD,EAAwD;;;KAAxB,EAAA,CAAA,CAAS,CAAC,EAAK,IAAI,CAAA,GAAA,MAAA,EAAA,KAAA,EAAA,IAAA,EAAA,GAAA,EAAK,MACxD,EAAG,EAAK,KAAK,GAAA,CAAA,CAAA,GAAA,GAAA,CAAA,CAAA,CAAA,CAAA,GAAA,EAAA"}
|
|
1
|
+
{"version":3,"file":"VBreadcrumb.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/VBreadcrumb/VBreadcrumb.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @ssr @core\n/**\n * The path leading to the page being read, from the broadest section down to the current\n * one: a `<nav>` holding an `<ol>`, built entirely from the `items` prop. Nothing is read\n * from the browser, so the server and the client render the same thing.\n *\n * The separators are decorative `aria-hidden` icons, and the first is removed in CSS rather\n * than by a condition in the markup. The current page is found by comparing each address\n * with `currentPath`, carries `aria-current=\"page\"` and stays a working link, as the ARIA\n * practices recommend. Past `maxItems`, the middle segments fold into a VMenu behind an \"…\".\n */\n\nimport { computed } 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 { more_horiz as moreHorizIcon } from '../VIcon/icons/more_horiz'\nimport type { IconSource } from '../VIcon/types'\nimport VIconButton from '../VIconButton/VIconButton.vue'\nimport VMenu from '../VMenu/VMenu.vue'\nimport VMenuItem from '../VMenu/VMenuItem.vue'\n\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useMessages } from '../../i18n/state'\n\nexport interface BreadcrumbItem {\n /** The text shown for this segment. */\n label: string\n /**\n * Where the segment leads. It is also the value compared with `currentPath` to\n * decide which segment is the current page.\n */\n href: string\n /**\n * An icon placed before the label: an icon name, or an explicit render\n * (`{ src: '/logo.svg' }`, `{ component }`…). A string is always a name.\n */\n icon?: IconSource\n}\n\ninterface BreadcrumbProps {\n /** The segments of the trail, ordered from the most general down to the deepest. */\n items: BreadcrumbItem[]\n /**\n * The name screen readers announce for this navigation. It falls back to the\n * wording of the DS dictionary, in the current language.\n */\n label?: string\n /**\n * The address of the page being displayed. The segment whose `href` matches it is\n * the current one, even when it is folded into the menu. A trailing slash, a query and\n * a hash on either side make no difference, so a router's full path can be passed as is.\n */\n currentPath?: string\n /**\n * The icon drawn between two segments: an icon name, or an explicit render,\n * exactly like an item's `icon`. It is mirrored in a right-to-left page.\n */\n separatorIcon?: IconSource\n /**\n * The length past which the trail folds: only the first segment, an \"…\" button and\n * the last two remain, the button opening a menu that lists the hidden segments\n * alone. Below 3 there would be nothing left to fold, so 3 is the effective\n * minimum.\n */\n maxItems?: number\n /**\n * The name screen readers announce for the \"…\" button. It falls back to the\n * wording of the DS dictionary.\n */\n ellipsisLabel?: string\n}\n\nconst props = withDefaults(defineProps<BreadcrumbProps>(), {\n label: undefined,\n currentPath: undefined,\n separatorIcon: () => chevronRightIcon,\n maxItems: undefined,\n ellipsisLabel: undefined,\n})\n\nconst m = useMessages()\nconst ariaLabel = useAriaLabel(() => props.label ?? m.value.breadcrumb.label)\nconst resolvedEllipsisLabel = computed(() => props.ellipsisLabel ?? m.value.breadcrumb.ellipsis)\n\n/**\n * Drops the query, the hash and a trailing slash, so that `/docs`, `/docs/` and a\n * router's full path `/docs?tab=2#intro` compare as the same page; the root `/` is left\n * alone. Pure string handling, hence safe to run on the server.\n */\nfunction normalize(path: string): string {\n const bare = path.replace(/[?#].*$/, '')\n return bare.length > 1 && bare.endsWith('/') ? bare.slice(0, -1) : bare\n}\n\n// Normalized once per change of the prop rather than once per segment on every render.\nconst normalizedCurrent = computed(() =>\n props.currentPath === undefined ? undefined : normalize(props.currentPath),\n)\n\n// @a11y\n// This is what feeds `aria-current=\"page\"`, the only marker telling assistive technology\n// where the trail ends, the folded segments of the menu included.\nfunction isCurrent(item: BreadcrumbItem): boolean {\n return normalizedCurrent.value !== undefined && normalize(item.href) === normalizedCurrent.value\n}\n\nconst truncated = computed(\n () => props.maxItems !== undefined && props.items.length > Math.max(props.maxItems, 3),\n)\n/** The segments folded into the menu: everything between the first and the last two. */\nconst hiddenItems = computed(() => (truncated.value ? props.items.slice(1, -2) : []))\n/**\n * The segments actually rendered in the list — when the trail is folded, the first\n * one followed by the last two.\n */\nconst visibleItems = computed(() =>\n truncated.value ? [props.items[0] as BreadcrumbItem, ...props.items.slice(-2)] : props.items,\n)\n</script>\n\n<template>\n <nav class=\"v-breadcrumb\" :aria-label=\"ariaLabel\">\n <ol class=\"v-breadcrumb-list\">\n <template v-for=\"(item, index) in visibleItems\" :key=\"item.href\">\n <li v-if=\"truncated && index === 1\" class=\"v-breadcrumb-item v-breadcrumb-ellipsis\">\n <VIcon class=\"v-breadcrumb-separator\" v-bind=\"iconProps(separatorIcon)\" mirrored />\n <VMenu>\n <template #trigger=\"{ triggerProps }\">\n <VIconButton\n size=\"sm\"\n :label=\"resolvedEllipsisLabel\"\n :icon=\"moreHorizIcon\"\n v-bind=\"triggerProps\"\n />\n </template>\n <VMenuItem\n v-for=\"hidden in hiddenItems\"\n :key=\"hidden.href\"\n :href=\"hidden.href\"\n :label=\"hidden.label\"\n :icon-start=\"hidden.icon\"\n :selected=\"isCurrent(hidden)\"\n :aria-current=\"isCurrent(hidden) ? 'page' : undefined\"\n />\n </VMenu>\n </li>\n <li class=\"v-breadcrumb-item\">\n <VIcon class=\"v-breadcrumb-separator\" v-bind=\"iconProps(separatorIcon)\" mirrored />\n <a\n class=\"v-breadcrumb-link\"\n :href=\"item.href\"\n :aria-current=\"isCurrent(item) ? 'page' : undefined\"\n >\n <VIcon v-if=\"item.icon\" v-bind=\"iconProps(item.icon)\" />\n {{ item.label }}\n </a>\n </li>\n </template>\n </ol>\n </nav>\n</template>\n\n<style>\n@layer vectis.components {\n /* The icon context is set here rather than through `.v-control`, which is the usual\n route: a trail has no `size` prop and no height to speak of, so the size scale would\n bring a table of five steps to pick one value from. */\n .v-breadcrumb {\n --vectis-icon-size: var(--vectis-icon-size-sm);\n --vectis-icon-opsz: 20;\n }\n\n .v-breadcrumb-list {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: var(--vectis-space-2);\n margin: 0;\n padding: 0;\n list-style: none;\n font-family: var(--vectis-text-family);\n font-size: var(--vectis-text-body-md-size);\n }\n\n .v-breadcrumb-item {\n display: inline-flex;\n align-items: center;\n gap: var(--vectis-space-2);\n color: var(--vectis-color-text-muted);\n }\n\n /* TRAP — every item renders its own leading separator and the first one is hidden HERE,\n which is what keeps the template free of an index test. Delete this rule and the trail\n opens on a stray chevron; both child combinators are load-bearing too, so wrapping an\n item or the list in anything puts that chevron straight back. */\n .v-breadcrumb-list > .v-breadcrumb-item:first-child > .v-breadcrumb-separator {\n display: none;\n }\n\n .v-breadcrumb-separator {\n color: var(--vectis-color-text-subtle);\n }\n\n /* The corner is only ever seen on the focus ring, which follows it. It is the control\n radius capped at half a line, the row recipe of VSideNavigationItem with the line\n standing in for a control height the link does not have: a label that wraps keeps\n the corner of a one-line one under a pill override. */\n .v-breadcrumb-link {\n display: inline-flex;\n align-items: center;\n gap: var(--vectis-space-1);\n color: var(--vectis-color-text-muted);\n text-decoration: none;\n border-radius: min(var(--vectis-radius-interactive), 0.5lh);\n transition: color var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n\n .v-breadcrumb-link:hover {\n color: var(--vectis-color-text);\n text-decoration: underline;\n }\n\n .v-breadcrumb-link:focus-visible {\n outline: var(--vectis-focus-ring-width) solid var(--vectis-focus-ring-color);\n outline-offset: var(--vectis-focus-ring-offset);\n }\n\n .v-breadcrumb-link[aria-current='page'] {\n color: var(--vectis-color-text);\n font-weight: var(--vectis-text-label-weight);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-breadcrumb-link {\n transition: none;\n }\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;EA2EA,IAAM,IAAQ,GAQR,IAAI,EAAY,GAChB,IAAY,QAAmB,EAAM,SAAS,EAAE,MAAM,WAAW,KAAK,GACtE,IAAwB,QAAe,EAAM,iBAAiB,EAAE,MAAM,WAAW,QAAQ;EAO/F,SAAS,EAAU,GAAsB;GACvC,IAAM,IAAO,EAAK,QAAQ,WAAW,EAAE;GACvC,OAAO,EAAK,SAAS,KAAK,EAAK,SAAS,GAAG,IAAI,EAAK,MAAM,GAAG,EAAE,IAAI;EACrE;EAGA,IAAM,IAAoB,QACxB,EAAM,gBAAgB,KAAA,IAAY,KAAA,IAAY,EAAU,EAAM,WAAW,CAC3E;EAKA,SAAS,EAAU,GAA+B;GAChD,OAAO,EAAkB,UAAU,KAAA,KAAa,EAAU,EAAK,IAAI,MAAM,EAAkB;EAC7F;EAEA,IAAM,IAAY,QACV,EAAM,aAAa,KAAA,KAAa,EAAM,MAAM,SAAS,KAAK,IAAI,EAAM,UAAU,CAAC,CACvF,GAEM,IAAc,QAAgB,EAAU,QAAQ,EAAM,MAAM,MAAM,GAAG,EAAE,IAAI,CAAC,CAAE,GAK9E,IAAe,QACnB,EAAU,QAAQ,CAAC,EAAM,MAAM,IAAsB,GAAG,EAAM,MAAM,MAAM,EAAE,CAAC,IAAI,EAAM,KACzF;yBAIE,EAsCM,OAAA;GAtCD,OAAM;GAAgB,cAAY,EAAA,CAAA;MACrC,EAoCK,MApCL,GAoCK,EAAA,EAAA,EAAA,GAnCH,EAkCW,GAAA,MAAA,EAlCuB,EAAA,QAAhB,GAAM,wBAA8B,EAAK,KAAA,GAAA,CAC/C,EAAA,SAAa,MAAK,KAAA,EAAA,GAA5B,EAqBK,MArBL,GAqBK,CApBH,EAAmF,GAAnF,EAAmF,EAA5E,OAAM,yBAAwB,GAAA,EAAA,SAAA,GAAA,GAAS,EAAA,CAAA,CAAS,CAAC,EAAA,aAAa,GAAA,EAAG,UAAA,GAAQ,CAAA,GAAA,MAAA,EAAA,GAChF,EAkBQ,GAAA,MAAA;GAjBK,SAAO,GAMd,EANkB,sBAAY,CAChC,EAKE,GALF,EAKE;IAJA,MAAK;IACJ,OAAO,EAAA;IACP,MAAM,EAAA,CAAA;uBACC,CAAY,GAAA,MAAA,IAAA,CAAA,SAAA,MAAA,CAAA,CAAA,CAAA;oBAIO,EAAA,EAAA,EAAA,GAD/B,EAQE,GAAA,MAAA,EAPiB,EAAA,QAAV,YADT,EAQE,GAAA;IANC,KAAK,EAAO;IACZ,MAAM,EAAO;IACb,OAAO,EAAO;IACd,cAAY,EAAO;IACnB,UAAU,EAAU,CAAM;IAC1B,gBAAc,EAAU,CAAM,IAAA,SAAa,KAAA;;;;;;;;;qBAIlD,EAUK,MAVL,GAUK,CATH,EAAmF,GAAnF,EAAmF,EAA5E,OAAM,yBAAwB,GAAA,EAAA,SAAA,GAAA,GAAS,EAAA,CAAA,CAAS,CAAC,EAAA,aAAa,GAAA,EAAG,UAAA,GAAQ,CAAA,GAAA,MAAA,EAAA,GAChF,EAOI,KAAA;GANF,OAAM;GACL,MAAM,EAAK;GACX,gBAAc,EAAU,CAAI,IAAA,SAAa,KAAA;MAE7B,EAAK,QAAA,EAAA,GAAlB,EAAwD,GAAxD,EAAwD;;;KAAxB,EAAA,CAAA,CAAS,CAAC,EAAK,IAAI,CAAA,GAAA,MAAA,EAAA,KAAA,EAAA,IAAA,EAAA,GAAA,EAAK,MACxD,EAAG,EAAK,KAAK,GAAA,CAAA,CAAA,GAAA,GAAA,CAAA,CAAA,CAAA,CAAA,GAAA,EAAA"}
|