vectis-ui 0.10.0 → 0.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/VAccordion/VAccordion.js.map +1 -1
- package/dist/components/VAccordion/VAccordion.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VAccordion/VAccordionItem.d.ts +6 -21
- package/dist/components/VAccordion/VAccordionItem.js.map +1 -1
- package/dist/components/VAccordion/VAccordionItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VAccordion/context.js.map +1 -1
- package/dist/components/VAvatar/VAvatar.d.ts +2 -12
- package/dist/components/VAvatar/VAvatar.js.map +1 -1
- package/dist/components/VAvatar/VAvatar.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VAvatar/VAvatarGroup.d.ts +2 -2
- package/dist/components/VAvatar/VAvatarGroup.js.map +1 -1
- package/dist/components/VAvatar/VAvatarGroup.vue_vue_type_script_setup_true_lang.js +6 -6
- package/dist/components/VAvatar/VAvatarGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VAvatar/context.d.ts +1 -5
- package/dist/components/VAvatar/context.js.map +1 -1
- package/dist/components/VBadge/VBadge.d.ts +13 -27
- package/dist/components/VBadge/VBadge.js.map +1 -1
- package/dist/components/VBadge/VBadge.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VBreadcrumb/VBreadcrumb.d.ts +3 -9
- package/dist/components/VBreadcrumb/VBreadcrumb.js.map +1 -1
- package/dist/components/VBreadcrumb/VBreadcrumb.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VButton/VButton.d.ts +10 -17
- package/dist/components/VButton/VButton.js.map +1 -1
- package/dist/components/VButton/VButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VButton/VButtonGroup.d.ts +6 -15
- 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/VButton/context.d.ts +1 -9
- package/dist/components/VButton/context.js.map +1 -1
- package/dist/components/VCalendar/VCalendar.d.ts +9 -24
- package/dist/components/VCalendar/VCalendar.js.map +1 -1
- package/dist/components/VCalendar/VCalendar.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCalendar/VCalendarEvent.d.ts +4 -13
- 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.js.map +1 -1
- package/dist/components/VCalendar/VCalendarMonth.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCalendar/VCalendarTimeGrid.d.ts +1 -5
- package/dist/components/VCalendar/VCalendarTimeGrid.js.map +1 -1
- package/dist/components/VCalendar/VCalendarTimeGrid.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCalendar/VCalendarYear.js.map +1 -1
- package/dist/components/VCalendar/VCalendarYear.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCalendar/color.d.ts +1 -7
- package/dist/components/VCalendar/color.js.map +1 -1
- package/dist/components/VCalendar/edgeStep.d.ts +5 -15
- package/dist/components/VCalendar/edgeStep.js.map +1 -1
- package/dist/components/VCalendar/gesture.d.ts +12 -36
- package/dist/components/VCalendar/gesture.js.map +1 -1
- package/dist/components/VCalendar/keyboard.d.ts +5 -42
- package/dist/components/VCalendar/keyboard.js.map +1 -1
- package/dist/components/VCalendar/layout.d.ts +38 -199
- package/dist/components/VCalendar/layout.js.map +1 -1
- package/dist/components/VCalendar/timeGrid.d.ts +3 -25
- package/dist/components/VCalendar/timeGrid.js.map +1 -1
- package/dist/components/VCalendar/types.d.ts +6 -23
- package/dist/components/VCarousel/VCarousel.d.ts +25 -96
- package/dist/components/VCarousel/VCarousel.js.map +1 -1
- package/dist/components/VCarousel/VCarousel.vue_vue_type_script_setup_true_lang.js +6 -6
- package/dist/components/VCarousel/VCarousel.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCarousel/VCarouselItem.d.ts +1 -6
- 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.js.map +1 -1
- package/dist/components/VCheckbox/VCheckbox.d.ts +1 -5
- package/dist/components/VCheckbox/VCheckbox.js.map +1 -1
- package/dist/components/VCheckbox/VCheckbox.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VChip/VChip.d.ts +2 -8
- package/dist/components/VChip/VChip.js.map +1 -1
- package/dist/components/VChip/VChip.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCombobox/VCombobox.d.ts +21 -59
- package/dist/components/VCombobox/VCombobox.js.map +1 -1
- package/dist/components/VCombobox/VCombobox.vue_vue_type_script_setup_true_lang.js +117 -119
- package/dist/components/VCombobox/VCombobox.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCombobox/VComboboxGroup.js.map +1 -1
- package/dist/components/VCombobox/VComboboxGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCombobox/VComboboxOption.js.map +1 -1
- package/dist/components/VCombobox/VComboboxOption.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCombobox/VComboboxSeparator.js.map +1 -1
- package/dist/components/VCombobox/VComboboxSeparator.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCombobox/infiniteScroll.d.ts +4 -10
- package/dist/components/VCombobox/infiniteScroll.js.map +1 -1
- package/dist/components/VDataTable/VDataTable.d.ts +11 -36
- package/dist/components/VDataTable/VDataTable.js.map +1 -1
- package/dist/components/VDataTable/VDataTable.vue_vue_type_script_setup_true_lang.js +23 -20
- package/dist/components/VDataTable/VDataTable.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VDateInput/VDateInput.d.ts +12 -21
- package/dist/components/VDateInput/VDateInput.js.map +1 -1
- package/dist/components/VDateInput/VDateInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VDateInput/mask.d.ts +14 -59
- package/dist/components/VDateInput/mask.js.map +1 -1
- package/dist/components/VDatePicker/VDatePicker.d.ts +6 -12
- package/dist/components/VDatePicker/VDatePicker.js.map +1 -1
- package/dist/components/VDatePicker/VDatePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VDatePicker/keyboard.d.ts +10 -42
- package/dist/components/VDatePicker/keyboard.js.map +1 -1
- package/dist/components/VDatePicker/names.d.ts +8 -22
- package/dist/components/VDatePicker/names.js.map +1 -1
- package/dist/components/VDialog/VDialog.d.ts +5 -10
- package/dist/components/VDialog/VDialog.js.map +1 -1
- package/dist/components/VDialog/VDialog.vue_vue_type_script_setup_true_lang.js +51 -53
- package/dist/components/VDialog/VDialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VDialog/VDialogAlert.d.ts +2 -3
- package/dist/components/VDialog/VDialogAlert.js.map +1 -1
- package/dist/components/VDialog/VDialogAlert.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VFileInput/VFileInput.d.ts +11 -37
- package/dist/components/VFileInput/VFileInput.js.map +1 -1
- package/dist/components/VFileInput/VFileInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VFileInput/truncate.d.ts +3 -23
- package/dist/components/VFileInput/truncate.js.map +1 -1
- package/dist/components/VFilePicker/VFilePicker.d.ts +15 -65
- package/dist/components/VFilePicker/VFilePicker.js.map +1 -1
- package/dist/components/VFilePicker/VFilePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VFilePicker/fileKind.js.map +1 -1
- package/dist/components/VHotkeys/VHotkeys.d.ts +6 -15
- package/dist/components/VHotkeys/VHotkeys.js.map +1 -1
- package/dist/components/VHotkeys/VHotkeys.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VHotkeys/platform.d.ts +10 -49
- package/dist/components/VHotkeys/platform.js.map +1 -1
- package/dist/components/VIcon/VIcon.d.ts +7 -19
- 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 +5 -19
- package/dist/components/VIcon/iconProps.js.map +1 -1
- package/dist/components/VIcon/resolver.d.ts +15 -43
- package/dist/components/VIcon/resolver.js.map +1 -1
- package/dist/components/VIcon/types.d.ts +7 -34
- package/dist/components/VIconButton/VIconButton.d.ts +2 -3
- 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 +14 -29
- package/dist/components/VInput/VInput.js.map +1 -1
- package/dist/components/VInput/VInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VInput/VInputGroup.js.map +1 -1
- package/dist/components/VInput/VInputGroup.vue_vue_type_script_setup_true_lang.js +34 -50
- package/dist/components/VInput/VInputGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VInput/context.js.map +1 -1
- package/dist/components/VInputOTP/VInputOTP.d.ts +8 -16
- package/dist/components/VInputOTP/VInputOTP.js.map +1 -1
- package/dist/components/VInputOTP/VInputOTP.vue_vue_type_script_setup_true_lang.js +55 -63
- package/dist/components/VInputOTP/VInputOTP.vue_vue_type_script_setup_true_lang.js.map +1 -1
- 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.d.ts +1 -6
- package/dist/components/VMenu/VMenuGroup.js.map +1 -1
- package/dist/components/VMenu/VMenuGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VMenu/VMenuItem.d.ts +0 -5
- package/dist/components/VMenu/VMenuItem.js.map +1 -1
- package/dist/components/VMenu/VMenuItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VMenu/VMenuPanel.d.ts +1 -6
- package/dist/components/VMenu/VMenuPanel.js.map +1 -1
- package/dist/components/VMenu/VMenuPanel.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/components/VMenu/VMenuPanel.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VMenu/VMenuSeparator.js.map +1 -1
- package/dist/components/VMenu/VMenuSeparator.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VMenu/context.d.ts +3 -11
- package/dist/components/VMenu/context.js.map +1 -1
- package/dist/components/VPagination/VPagination.d.ts +9 -20
- package/dist/components/VPagination/VPagination.js.map +1 -1
- package/dist/components/VPagination/VPagination.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VPopover/VPopover.d.ts +7 -18
- package/dist/components/VPopover/VPopover.js.map +1 -1
- package/dist/components/VPopover/VPopover.vue_vue_type_script_setup_true_lang.js +23 -27
- package/dist/components/VPopover/VPopover.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VProgressCircular/VProgressCircular.d.ts +2 -6
- 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.d.ts +4 -15
- 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.d.ts +1 -5
- package/dist/components/VRadio/VRadio.js.map +1 -1
- package/dist/components/VRadio/VRadio.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSeparator/VSeparator.d.ts +2 -15
- 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 +1 -1
- package/dist/components/VSideNavigation/VSideNavigation.js.map +1 -1
- package/dist/components/VSideNavigation/VSideNavigation.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSideNavigation/VSideNavigationGroup.d.ts +1 -5
- package/dist/components/VSideNavigation/VSideNavigationGroup.js.map +1 -1
- package/dist/components/VSideNavigation/VSideNavigationGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSideNavigation/VSideNavigationItem.d.ts +1 -5
- package/dist/components/VSideNavigation/VSideNavigationItem.js.map +1 -1
- package/dist/components/VSideNavigation/VSideNavigationItem.vue_vue_type_script_setup_true_lang.js +80 -75
- package/dist/components/VSideNavigation/VSideNavigationItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSideNavigation/VSideNavigationSeparator.js.map +1 -1
- package/dist/components/VSideNavigation/context.js.map +1 -1
- package/dist/components/VSkeletonLoader/VSkeletonLoader.d.ts +6 -19
- package/dist/components/VSkeletonLoader/VSkeletonLoader.js.map +1 -1
- package/dist/components/VSkeletonLoader/VSkeletonLoader.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSlider/VSlider.d.ts +5 -13
- package/dist/components/VSlider/VSlider.js.map +1 -1
- package/dist/components/VSlider/VSlider.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSnackbar/VSnackbar.js.map +1 -1
- package/dist/components/VSnackbar/VSnackbar.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSnackbar/state.d.ts +4 -17
- package/dist/components/VSnackbar/state.js.map +1 -1
- package/dist/components/VSpinner/VSpinner.d.ts +3 -5
- 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.js.map +1 -1
- package/dist/components/VSwitch/VSwitch.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTabs/VTab.d.ts +1 -5
- package/dist/components/VTabs/VTab.js.map +1 -1
- package/dist/components/VTabs/VTab.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTabs/VTabPanel.js.map +1 -1
- package/dist/components/VTabs/VTabPanel.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTabs/VTabs.d.ts +5 -17
- package/dist/components/VTabs/VTabs.js.map +1 -1
- package/dist/components/VTabs/VTabs.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTabs/context.js.map +1 -1
- package/dist/components/VTextarea/VTextarea.d.ts +13 -20
- package/dist/components/VTextarea/VTextarea.js.map +1 -1
- package/dist/components/VTextarea/VTextarea.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTimeInput/VTimeInput.d.ts +8 -21
- package/dist/components/VTimeInput/VTimeInput.js.map +1 -1
- package/dist/components/VTimeInput/VTimeInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTimeInput/search.d.ts +3 -34
- package/dist/components/VTimeInput/search.js.map +1 -1
- package/dist/components/VTimePicker/VTimePicker.d.ts +9 -31
- package/dist/components/VTimePicker/VTimePicker.js.map +1 -1
- package/dist/components/VTimePicker/VTimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTimePicker/limits.d.ts +18 -45
- package/dist/components/VTimePicker/limits.js.map +1 -1
- package/dist/components/VToast/VToast.js.map +1 -1
- 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.map +1 -1
- package/dist/components/VToast/state.d.ts +2 -7
- package/dist/components/VToast/state.js.map +1 -1
- package/dist/components/VToggle/VToggle.d.ts +5 -9
- package/dist/components/VToggle/VToggle.js.map +1 -1
- package/dist/components/VToggle/VToggle.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VToggle/VToggleItem.d.ts +1 -9
- package/dist/components/VToggle/VToggleItem.js.map +1 -1
- package/dist/components/VToggle/VToggleItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VToggle/context.js.map +1 -1
- package/dist/components/VTooltip/VTooltip.d.ts +3 -16
- package/dist/components/VTooltip/VTooltip.js.map +1 -1
- package/dist/components/VTooltip/VTooltip.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/components/VTooltip/VTooltip.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTypography/VTypography.d.ts +4 -8
- 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.map +1 -1
- package/dist/composables/useClearable.d.ts +2 -8
- package/dist/composables/useClearable.js.map +1 -1
- package/dist/composables/useControlShape.js.map +1 -1
- package/dist/composables/useDetailsOpen.d.ts +2 -10
- package/dist/composables/useDetailsOpen.js.map +1 -1
- package/dist/composables/useFieldIds.js.map +1 -1
- package/dist/composables/useFieldPanel.d.ts +4 -17
- package/dist/composables/useFieldPanel.js.map +1 -1
- package/dist/composables/useFileDrop.js.map +1 -1
- package/dist/composables/useFileField.d.ts +1 -5
- package/dist/composables/useFileField.js.map +1 -1
- package/dist/composables/useFocusoutDismiss.js.map +1 -1
- package/dist/composables/useIconClickHandlers.d.ts +4 -19
- package/dist/composables/useIconClickHandlers.js.map +1 -1
- package/dist/composables/useInertLink.d.ts +1 -1
- package/dist/composables/useInertLink.js.map +1 -1
- package/dist/composables/useLiveAnnouncer.js.map +1 -1
- package/dist/composables/useMaskedField.d.ts +12 -27
- package/dist/composables/useMaskedField.js.map +1 -1
- package/dist/composables/usePopover.d.ts +3 -11
- package/dist/composables/usePopover.js.map +1 -1
- package/dist/composables/useProgressValue.js.map +1 -1
- package/dist/composables/useRootAttrs.d.ts +0 -9
- package/dist/composables/useRootAttrs.js +11 -4
- package/dist/composables/useRootAttrs.js.map +1 -1
- package/dist/composables/useSlotNodes.d.ts +3 -14
- package/dist/composables/useSlotNodes.js.map +1 -1
- package/dist/composables/useTextLimit.d.ts +4 -16
- package/dist/composables/useTextLimit.js.map +1 -1
- package/dist/composables/useTimer.d.ts +2 -15
- package/dist/composables/useTimer.js.map +1 -1
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/fr.js.map +1 -1
- package/dist/i18n/state.d.ts +9 -38
- package/dist/i18n/state.js.map +1 -1
- package/dist/i18n/types.d.ts +19 -81
- package/dist/icons.d.ts +2 -12
- package/dist/styles.css +1 -1
- package/dist/tokens/css.d.ts +3 -16
- package/dist/tokens/css.js.map +1 -1
- package/dist/tokens/index.d.ts +5 -0
- package/dist/tokens/index.js.map +1 -1
- package/dist/tokens/primitives.js.map +1 -1
- package/dist/tokens/semantic.d.ts +6 -23
- package/dist/tokens/semantic.js +5 -0
- package/dist/tokens/semantic.js.map +1 -1
- package/dist/tokens/themes/dark.js.map +1 -1
- package/dist/tokens/types.d.ts +2 -12
- package/dist/tokens/types.js.map +1 -1
- package/dist/tokens.json +14 -0
- package/dist/types.d.ts +3 -21
- package/dist/utils/array.d.ts +2 -4
- package/dist/utils/array.js.map +1 -1
- package/dist/utils/arrowNav.d.ts +2 -26
- package/dist/utils/arrowNav.js.map +1 -1
- package/dist/utils/chip.d.ts +1 -8
- package/dist/utils/chip.js.map +1 -1
- package/dist/utils/clock.d.ts +16 -39
- package/dist/utils/clock.js.map +1 -1
- package/dist/utils/css.d.ts +5 -16
- package/dist/utils/css.js.map +1 -1
- package/dist/utils/date.d.ts +17 -60
- package/dist/utils/date.js.map +1 -1
- package/dist/utils/direction.d.ts +2 -9
- package/dist/utils/direction.js.map +1 -1
- package/dist/utils/env.d.ts +2 -15
- package/dist/utils/env.js.map +1 -1
- package/dist/utils/file.d.ts +8 -46
- package/dist/utils/file.js.map +1 -1
- package/dist/utils/focus.d.ts +1 -14
- package/dist/utils/focus.js +1 -6
- package/dist/utils/focus.js.map +1 -1
- package/dist/utils/hostWarns.d.ts +3 -8
- package/dist/utils/hostWarns.js.map +1 -1
- package/dist/utils/ids.d.ts +2 -7
- package/dist/utils/ids.js.map +1 -1
- package/dist/utils/matcher.d.ts +1 -8
- package/dist/utils/matcher.js.map +1 -1
- package/dist/utils/memo.d.ts +1 -11
- package/dist/utils/memo.js.map +1 -1
- package/dist/utils/number.d.ts +1 -7
- package/dist/utils/number.js.map +1 -1
- package/dist/utils/text.d.ts +4 -23
- package/dist/utils/text.js.map +1 -1
- package/dist/utils/time.d.ts +4 -12
- package/dist/utils/time.js.map +1 -1
- package/dist/utils/vnode.d.ts +0 -10
- package/dist/utils/vnode.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { usePopover as e, usePopoverModel as t } from "../../composables/usePopover.js";
|
|
2
|
-
import { computed as n, createElementBlock as r, createElementVNode as i, defineComponent as a, mergeModels as o, mergeProps as s, openBlock as c, ref as l, renderSlot as u, unref as d, useId as f, useModel as p
|
|
2
|
+
import { computed as n, createElementBlock as r, createElementVNode as i, defineComponent as a, mergeModels as o, mergeProps as s, openBlock as c, ref as l, renderSlot as u, unref as d, useId as f, useModel as p } from "vue";
|
|
3
3
|
//#region src/components/VPopover/VPopover.vue?vue&type=script&setup=true&lang.ts
|
|
4
|
-
var
|
|
4
|
+
var m = ["data-trigger"], h = [
|
|
5
5
|
"id",
|
|
6
6
|
"popover",
|
|
7
7
|
"data-placement",
|
|
8
8
|
"data-match-trigger"
|
|
9
|
-
],
|
|
9
|
+
], g = /*@__PURE__*/ a({
|
|
10
10
|
inheritAttrs: !1,
|
|
11
11
|
__name: "VPopover",
|
|
12
12
|
props: /*@__PURE__*/ o({
|
|
@@ -31,41 +31,37 @@ var h = ["data-trigger"], g = [
|
|
|
31
31
|
}),
|
|
32
32
|
emits: ["update:open"],
|
|
33
33
|
setup(a, { expose: o }) {
|
|
34
|
-
let
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
let g = a, _ = p(a, "open"), v = l(null), y = f(), b = n(() => g.id ?? y), { shown: x, syncShown: S, show: C, hide: w } = e(v), T = n(() => ({
|
|
35
|
+
popovertarget: b.value,
|
|
36
|
+
"aria-expanded": _.value,
|
|
37
|
+
"aria-controls": b.value
|
|
38
|
+
})), E = n(() => ({ "--popover-anchor-name": g.anchor ?? "--popover-anchor" }));
|
|
39
|
+
function D(e) {
|
|
40
|
+
S(e), _.value = x.value;
|
|
37
41
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
})), k = n(() => ({ "--popover-anchor-name": _.anchor ?? "--popover-anchor" }));
|
|
43
|
-
function A(e) {
|
|
44
|
-
w(e), v.value = C.value;
|
|
45
|
-
}
|
|
46
|
-
return t(v, () => C.value, T, E), o({
|
|
47
|
-
show: T,
|
|
48
|
-
close: E,
|
|
49
|
-
el: b
|
|
42
|
+
return t(_, () => x.value, C, w), o({
|
|
43
|
+
show: C,
|
|
44
|
+
close: w,
|
|
45
|
+
el: v
|
|
50
46
|
}), (e, t) => (c(), r("span", {
|
|
51
47
|
class: "v-popover",
|
|
52
|
-
"data-trigger":
|
|
53
|
-
}, [u(e.$slots, "trigger", { triggerProps:
|
|
54
|
-
id:
|
|
48
|
+
"data-trigger": e.$slots.trigger ? "" : void 0
|
|
49
|
+
}, [u(e.$slots, "trigger", { triggerProps: T.value }), i("div", s({
|
|
50
|
+
id: b.value,
|
|
55
51
|
ref_key: "panelEl",
|
|
56
|
-
ref:
|
|
52
|
+
ref: v,
|
|
57
53
|
popover: a.mode,
|
|
58
54
|
class: ["v-overlay v-popover-panel v-floating", { "v-panel": !a.bare }],
|
|
59
55
|
"data-placement": a.placement,
|
|
60
56
|
"data-match-trigger": a.matchTrigger ? "" : void 0,
|
|
61
|
-
style:
|
|
57
|
+
style: E.value
|
|
62
58
|
}, e.$attrs, {
|
|
63
|
-
onBeforetoggle: t[0] ||= (...e) => d(
|
|
64
|
-
onToggle:
|
|
65
|
-
}), [u(e.$slots, "default")], 16,
|
|
59
|
+
onBeforetoggle: t[0] ||= (...e) => d(S) && d(S)(...e),
|
|
60
|
+
onToggle: D
|
|
61
|
+
}), [u(e.$slots, "default")], 16, h)], 8, m));
|
|
66
62
|
}
|
|
67
63
|
});
|
|
68
64
|
//#endregion
|
|
69
|
-
export {
|
|
65
|
+
export { g as default };
|
|
70
66
|
|
|
71
67
|
//# sourceMappingURL=VPopover.vue_vue_type_script_setup_true_lang.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VPopover.vue_vue_type_script_setup_true_lang.js","names":["$attrs"],"sources":["../../../src/components/VPopover/VPopover.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @core\n/**\n * A panel that floats above the page, next to whatever opened it. It is built on the\n * browser's own popover support and positions itself entirely in CSS, so there is no\n * positioning library involved and no JavaScript measuring anything.\n *\n * What it carries is deliberately only the PLUMBING every panel of the design system\n * needs: the popover element and how it opens, the bridge between the browser's own\n * open state and `v-model:open`, the anchoring and the placement, and the surface a\n * panel is drawn on — its background, border and shadow, which `bare` strips away.\n *\n * What it carries NOT is just as deliberate: no ARIA role, no keyboard, no focus\n * management and no rule about when to close. Those are exactly what makes a menu\n * different from a listbox or a tooltip, and they stay with the components building\n * on it — VTooltip, VCombobox, VDateInput, VTimeInput. Turning this into one panel\n * with a `role` prop would put all four sets of behaviour back into a single file.\n *\n * There are two ways of anchoring it, and they exclude one another:\n *\n * - the `#trigger` slot, where the component wraps the trigger and names that\n * wrapper as the anchor. The name is shared by every instance and confined to each\n * wrapper's own subtree, which is what makes a panel resolve ITS trigger rather\n * than the last one named on the page — a real risk, since an open panel moves to\n * the top layer and counts as coming after the whole document.\n * - the `anchor` prop, for a consumer that already owns its root and its control —\n * VCombobox and the pickers do. They name the anchor themselves and pass the name\n * in, and the wrapper then disappears from the layout entirely.\n *\n * The only JavaScript is the bridge between `v-model:open` and the browser's own\n * imperative popover methods.\n */\nimport { computed, ref, useId } from 'vue'\n\nimport { usePopover, usePopoverModel } from '../../composables/usePopover'\n\nexport type PopoverPlacement =\n | 'top'\n | 'top-start'\n | 'top-end'\n | 'bottom'\n | 'bottom-start'\n | 'bottom-end'\n | 'left'\n | 'left-start'\n | 'left-end'\n | 'right'\n | 'right-start'\n | 'right-end'\n\n/**\n * What the trigger has to carry for the browser to open the panel and for assistive\n * technology to know what it controls. It is the disclosure pattern and nothing more:\n * no role and no `aria-haspopup` are imposed, since only the consumer knows what kind\n * of panel it is opening.\n */\nexport type PopoverTriggerProps = {\n popovertarget: string\n 'aria-expanded': boolean\n 'aria-controls': string\n}\n\n/** Whether the browser dismisses the panel on its own. */\nexport type PopoverMode = 'auto' | 'manual'\n\ninterface PopoverProps {\n /**\n * The id of the panel, which the trigger points at. One is generated when none is\n * given, so this is only needed to tie the panel to something outside the\n * component.\n */\n id?: string\n /**\n * Where the panel is placed relative to its trigger. The browser flips it to the\n * opposite side by itself when there is not enough room.\n */\n placement?: PopoverPlacement\n /**\n * How the panel closes. `auto` lets the browser dismiss it on a click outside or on\n * Escape, and stack it with other panels; `manual` leaves everything to the\n * consumer, which is what a panel with its own focus and dismissal rules needs.\n */\n mode?: PopoverMode\n /**\n * The name of an anchor the consumer has set on its own control, written as a CSS\n * dashed identifier such as `--tooltip-anchor`. Supplying it replaces the internal\n * wrapper, which is the required route as soon as the trigger is a text input,\n * where the browser's own `popovertarget` attribute is not allowed.\n */\n anchor?: string\n /**\n * Strips the panel of the design system's surface: no background, no border, no\n * shadow and no rounded corners. It is what a panel whose content brings its own\n * asks for, as VDatePicker does.\n */\n bare?: boolean\n /**\n * Stops the panel being narrower than whatever it is anchored to. It is a FLOOR, so a\n * panel with a width of its own still grows past it rather than being clamped to the\n * trigger, which is what a list of long labels under a short field wants.\n */\n matchTrigger?: boolean\n}\n\nconst props = withDefaults(defineProps<PopoverProps>(), {\n id: undefined,\n placement: 'bottom-start',\n mode: 'auto',\n anchor: undefined,\n bare: false,\n matchTrigger: false,\n})\n\n/**\n * Whether the panel is showing. It starts closed and is BIDIRECTIONAL, fed from the DOM: in\n * `auto` mode the browser's own light dismiss writes back to it. Setting it opens and closes\n * the panel; a consumer needing the change to be synchronous uses the exposed `show`/`close`\n * instead, which is what VTooltip and the pickers do.\n */\nconst open = defineModel<boolean>('open', { default: false })\n\nconst slots = defineSlots<{\n /**\n * The element that opens the panel. Bind the `triggerProps` it receives onto a\n * button of your own: that is what wires the two together.\n */\n trigger?(props: { triggerProps: PopoverTriggerProps }): unknown\n /** What the panel contains. */\n default(): unknown\n}>()\n\n/*\n * Everything the consumer passes — the ARIA role, the aria-*, the data-*, class,\n * style and the listeners — goes on the PANEL rather than on the anchoring wrapper,\n * because the panel is what the consumer is really describing and styling.\n *\n * This is a deliberate departure from the design system's usual wrapper pattern,\n * which keeps class and style on the root; `useRootAttrs` therefore does not apply\n * here.\n */\ndefineOptions({ inheritAttrs: false })\n\nconst panelEl = ref<HTMLElement | null>(null)\nconst generatedId = useId()\nconst panelId = computed(() => props.id ?? generatedId)\n\n// The open state and the guards that keep the calls idempotent live in usePopover.\n// The invariant to respect here: `shown` is fed by the panel's own events and never\n// assigned by hand, so the browser stays the source of truth — it can close the panel\n// without asking us.\nconst { shown, syncShown, show, hide } = usePopover(panelEl)\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 hasTrigger() {\n return slots.trigger !== undefined\n}\n\nconst triggerProps = computed<PopoverTriggerProps>(() => ({\n popovertarget: panelId.value,\n 'aria-expanded': open.value,\n 'aria-controls': panelId.value,\n}))\n\n// Both anchoring modes are served by one CSS declaration: the panel reads this variable,\n// which names either the consumer's anchor or the wrapper's own.\n//\n// TRAP — it is set inline in BOTH modes, never left to a fallback. A custom property\n// INHERITS: left unset in the `#trigger` mode, the panel read whatever an ancestor had\n// set — a VPopover placed in VDateInput's `#footer` inherited the date field's anchor and\n// opened under the field instead of under its own trigger, with no error anywhere.\nconst panelStyle = computed(() => ({\n '--popover-anchor-name': props.anchor ?? '--popover-anchor',\n}))\n\nfunction onToggle(event: Event) {\n syncShown(event)\n open.value = shown.value\n}\n\nusePopoverModel(open, () => shown.value, show, hide)\n\n// The imperative counterpart of `v-model:open`, for a consumer whose opening must be\n// SYNCHRONOUS: the model would insert a tick, which is exactly what VTooltip's delay and\n// the pickers' focus frame cannot afford.\ndefineExpose({\n /** Opens the panel at once, without waiting for the model to come round. */\n show,\n /** Closes it at once. Safe to call on a panel that is already closed. */\n close: hide,\n /** The panel element itself, which is the popover. */\n el: panelEl,\n})\n</script>\n\n<template>\n <span class=\"v-popover\" :data-trigger=\"hasTrigger() ? '' : undefined\">\n <slot name=\"trigger\" :trigger-props=\"triggerProps\" />\n <div\n :id=\"panelId\"\n ref=\"panelEl\"\n :popover=\"mode\"\n class=\"v-overlay v-popover-panel v-floating\"\n :class=\"{ 'v-panel': !bare }\"\n :data-placement=\"placement\"\n :data-match-trigger=\"matchTrigger ? '' : undefined\"\n :style=\"panelStyle\"\n v-bind=\"$attrs\"\n @beforetoggle=\"syncShown\"\n @toggle=\"onToggle\"\n >\n <slot />\n </div>\n </span>\n</template>\n\n<style>\n@layer vectis.components {\n /*\n * Without a trigger the wrapper has nothing to wrap, so `display: contents` takes\n * it out of the layout entirely — the panel is positioned against the viewport and\n * does not depend on it. Left as an empty inline-block it would still create a line\n * box, and therefore add height, inside every component using this route.\n */\n .v-popover {\n display: contents;\n }\n\n /*\n * With a trigger the wrapper must generate a box, since that box is the ANCHOR —\n * which is why `display: contents` stops at the rule above. It is FLEX rather than\n * inline-block, the `.v-badge-host` and `.v-tooltip` form: both are inline-level\n * atomic boxes, so text flows around them identically, but an inline-block opens an\n * inline formatting context for the trigger, which then lands on a line box and adds\n * the strut's descender to the wrapper. The wrapper being the anchor, that offsets\n * the panel as well as the row.\n *\n * `align-items: center` covers the rest: a wrapper stretched by a parent in\n * `align-items: stretch` would otherwise stretch the trigger with it, where the\n * inline-block form left it at its natural height.\n */\n .v-popover[data-trigger] {\n display: inline-flex;\n align-items: center;\n anchor-name: --popover-anchor;\n /* Confining the name to this subtree is indispensable, not tidy: an open panel\n moves to the top layer, where anchor resolution treats it as coming after the\n whole document. Without the confinement every panel on the page would attach\n itself to the LAST wrapper carrying this name. */\n anchor-scope: --popover-anchor;\n }\n\n /*\n * The panel gets this one declaration and no dimension whatsoever. Widths, heights\n * and overflow differ from one consumer to the next, and since each component ships\n * its own stylesheet, a declaration here would sit at equal specificity with theirs\n * — leaving the winner to whichever order the consumer's bundler happens to\n * produce.\n */\n .v-popover-panel {\n position-anchor: var(--popover-anchor-name);\n }\n\n /*\n * A `bare` panel is bare of the BROWSER's decoration too. The UA sheet gives every\n * `[popover]` a border, a padding, a Canvas background and `overflow: auto`, and `.v-panel`\n * is what normally overrides them: without it they came back, a solid line and a white box\n * around content promised \"no background, no border\".\n *\n * TRAP — `:where()` keeps this at (0,1,0). A bare consumer restyles its panel through the\n * `.v-popover-panel.v-x-panel` compound (VTooltip), at (0,2,0), which must win; a (0,2,0)\n * rule here would tie with it across two sheets.\n */\n .v-popover-panel:where(:not(.v-panel)) {\n border: none;\n padding: 0;\n background: none;\n color: inherit;\n overflow: visible;\n }\n\n /*\n * The one dimension this sheet does carry, and it is a FLOOR rather than a size: a panel\n * may not come out narrower than what it is anchored to. It is written here rather than in\n * each consumer because `anchor-size()` resolves against `position-anchor`, which is the\n * declaration above — the same reason the anchoring itself lives here.\n *\n * A minimum beats a maximum, so a consumer's own `max-inline-size` does not clamp it: a\n * trigger wider than the ceiling widens the panel past it, which is intended. VMenu carries\n * the twin of this rule, being deliberately outside VPopover, and answers to the same word.\n */\n .v-popover-panel[data-match-trigger] {\n min-inline-size: anchor-size(width);\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwGA,IAAM,IAAQ,GAeR,IAAO,EAAoB,GAAC,MAA0B,GAEtD,IAAQ,EAAA,GAqBR,IAAU,EAAwB,IAAI,GACtC,IAAc,EAAM,GACpB,IAAU,QAAe,EAAM,MAAM,CAAW,GAMhD,EAAE,UAAO,cAAW,SAAM,YAAS,EAAW,CAAO;EAI3D,SAAS,IAAa;GACpB,OAAO,EAAM,YAAY,KAAA;EAC3B;EAEA,IAAM,IAAe,SAAqC;GACxD,eAAe,EAAQ;GACvB,iBAAiB,EAAK;GACtB,iBAAiB,EAAQ;EAC3B,EAAE,GASI,IAAa,SAAgB,EACjC,yBAAyB,EAAM,UAAU,mBAC3C,EAAE;EAEF,SAAS,EAAS,GAAc;GAE9B,AADA,EAAU,CAAK,GACf,EAAK,QAAQ,EAAM;EACrB;SAEA,EAAgB,SAAY,EAAM,OAAO,GAAM,CAAI,GAKnD,EAAa;GAEX;GAEA,OAAO;GAEP,IAAI;EACN,CAAC,mBAIC,EAiBO,QAAA;GAjBD,OAAM;GAAa,gBAAc,EAAU,IAAA,KAAU,KAAA;MACzD,EAAqD,EAAA,QAAA,WAAA,EAA/B,cAAe,EAAA,MAAY,CAAA,GACjD,EAcM,OAdN,EAcM;GAbH,IAAI,EAAA;YACD;GAAJ,KAAI;GACH,SAAS,EAAA;GACV,OAAK,CAAC,wCAAsC,EAAA,WAAA,CACtB,EAAA,KAAI,CAAA;GACzB,kBAAgB,EAAA;GAChB,sBAAoB,EAAA,eAAY,KAAQ,KAAA;GACxC,OAAO,EAAA;KACAA,EAAAA,QAAM;GACb,gBAAY,AAAA,EAAA,QAAA,GAAA,MAAE,EAAA,CAAA,KAAA,EAAA,CAAA,CAAA,CAAA,GAAA,CAAA;GACN;OAET,EAAQ,EAAA,QAAA,SAAA,CAAA,GAAA,IAAA,CAAA,CAAA,GAAA,GAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"VPopover.vue_vue_type_script_setup_true_lang.js","names":["$slots","$attrs"],"sources":["../../../src/components/VPopover/VPopover.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @core\n/**\n * Bridge native popover state to v-model while CSS anchors the panel. Roles, keyboard handling\n * and dismissal policy belong to the consuming widget.\n */\nimport { computed, ref, useId } from 'vue'\n\nimport { usePopover, usePopoverModel } from '../../composables/usePopover'\n\nexport type PopoverPlacement =\n | 'top'\n | 'top-start'\n | 'top-end'\n | 'bottom'\n | 'bottom-start'\n | 'bottom-end'\n | 'left'\n | 'left-start'\n | 'left-end'\n | 'right'\n | 'right-start'\n | 'right-end'\n\n/**\n * What the trigger has to carry for the browser to open the panel and for assistive technology\n * to know what it controls.\n */\nexport type PopoverTriggerProps = {\n popovertarget: string\n 'aria-expanded': boolean\n 'aria-controls': string\n}\n\n/** Whether the browser dismisses the panel on its own. */\nexport type PopoverMode = 'auto' | 'manual'\n\ninterface PopoverProps {\n /**\n * The id of the panel, which the trigger points at. One is generated when none is\n * given, so this is only needed to tie the panel to something outside the\n * component.\n */\n id?: string\n /**\n * Where the panel is placed relative to its trigger. The browser flips it to the\n * opposite side by itself when there is not enough room.\n */\n placement?: PopoverPlacement\n /** How the panel closes. */\n mode?: PopoverMode\n /**\n * The name of an anchor the consumer has set on its own control, written as a CSS\n * dashed identifier such as `--tooltip-anchor`. Supplying it replaces the internal\n * wrapper, which is the required route as soon as the trigger is a text input,\n * where the browser's own `popovertarget` attribute is not allowed.\n */\n anchor?: string\n /**\n * Strips the panel of the design system's surface: no background, no border, no\n * shadow and no rounded corners. It is what a panel whose content brings its own\n * asks for, as VDatePicker does.\n */\n bare?: boolean\n /** Stops the panel being narrower than whatever it is anchored to. */\n matchTrigger?: boolean\n}\n\nconst props = withDefaults(defineProps<PopoverProps>(), {\n id: undefined,\n placement: 'bottom-start',\n mode: 'auto',\n anchor: undefined,\n bare: false,\n matchTrigger: false,\n})\n\n/**\n * Whether the panel is showing. Setting it opens and closes the panel; a consumer needing the\n * change to be synchronous uses the exposed `show`/ `close` instead, which VTooltip and the\n * pickers do.\n */\nconst open = defineModel<boolean>('open', { default: false })\n\ndefineSlots<{\n /**\n * The element that opens the panel. Bind the `triggerProps` it receives onto a\n * button of your own: that is what wires the two together.\n */\n trigger?(props: { triggerProps: PopoverTriggerProps }): unknown\n /** What the panel contains. */\n default(): unknown\n}>()\n\n/*\n * Everything the consumer passes; the ARIA role, the aria-*, the data-*, class, style and the\n * listeners; goes on the PANEL rather than on the anchoring wrapper, because the panel is what\n * the consumer is really describing and styling. This is a deliberate departure from the design\n * system's usual wrapper pattern, which keeps class and style on the root; `useRootAttrs`\n * therefore does not apply here.\n */\ndefineOptions({ inheritAttrs: false })\n\nconst panelEl = ref<HTMLElement | null>(null)\nconst generatedId = useId()\nconst panelId = computed(() => props.id ?? generatedId)\n\n// The invariant to respect here: `shown` is fed by the panel's own events and never assigned by\n// hand, so the browser stays the source of truth; it can close the panel without asking us.\nconst { shown, syncShown, show, hide } = usePopover(panelEl)\n\nconst triggerProps = computed<PopoverTriggerProps>(() => ({\n popovertarget: panelId.value,\n 'aria-expanded': open.value,\n 'aria-controls': panelId.value,\n}))\n\n// Set the anchor explicitly in both trigger modes; an unset custom property would inherit an\n// ancestor popover's anchor.\nconst panelStyle = computed(() => ({\n '--popover-anchor-name': props.anchor ?? '--popover-anchor',\n}))\n\nfunction onToggle(event: Event) {\n syncShown(event)\n open.value = shown.value\n}\n\nusePopoverModel(open, () => shown.value, show, hide)\n\n// The imperative counterpart of `v-model:open`, for a consumer whose opening must be\n// SYNCHRONOUS: the model would insert a tick, which is exactly what VTooltip's delay and\n// the pickers' focus frame cannot afford.\ndefineExpose({\n /** Opens the panel at once, without waiting for the model to come round. */\n show,\n /** Closes it at once. Safe to call on a panel that is already closed. */\n close: hide,\n /** The panel element itself, which is the popover. */\n el: panelEl,\n})\n</script>\n\n<template>\n <span class=\"v-popover\" :data-trigger=\"$slots.trigger ? '' : undefined\">\n <slot name=\"trigger\" :trigger-props=\"triggerProps\" />\n <div\n :id=\"panelId\"\n ref=\"panelEl\"\n :popover=\"mode\"\n class=\"v-overlay v-popover-panel v-floating\"\n :class=\"{ 'v-panel': !bare }\"\n :data-placement=\"placement\"\n :data-match-trigger=\"matchTrigger ? '' : undefined\"\n :style=\"panelStyle\"\n v-bind=\"$attrs\"\n @beforetoggle=\"syncShown\"\n @toggle=\"onToggle\"\n >\n <slot />\n </div>\n </span>\n</template>\n\n<style>\n@layer vectis.components {\n /*\n * Without a trigger the wrapper has nothing to wrap, so `display: contents` takes it out of\n * the layout entirely; the panel is positioned against the viewport and does not depend on\n * it. Left as an empty inline-block it would still create a line box, and therefore add\n * height, inside every component using this route.\n */\n .v-popover {\n display: contents;\n }\n\n /*\n * With a trigger the wrapper must generate a box, since that box is the ANCHOR; which is why\n * `display: contents` stops at the rule above. It is FLEX rather than inline-block, the\n * `.v-badge-host` and `.v-tooltip` form: both are inline-level atomic boxes, so text flows\n * around them identically, but an inline-block opens an inline formatting context for the\n * trigger, which then lands on a line box and adds the strut's descender to the wrapper.\n */\n .v-popover[data-trigger] {\n display: inline-flex;\n align-items: center;\n anchor-name: --popover-anchor;\n /*\n * Without the confinement every panel on the page would attach itself to the last wrapper\n * carrying this name.\n */\n anchor-scope: --popover-anchor;\n }\n\n /*\n * Widths, heights and overflow differ from one consumer to the next, and since each component\n * ships its own stylesheet, a declaration here would sit at equal specificity with theirs;\n * leaving the winner to whichever order the consumer's bundler happens to produce.\n */\n .v-popover-panel {\n position-anchor: var(--popover-anchor-name);\n }\n\n /*\n * `:where()` keeps this at (0,1,0). A bare consumer restyles its panel through the\n * `.v-popover-panel.v-x-panel` compound (VTooltip), at (0,2,0), which must win; a (0,2,0)\n * rule here would tie with it across two sheets.\n */\n .v-popover-panel:where(:not(.v-panel)) {\n border: none;\n padding: 0;\n background: none;\n color: inherit;\n overflow: visible;\n }\n\n /*\n * It is written here rather than in each consumer because `anchor-size()` resolves against\n * `position-anchor`, which is the declaration above; the same reason the anchoring itself\n * lives here. A minimum beats a maximum, so a consumer's own `max-inline-size` does not clamp\n * it: a trigger wider than the ceiling widens the panel past it, which is intended.\n */\n .v-popover-panel[data-match-trigger] {\n min-inline-size: anchor-size(width);\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoEA,IAAM,IAAQ,GAcR,IAAO,EAAoB,GAAC,MAA0B,GAqBtD,IAAU,EAAwB,IAAI,GACtC,IAAc,EAAM,GACpB,IAAU,QAAe,EAAM,MAAM,CAAW,GAIhD,EAAE,UAAO,cAAW,SAAM,YAAS,EAAW,CAAO,GAErD,IAAe,SAAqC;GACxD,eAAe,EAAQ;GACvB,iBAAiB,EAAK;GACtB,iBAAiB,EAAQ;EAC3B,EAAE,GAII,IAAa,SAAgB,EACjC,yBAAyB,EAAM,UAAU,mBAC3C,EAAE;EAEF,SAAS,EAAS,GAAc;GAE9B,AADA,EAAU,CAAK,GACf,EAAK,QAAQ,EAAM;EACrB;SAEA,EAAgB,SAAY,EAAM,OAAO,GAAM,CAAI,GAKnD,EAAa;GAEX;GAEA,OAAO;GAEP,IAAI;EACN,CAAC,mBAIC,EAiBO,QAAA;GAjBD,OAAM;GAAa,gBAAcA,EAAAA,OAAO,UAAO,KAAQ,KAAA;MAC3D,EAAqD,EAAA,QAAA,WAAA,EAA/B,cAAe,EAAA,MAAY,CAAA,GACjD,EAcM,OAdN,EAcM;GAbH,IAAI,EAAA;YACD;GAAJ,KAAI;GACH,SAAS,EAAA;GACV,OAAK,CAAC,wCAAsC,EAAA,WAAA,CACtB,EAAA,KAAI,CAAA;GACzB,kBAAgB,EAAA;GAChB,sBAAoB,EAAA,eAAY,KAAQ,KAAA;GACxC,OAAO,EAAA;KACAC,EAAAA,QAAM;GACb,gBAAY,AAAA,EAAA,QAAA,GAAA,MAAE,EAAA,CAAA,KAAA,EAAA,CAAA,CAAA,CAAA,GAAA,CAAA;GACN;OAET,EAAQ,EAAA,QAAA,SAAA,CAAA,GAAA,IAAA,CAAA,CAAA,GAAA,GAAA,CAAA"}
|
|
@@ -22,10 +22,6 @@ interface ProgressCircularProps {
|
|
|
22
22
|
label?: string;
|
|
23
23
|
/** What counts as finished. The other end is always zero. */
|
|
24
24
|
max?: number;
|
|
25
|
-
/**
|
|
26
|
-
* Says that the progress cannot be measured: the ring turns continuously and the
|
|
27
|
-
* value is ignored.
|
|
28
|
-
*/
|
|
29
25
|
indeterminate?: boolean;
|
|
30
26
|
/** What the progress means, expressed as a colour. */
|
|
31
27
|
tone?: ProgressCircularTone;
|
|
@@ -35,9 +31,9 @@ interface ProgressCircularProps {
|
|
|
35
31
|
* and the dark one.
|
|
36
32
|
*/
|
|
37
33
|
color?: string;
|
|
38
|
-
/** The diameter, always
|
|
34
|
+
/** The diameter, always in PIXELS: `96` and `'96'` both give 96px. */
|
|
39
35
|
size?: number | string;
|
|
40
|
-
/** How thick the ring is, always
|
|
36
|
+
/** How thick the ring is, always in PIXELS: `8` and `'8'` both give 8px. */
|
|
41
37
|
thickness?: number | string;
|
|
42
38
|
/** Whether the ends of the drawn arc are rounded or cut square. */
|
|
43
39
|
shape?: ProgressCircularShape;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VProgressCircular.js","names":[],"sources":["../../../src/components/VProgressCircular/VProgressCircular.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Progress drawn as a ring, an SVG whose geometry is described entirely in CSS with no JS\n * computing anything.\n *\n * Two things make that possible. There is no `viewBox`, so one user unit is one pixel and\n * the circles take plain lengths — a fixed coordinate system would mean converting the\n * thickness into its units, hence knowing the ratio in code and recomputing it at every\n * change of size. And `pathLength=\"100\"` declares the outline 100 units long whatever its\n * real circumference, so the portion drawn is a percentage with no π anywhere.\n *\n * NAMING — pass a `label` saying what is progressing. The figure in the middle cannot\n * serve: `role=\"progressbar\"` makes its content presentational, so it is never announced.\n */\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useProgressValue } from '../../composables/useProgressValue'\nimport { useMessages } from '../../i18n/state'\nimport { px } from '../../utils/css'\n\n/** What the progress means, in colour. */\nexport type ProgressCircularTone = 'neutral' | 'accent' | 'danger' | 'success' | 'warning'\n\n/** How the arc ends. */\nexport type ProgressCircularShape = 'rounded' | 'square'\n\n/** What the default slot receives. */\nexport interface ProgressCircularSlotProps {\n /** The value, brought back into the range. */\n value: number\n /** The bound, zero or more. */\n max: number\n /** How far along it is, as a percentage and unrounded. */\n percent: number\n}\n\ninterface ProgressCircularProps {\n /** How far along it is. Anything outside the range is brought back into it. */\n value?: number\n /**\n * What is progressing, in words, for screen readers. It draws nothing on screen, and falls\n * back to the design system dictionary; an `aria-label` or `aria-labelledby` of your own\n * takes precedence over it.\n */\n label?: string\n /** What counts as finished. The other end is always zero. */\n max?: number\n /**\n * Says that the progress cannot be measured: the ring turns continuously and the\n * value is ignored.\n */\n indeterminate?: boolean\n /** What the progress means, expressed as a colour. */\n tone?: ProgressCircularTone\n /**\n * A colour of your own (hex, CSS name or `oklch()`), which replaces the tone. The\n * unfilled ring's shade is derived from it against the theme, so it follows the light\n * and the dark one.\n */\n color?: string\n /** The diameter, always IN PIXELS: `96` and `'96'` both give 96px. */\n size?: number | string\n /** How thick the ring is, always IN PIXELS: `8` and `'8'` both give 8px. */\n thickness?: number | string\n /** Whether the ends of the drawn arc are rounded or cut square. */\n shape?: ProgressCircularShape\n /**\n * Writes the percentage in the middle of the ring. It is ignored while the progress is\n * unmeasurable, there being no figure to write.\n */\n showValue?: boolean\n}\n\nconst props = withDefaults(defineProps<ProgressCircularProps>(), {\n value: 0,\n label: undefined,\n max: 100,\n indeterminate: false,\n tone: 'accent',\n color: undefined,\n size: undefined,\n thickness: undefined,\n shape: 'rounded',\n showValue: false,\n})\n\ndefineSlots<{\n /**\n * What to put in the middle of the ring instead of the percentage: a count of files,\n * an icon, a shortened figure.\n */\n default?(props: ProgressCircularSlotProps): unknown\n}>()\n\n/* The percent sign, and the non-breaking space French puts before it where English puts\n nothing, are a convention of the language: they belong in the dictionary rather than\n in this file. Any other format goes through the slot above. */\nconst m = useMessages()\n\nconst {\n max: normalizedMax,\n clamped,\n fraction,\n percent,\n roundedPercent,\n} = useProgressValue(\n () => props.value,\n () => props.max,\n)\n\n// @a11y\n// The canonical cascade: a consumer's `aria-labelledby`, then their `aria-label`, then the\n// `label` prop, then the dictionary. An indicator takes no name from the text inside it, so\n// without the last step it would have none at all.\nconst ariaLabel = useAriaLabel(() => props.label ?? m.value.progress.label)\n</script>\n\n<template>\n <span\n class=\"v-progress-circular v-tone\"\n role=\"progressbar\"\n :aria-label=\"ariaLabel\"\n :data-tone=\"tone\"\n :data-custom=\"color !== undefined ? '' : undefined\"\n :data-shape=\"shape\"\n :data-indeterminate=\"indeterminate ? '' : undefined\"\n :aria-valuenow=\"indeterminate ? undefined : clamped\"\n aria-valuemin=\"0\"\n :aria-valuemax=\"normalizedMax\"\n :style=\"{\n '--fill-fraction': String(fraction),\n '--custom-color': color,\n '--progress-diameter': px(size),\n '--progress-thickness': px(thickness),\n }\"\n >\n <svg class=\"v-progress-circular-svg\" aria-hidden=\"true\">\n <circle class=\"v-progress-circular-track\" pathLength=\"100\" />\n <circle class=\"v-progress-circular-bar\" pathLength=\"100\" />\n </svg>\n <span v-if=\"!indeterminate && (showValue || $slots.default)\" class=\"v-progress-circular-label\">\n <slot :value=\"clamped\" :max=\"normalizedMax\" :percent=\"percent\">\n {{ m.progress.percent(roundedPercent) }}\n </slot>\n </span>\n </span>\n</template>\n\n<style>\n@layer vectis.components {\n /* The two dimensions are declared here as defaults, on the very element the props\n write to inline — which is what makes an explicit size or thickness always win. */\n .v-progress-circular {\n --progress-diameter: var(--vectis-control-size-progress-circular-diameter);\n --progress-thickness: var(--vectis-control-size-progress-circular-thickness);\n /* Arc and track are the tone's solid and soft colours, read from the shared table\n (`.v-tone`, set in the template). No text colour is taken from it: the figure sits\n in the hole of the ring, against the page, in the ordinary text colour. */\n --progress-fill: var(--tone-bg-solid);\n --progress-track: var(--tone-bg-soft);\n display: inline-grid;\n inline-size: var(--progress-diameter);\n block-size: var(--progress-diameter);\n vertical-align: middle;\n }\n\n .v-progress-circular-svg,\n .v-progress-circular-label {\n grid-area: 1 / 1;\n }\n\n .v-progress-circular-svg {\n inline-size: 100%;\n block-size: 100%;\n /* Turns the ring so that it starts at twelve o'clock rather than at three. It is\n written as its own property and not as a transform, so that it COMPOSES with the\n spinning of the unmeasurable mode instead of being overwritten by it. */\n rotate: -90deg;\n }\n\n /* In a right-to-left page the ring fills the other way round, following the reading\n direction. These individual properties are applied in a fixed order — move, turn,\n then mirror — so the mirroring is taken into account before the quarter turn above. */\n .v-progress-circular:dir(rtl) .v-progress-circular-svg {\n scale: 1 -1;\n }\n\n /* The geometry, entirely in CSS and in plain lengths. Percentages are avoided\n deliberately: a radius given as a percentage is resolved against a normalized\n diagonal rather than against the width, and there is no reason to expose the\n component to that when the diameter is always a length to begin with. */\n .v-progress-circular-track,\n .v-progress-circular-bar {\n cx: calc(var(--progress-diameter) / 2);\n cy: calc(var(--progress-diameter) / 2);\n /* A thickness as large as the diameter would give a NEGATIVE radius, which is an\n error in SVG: the circle would simply not be drawn. The floor degrades that case\n to a radius of zero instead. */\n r: max(0px, calc((var(--progress-diameter) - var(--progress-thickness)) / 2));\n fill: none;\n stroke-width: var(--progress-thickness);\n }\n\n .v-progress-circular-track {\n stroke: var(--progress-track);\n }\n\n .v-progress-circular-bar {\n stroke: var(--progress-fill);\n stroke-linecap: round;\n stroke-dasharray: 100;\n stroke-dashoffset: calc(100 - 100 * var(--fill-fraction));\n transition: stroke-dashoffset var(--vectis-duration-base) var(--vectis-ease-default);\n }\n\n .v-progress-circular[data-shape='square'] .v-progress-circular-bar {\n stroke-linecap: butt;\n }\n\n .v-progress-circular-label {\n display: flex;\n align-items: center;\n justify-content: center;\n /* TRAP — this centres the BOX itself in its cell, and it is not redundant with the\n centring above. The maximum width below stops the box from being stretched to\n fill the cell, and a stretch that cannot apply falls back to the START edge: the\n figure would end up against the side of the ring. */\n place-self: center;\n max-inline-size: calc(var(--progress-diameter) - var(--progress-thickness) * 2);\n color: var(--vectis-color-text);\n font-family: var(--vectis-text-family);\n /* Sized as a fraction of the diameter so it stays in proportion at every size — the\n same tolerance already granted to VSpinner's stroke — with a floor at the smallest\n type token, below which it would be unreadable. */\n font-size: max(var(--vectis-text-caption-size), calc(var(--progress-diameter) / 4));\n font-weight: var(--vectis-text-control-weight);\n line-height: var(--vectis-text-control-leading);\n text-align: center;\n }\n\n /* When the progress cannot be measured, two animations run at once: the whole ring\n turns, and the arc drawn on it lengthens and shortens. Their periods are deliberately\n not multiples of one another — were the arc to restart on every rotation, the pair\n would repeat the same picture over and over and read as a mechanical beat. At 1s and\n 1.5s they only realign every third turn; the slowed-down pair below is 3s and 5s, so\n every fifth. Keep any change to those four values out of a whole-number ratio. */\n .v-progress-circular[data-indeterminate] .v-progress-circular-svg {\n animation: v-progress-circular-spin var(--vectis-duration-1000) linear infinite;\n }\n\n .v-progress-circular[data-indeterminate] .v-progress-circular-bar {\n animation: v-progress-circular-dash var(--vectis-duration-1500) var(--vectis-ease-default)\n infinite;\n transition: none;\n }\n\n /* The turn of the whole ring. VSpinner writes the same one under its own name: shared\n in the core sheet it cost every consumer the bytes, where the two copies only meet in\n an application that loads both components. */\n @keyframes v-progress-circular-spin {\n to {\n transform: rotate(1turn);\n }\n }\n\n /* Both ends of the arc move, so it lengthens, shortens and travels around the circle\n at once. */\n @keyframes v-progress-circular-dash {\n 0% {\n stroke-dasharray: 5 100;\n stroke-dashoffset: 0;\n }\n\n 50% {\n stroke-dasharray: 70 100;\n stroke-dashoffset: -20;\n }\n\n 100% {\n stroke-dasharray: 5 100;\n stroke-dashoffset: -100;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-progress-circular-bar {\n transition: none;\n }\n\n /* Slowed down and not stopped: a motionless loader no longer says that anything is\n happening, which is the one thing it exists to say. */\n .v-progress-circular[data-indeterminate] .v-progress-circular-svg {\n animation-duration: var(--vectis-duration-3000);\n }\n\n .v-progress-circular[data-indeterminate] .v-progress-circular-bar {\n animation-duration: var(--vectis-duration-5000);\n }\n }\n\n /* An SVG keeps its authored colours under Windows forced colours, so the ring would\n stay pale indigo on a system palette. It is drawn in the system colours instead: the\n remaining part in GrayText, the progress in Highlight. */\n @media (forced-colors: active) {\n .v-progress-circular {\n forced-color-adjust: none;\n }\n\n .v-progress-circular-track {\n stroke: GrayText;\n }\n\n .v-progress-circular-bar {\n stroke: Highlight;\n }\n\n .v-progress-circular-label {\n color: CanvasText;\n }\n }\n}\n</style>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"VProgressCircular.js","names":[],"sources":["../../../src/components/VProgressCircular/VProgressCircular.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * CSS draws the progress arc. JavaScript normalizes values shared by geometry, slots and\n * progressbar ARIA attributes.\n */\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useProgressValue } from '../../composables/useProgressValue'\nimport { useMessages } from '../../i18n/state'\nimport { px } from '../../utils/css'\n\n/** What the progress means, in colour. */\nexport type ProgressCircularTone = 'neutral' | 'accent' | 'danger' | 'success' | 'warning'\n\n/** How the arc ends. */\nexport type ProgressCircularShape = 'rounded' | 'square'\n\n/** What the default slot receives. */\nexport interface ProgressCircularSlotProps {\n /** The value, brought back into the range. */\n value: number\n /** The bound, zero or more. */\n max: number\n /** How far along it is, as a percentage and unrounded. */\n percent: number\n}\n\ninterface ProgressCircularProps {\n /** How far along it is. Anything outside the range is brought back into it. */\n value?: number\n /**\n * What is progressing, in words, for screen readers. It draws nothing on screen, and falls\n * back to the design system dictionary; an `aria-label` or `aria-labelledby` of your own\n * takes precedence over it.\n */\n label?: string\n /** What counts as finished. The other end is always zero. */\n max?: number\n indeterminate?: boolean\n /** What the progress means, expressed as a colour. */\n tone?: ProgressCircularTone\n /**\n * A colour of your own (hex, CSS name or `oklch()`), which replaces the tone. The\n * unfilled ring's shade is derived from it against the theme, so it follows the light\n * and the dark one.\n */\n color?: string\n /** The diameter, always in PIXELS: `96` and `'96'` both give 96px. */\n size?: number | string\n /** How thick the ring is, always in PIXELS: `8` and `'8'` both give 8px. */\n thickness?: number | string\n /** Whether the ends of the drawn arc are rounded or cut square. */\n shape?: ProgressCircularShape\n /**\n * Writes the percentage in the middle of the ring. It is ignored while the progress is\n * unmeasurable, there being no figure to write.\n */\n showValue?: boolean\n}\n\nconst props = withDefaults(defineProps<ProgressCircularProps>(), {\n value: 0,\n label: undefined,\n max: 100,\n indeterminate: false,\n tone: 'accent',\n color: undefined,\n size: undefined,\n thickness: undefined,\n shape: 'rounded',\n showValue: false,\n})\n\ndefineSlots<{\n /**\n * What to put in the middle of the ring instead of the percentage: a count of files,\n * an icon, a shortened figure.\n */\n default?(props: ProgressCircularSlotProps): unknown\n}>()\n\n/* The percent sign, and the non-breaking space French puts before it where English puts\n nothing, are a convention of the language: they belong in the dictionary rather than\n in this file. Any other format goes through the slot above. */\nconst m = useMessages()\n\nconst {\n max: normalizedMax,\n clamped,\n fraction,\n percent,\n roundedPercent,\n} = useProgressValue(\n () => props.value,\n () => props.max,\n)\n\n// @a11y\n// The canonical cascade: a consumer's `aria-labelledby`, then their `aria-label`, then the\n// `label` prop, then the dictionary. An indicator takes no name from the text inside it, so\n// without the last step it would have none at all.\nconst ariaLabel = useAriaLabel(() => props.label ?? m.value.progress.label)\n</script>\n\n<template>\n <span\n class=\"v-progress-circular v-tone\"\n role=\"progressbar\"\n :aria-label=\"ariaLabel\"\n :data-tone=\"tone\"\n :data-custom=\"color !== undefined ? '' : undefined\"\n :data-shape=\"shape\"\n :data-indeterminate=\"indeterminate ? '' : undefined\"\n :aria-valuenow=\"indeterminate ? undefined : clamped\"\n aria-valuemin=\"0\"\n :aria-valuemax=\"normalizedMax\"\n :style=\"{\n '--fill-fraction': String(fraction),\n '--custom-color': color,\n '--progress-diameter': px(size),\n '--progress-thickness': px(thickness),\n }\"\n >\n <svg class=\"v-progress-circular-svg\" aria-hidden=\"true\">\n <circle class=\"v-progress-circular-track\" pathLength=\"100\" />\n <circle class=\"v-progress-circular-bar\" pathLength=\"100\" />\n </svg>\n <span v-if=\"!indeterminate && (showValue || $slots.default)\" class=\"v-progress-circular-label\">\n <slot :value=\"clamped\" :max=\"normalizedMax\" :percent=\"percent\">\n {{ m.progress.percent(roundedPercent) }}\n </slot>\n </span>\n </span>\n</template>\n\n<style>\n@layer vectis.components {\n /*\n * The two dimensions are declared here as defaults, on the very element the props write to\n * inline; which makes an explicit size or thickness always win.\n */\n .v-progress-circular {\n --progress-diameter: var(--vectis-control-size-progress-circular-diameter);\n --progress-thickness: var(--vectis-control-size-progress-circular-thickness);\n /* Arc and track are the tone's solid and soft colours, read from the shared table\n (`.v-tone`, set in the template). No text colour is taken from it: the figure sits\n in the hole of the ring, against the page, in the ordinary text colour. */\n --progress-fill: var(--tone-bg-solid);\n --progress-track: var(--tone-bg-soft);\n display: inline-grid;\n inline-size: var(--progress-diameter);\n block-size: var(--progress-diameter);\n vertical-align: middle;\n }\n\n .v-progress-circular-svg,\n .v-progress-circular-label {\n grid-area: 1 / 1;\n }\n\n .v-progress-circular-svg {\n inline-size: 100%;\n block-size: 100%;\n /* Turns the ring so that it starts at twelve o'clock rather than at three. It is\n written as its own property and not as a transform, so that it COMPOSES with the\n spinning of the unmeasurable mode instead of being overwritten by it. */\n rotate: -90deg;\n }\n\n /*\n * In a right-to-left page the ring fills the other way round, following the reading\n * direction. These individual properties are applied in a fixed order; move, turn, then\n * mirror; so the mirroring is taken into account before the quarter turn above.\n */\n .v-progress-circular:dir(rtl) .v-progress-circular-svg {\n scale: 1 -1;\n }\n\n /*\n * Percentages are avoided deliberately: a radius given as a percentage is resolved against a\n * normalized diagonal rather than against the width, and there is no reason to expose the\n * component to that when the diameter is always a length to begin with.\n */\n .v-progress-circular-track,\n .v-progress-circular-bar {\n cx: calc(var(--progress-diameter) / 2);\n cy: calc(var(--progress-diameter) / 2);\n /* A thickness as large as the diameter would give a NEGATIVE radius, which is an\n error in SVG: the circle would simply not be drawn. The floor degrades that case\n to a radius of zero instead. */\n r: max(0px, calc((var(--progress-diameter) - var(--progress-thickness)) / 2));\n fill: none;\n stroke-width: var(--progress-thickness);\n }\n\n .v-progress-circular-track {\n stroke: var(--progress-track);\n }\n\n .v-progress-circular-bar {\n stroke: var(--progress-fill);\n stroke-linecap: round;\n stroke-dasharray: 100;\n stroke-dashoffset: calc(100 - 100 * var(--fill-fraction));\n transition: stroke-dashoffset var(--vectis-duration-base) var(--vectis-ease-default);\n }\n\n .v-progress-circular[data-shape='square'] .v-progress-circular-bar {\n stroke-linecap: butt;\n }\n\n .v-progress-circular-label {\n display: flex;\n align-items: center;\n justify-content: center;\n /*\n * This centres the BOX itself in its cell, and it is not redundant with the centring above.\n * The maximum width below stops the box from being stretched to fill the cell, and a\n * stretch that cannot apply falls back to the START edge: the figure would end up against\n * the side of the ring.\n */\n place-self: center;\n max-inline-size: calc(var(--progress-diameter) - var(--progress-thickness) * 2);\n color: var(--vectis-color-text);\n font-family: var(--vectis-text-family);\n /*\n * Sized as a fraction of the diameter so it stays in proportion at every size; the same\n * tolerance already granted to VSpinner's stroke; with a floor at the smallest type token,\n * below which it would be unreadable.\n */\n font-size: max(var(--vectis-text-caption-size), calc(var(--progress-diameter) / 4));\n font-weight: var(--vectis-text-control-weight);\n line-height: var(--vectis-text-control-leading);\n text-align: center;\n }\n\n /*\n * Their periods are deliberately not multiples of one another; were the arc to restart on\n * every rotation, the pair would repeat the same picture over and over and read as a\n * mechanical beat. At 1s and 1.5s they only realign every third turn; the slowed-down pair\n * below is 3s and 5s, so every fifth.\n */\n .v-progress-circular[data-indeterminate] .v-progress-circular-svg {\n animation: v-progress-circular-spin var(--vectis-duration-1000) linear infinite;\n }\n\n .v-progress-circular[data-indeterminate] .v-progress-circular-bar {\n animation: v-progress-circular-dash var(--vectis-duration-1500) var(--vectis-ease-default)\n infinite;\n transition: none;\n }\n\n /* The turn of the whole ring. VSpinner writes the same one under its own name: shared\n in the core sheet it cost every consumer the bytes, where the two copies only meet in\n an application that loads both components. */\n @keyframes v-progress-circular-spin {\n to {\n transform: rotate(1turn);\n }\n }\n\n @keyframes v-progress-circular-dash {\n 0% {\n stroke-dasharray: 5 100;\n stroke-dashoffset: 0;\n }\n\n 50% {\n stroke-dasharray: 70 100;\n stroke-dashoffset: -20;\n }\n\n 100% {\n stroke-dasharray: 5 100;\n stroke-dashoffset: -100;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-progress-circular-bar {\n transition: none;\n }\n\n .v-progress-circular[data-indeterminate] .v-progress-circular-svg {\n animation-duration: var(--vectis-duration-3000);\n }\n\n .v-progress-circular[data-indeterminate] .v-progress-circular-bar {\n animation-duration: var(--vectis-duration-5000);\n }\n }\n\n /* An SVG keeps its authored colours under Windows forced colours, so the ring would\n stay pale indigo on a system palette. It is drawn in the system colours instead: the\n remaining part in GrayText, the progress in Highlight. */\n @media (forced-colors: active) {\n .v-progress-circular {\n forced-color-adjust: none;\n }\n\n .v-progress-circular-track {\n stroke: GrayText;\n }\n\n .v-progress-circular-bar {\n stroke: Highlight;\n }\n\n .v-progress-circular-label {\n color: CanvasText;\n }\n }\n}\n</style>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VProgressCircular.vue_vue_type_script_setup_true_lang.js","names":["$slots"],"sources":["../../../src/components/VProgressCircular/VProgressCircular.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Progress drawn as a ring, an SVG whose geometry is described entirely in CSS with no JS\n * computing anything.\n *\n * Two things make that possible. There is no `viewBox`, so one user unit is one pixel and\n * the circles take plain lengths — a fixed coordinate system would mean converting the\n * thickness into its units, hence knowing the ratio in code and recomputing it at every\n * change of size. And `pathLength=\"100\"` declares the outline 100 units long whatever its\n * real circumference, so the portion drawn is a percentage with no π anywhere.\n *\n * NAMING — pass a `label` saying what is progressing. The figure in the middle cannot\n * serve: `role=\"progressbar\"` makes its content presentational, so it is never announced.\n */\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useProgressValue } from '../../composables/useProgressValue'\nimport { useMessages } from '../../i18n/state'\nimport { px } from '../../utils/css'\n\n/** What the progress means, in colour. */\nexport type ProgressCircularTone = 'neutral' | 'accent' | 'danger' | 'success' | 'warning'\n\n/** How the arc ends. */\nexport type ProgressCircularShape = 'rounded' | 'square'\n\n/** What the default slot receives. */\nexport interface ProgressCircularSlotProps {\n /** The value, brought back into the range. */\n value: number\n /** The bound, zero or more. */\n max: number\n /** How far along it is, as a percentage and unrounded. */\n percent: number\n}\n\ninterface ProgressCircularProps {\n /** How far along it is. Anything outside the range is brought back into it. */\n value?: number\n /**\n * What is progressing, in words, for screen readers. It draws nothing on screen, and falls\n * back to the design system dictionary; an `aria-label` or `aria-labelledby` of your own\n * takes precedence over it.\n */\n label?: string\n /** What counts as finished. The other end is always zero. */\n max?: number\n /**\n * Says that the progress cannot be measured: the ring turns continuously and the\n * value is ignored.\n */\n indeterminate?: boolean\n /** What the progress means, expressed as a colour. */\n tone?: ProgressCircularTone\n /**\n * A colour of your own (hex, CSS name or `oklch()`), which replaces the tone. The\n * unfilled ring's shade is derived from it against the theme, so it follows the light\n * and the dark one.\n */\n color?: string\n /** The diameter, always IN PIXELS: `96` and `'96'` both give 96px. */\n size?: number | string\n /** How thick the ring is, always IN PIXELS: `8` and `'8'` both give 8px. */\n thickness?: number | string\n /** Whether the ends of the drawn arc are rounded or cut square. */\n shape?: ProgressCircularShape\n /**\n * Writes the percentage in the middle of the ring. It is ignored while the progress is\n * unmeasurable, there being no figure to write.\n */\n showValue?: boolean\n}\n\nconst props = withDefaults(defineProps<ProgressCircularProps>(), {\n value: 0,\n label: undefined,\n max: 100,\n indeterminate: false,\n tone: 'accent',\n color: undefined,\n size: undefined,\n thickness: undefined,\n shape: 'rounded',\n showValue: false,\n})\n\ndefineSlots<{\n /**\n * What to put in the middle of the ring instead of the percentage: a count of files,\n * an icon, a shortened figure.\n */\n default?(props: ProgressCircularSlotProps): unknown\n}>()\n\n/* The percent sign, and the non-breaking space French puts before it where English puts\n nothing, are a convention of the language: they belong in the dictionary rather than\n in this file. Any other format goes through the slot above. */\nconst m = useMessages()\n\nconst {\n max: normalizedMax,\n clamped,\n fraction,\n percent,\n roundedPercent,\n} = useProgressValue(\n () => props.value,\n () => props.max,\n)\n\n// @a11y\n// The canonical cascade: a consumer's `aria-labelledby`, then their `aria-label`, then the\n// `label` prop, then the dictionary. An indicator takes no name from the text inside it, so\n// without the last step it would have none at all.\nconst ariaLabel = useAriaLabel(() => props.label ?? m.value.progress.label)\n</script>\n\n<template>\n <span\n class=\"v-progress-circular v-tone\"\n role=\"progressbar\"\n :aria-label=\"ariaLabel\"\n :data-tone=\"tone\"\n :data-custom=\"color !== undefined ? '' : undefined\"\n :data-shape=\"shape\"\n :data-indeterminate=\"indeterminate ? '' : undefined\"\n :aria-valuenow=\"indeterminate ? undefined : clamped\"\n aria-valuemin=\"0\"\n :aria-valuemax=\"normalizedMax\"\n :style=\"{\n '--fill-fraction': String(fraction),\n '--custom-color': color,\n '--progress-diameter': px(size),\n '--progress-thickness': px(thickness),\n }\"\n >\n <svg class=\"v-progress-circular-svg\" aria-hidden=\"true\">\n <circle class=\"v-progress-circular-track\" pathLength=\"100\" />\n <circle class=\"v-progress-circular-bar\" pathLength=\"100\" />\n </svg>\n <span v-if=\"!indeterminate && (showValue || $slots.default)\" class=\"v-progress-circular-label\">\n <slot :value=\"clamped\" :max=\"normalizedMax\" :percent=\"percent\">\n {{ m.progress.percent(roundedPercent) }}\n </slot>\n </span>\n </span>\n</template>\n\n<style>\n@layer vectis.components {\n /* The two dimensions are declared here as defaults, on the very element the props\n write to inline — which is what makes an explicit size or thickness always win. */\n .v-progress-circular {\n --progress-diameter: var(--vectis-control-size-progress-circular-diameter);\n --progress-thickness: var(--vectis-control-size-progress-circular-thickness);\n /* Arc and track are the tone's solid and soft colours, read from the shared table\n (`.v-tone`, set in the template). No text colour is taken from it: the figure sits\n in the hole of the ring, against the page, in the ordinary text colour. */\n --progress-fill: var(--tone-bg-solid);\n --progress-track: var(--tone-bg-soft);\n display: inline-grid;\n inline-size: var(--progress-diameter);\n block-size: var(--progress-diameter);\n vertical-align: middle;\n }\n\n .v-progress-circular-svg,\n .v-progress-circular-label {\n grid-area: 1 / 1;\n }\n\n .v-progress-circular-svg {\n inline-size: 100%;\n block-size: 100%;\n /* Turns the ring so that it starts at twelve o'clock rather than at three. It is\n written as its own property and not as a transform, so that it COMPOSES with the\n spinning of the unmeasurable mode instead of being overwritten by it. */\n rotate: -90deg;\n }\n\n /* In a right-to-left page the ring fills the other way round, following the reading\n direction. These individual properties are applied in a fixed order — move, turn,\n then mirror — so the mirroring is taken into account before the quarter turn above. */\n .v-progress-circular:dir(rtl) .v-progress-circular-svg {\n scale: 1 -1;\n }\n\n /* The geometry, entirely in CSS and in plain lengths. Percentages are avoided\n deliberately: a radius given as a percentage is resolved against a normalized\n diagonal rather than against the width, and there is no reason to expose the\n component to that when the diameter is always a length to begin with. */\n .v-progress-circular-track,\n .v-progress-circular-bar {\n cx: calc(var(--progress-diameter) / 2);\n cy: calc(var(--progress-diameter) / 2);\n /* A thickness as large as the diameter would give a NEGATIVE radius, which is an\n error in SVG: the circle would simply not be drawn. The floor degrades that case\n to a radius of zero instead. */\n r: max(0px, calc((var(--progress-diameter) - var(--progress-thickness)) / 2));\n fill: none;\n stroke-width: var(--progress-thickness);\n }\n\n .v-progress-circular-track {\n stroke: var(--progress-track);\n }\n\n .v-progress-circular-bar {\n stroke: var(--progress-fill);\n stroke-linecap: round;\n stroke-dasharray: 100;\n stroke-dashoffset: calc(100 - 100 * var(--fill-fraction));\n transition: stroke-dashoffset var(--vectis-duration-base) var(--vectis-ease-default);\n }\n\n .v-progress-circular[data-shape='square'] .v-progress-circular-bar {\n stroke-linecap: butt;\n }\n\n .v-progress-circular-label {\n display: flex;\n align-items: center;\n justify-content: center;\n /* TRAP — this centres the BOX itself in its cell, and it is not redundant with the\n centring above. The maximum width below stops the box from being stretched to\n fill the cell, and a stretch that cannot apply falls back to the START edge: the\n figure would end up against the side of the ring. */\n place-self: center;\n max-inline-size: calc(var(--progress-diameter) - var(--progress-thickness) * 2);\n color: var(--vectis-color-text);\n font-family: var(--vectis-text-family);\n /* Sized as a fraction of the diameter so it stays in proportion at every size — the\n same tolerance already granted to VSpinner's stroke — with a floor at the smallest\n type token, below which it would be unreadable. */\n font-size: max(var(--vectis-text-caption-size), calc(var(--progress-diameter) / 4));\n font-weight: var(--vectis-text-control-weight);\n line-height: var(--vectis-text-control-leading);\n text-align: center;\n }\n\n /* When the progress cannot be measured, two animations run at once: the whole ring\n turns, and the arc drawn on it lengthens and shortens. Their periods are deliberately\n not multiples of one another — were the arc to restart on every rotation, the pair\n would repeat the same picture over and over and read as a mechanical beat. At 1s and\n 1.5s they only realign every third turn; the slowed-down pair below is 3s and 5s, so\n every fifth. Keep any change to those four values out of a whole-number ratio. */\n .v-progress-circular[data-indeterminate] .v-progress-circular-svg {\n animation: v-progress-circular-spin var(--vectis-duration-1000) linear infinite;\n }\n\n .v-progress-circular[data-indeterminate] .v-progress-circular-bar {\n animation: v-progress-circular-dash var(--vectis-duration-1500) var(--vectis-ease-default)\n infinite;\n transition: none;\n }\n\n /* The turn of the whole ring. VSpinner writes the same one under its own name: shared\n in the core sheet it cost every consumer the bytes, where the two copies only meet in\n an application that loads both components. */\n @keyframes v-progress-circular-spin {\n to {\n transform: rotate(1turn);\n }\n }\n\n /* Both ends of the arc move, so it lengthens, shortens and travels around the circle\n at once. */\n @keyframes v-progress-circular-dash {\n 0% {\n stroke-dasharray: 5 100;\n stroke-dashoffset: 0;\n }\n\n 50% {\n stroke-dasharray: 70 100;\n stroke-dashoffset: -20;\n }\n\n 100% {\n stroke-dasharray: 5 100;\n stroke-dashoffset: -100;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-progress-circular-bar {\n transition: none;\n }\n\n /* Slowed down and not stopped: a motionless loader no longer says that anything is\n happening, which is the one thing it exists to say. */\n .v-progress-circular[data-indeterminate] .v-progress-circular-svg {\n animation-duration: var(--vectis-duration-3000);\n }\n\n .v-progress-circular[data-indeterminate] .v-progress-circular-bar {\n animation-duration: var(--vectis-duration-5000);\n }\n }\n\n /* An SVG keeps its authored colours under Windows forced colours, so the ring would\n stay pale indigo on a system palette. It is drawn in the system colours instead: the\n remaining part in GrayText, the progress in Highlight. */\n @media (forced-colors: active) {\n .v-progress-circular {\n forced-color-adjust: none;\n }\n\n .v-progress-circular-track {\n stroke: GrayText;\n }\n\n .v-progress-circular-bar {\n stroke: Highlight;\n }\n\n .v-progress-circular-label {\n color: CanvasText;\n }\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwEA,IAAM,IAAQ,GAwBR,IAAI,EAAY,GAEhB,EACJ,KAAK,GACL,YACA,aACA,YACA,sBACE,QACI,EAAM,aACN,EAAM,GACd,GAMM,IAAY,QAAmB,EAAM,SAAS,EAAE,MAAM,SAAS,KAAK;yBAIxE,EA2BO,QAAA;GA1BL,OAAM;GACN,MAAK;GACJ,cAAY,EAAA,CAAA;GACZ,aAAW,EAAA;GACX,eAAa,EAAA,UAAU,KAAA,IAAiB,KAAA,IAAR;GAChC,cAAY,EAAA;GACZ,sBAAoB,EAAA,gBAAa,KAAQ,KAAA;GACzC,iBAAe,EAAA,gBAAgB,KAAA,IAAY,EAAA,CAAA;GAC5C,iBAAc;GACb,iBAAe,EAAA,CAAA;GACf,OAAK,EAAA;uBAA6B,OAAO,EAAA,CAAA,CAAQ;sBAA2B,EAAA;2BAAoC,EAAA,CAAA,CAAE,CAAC,EAAA,IAAI;4BAAiC,EAAA,CAAA,CAAE,CAAC,EAAA,SAAS;;eAOrK,EAGM,OAAA;GAHD,OAAM;GAA0B,eAAY;MAC/C,EAA6D,UAAA;GAArD,OAAM;GAA4B,YAAW;MACrD,EAA2D,UAAA;GAAnD,OAAM;GAA0B,YAAW;aAExC,EAAA,kBAAkB,EAAA,aAAaA,EAAAA,OAAO,YAAA,EAAA,GAAnD,EAIO,QAJP,GAIO,CAHL,EAEO,EAAA,QAAA,WAAA;GAFA,OAAO,EAAA,CAAA;GAAU,KAAK,EAAA,CAAA;GAAgB,SAAS,EAAA,CAAA;WAE/C,CAAA,EAAA,EADF,EAAA,CAAA,CAAC,CAAC,SAAS,QAAQ,EAAA,CAAA,CAAc,CAAA,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,GAAA,IAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"VProgressCircular.vue_vue_type_script_setup_true_lang.js","names":["$slots"],"sources":["../../../src/components/VProgressCircular/VProgressCircular.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * CSS draws the progress arc. JavaScript normalizes values shared by geometry, slots and\n * progressbar ARIA attributes.\n */\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useProgressValue } from '../../composables/useProgressValue'\nimport { useMessages } from '../../i18n/state'\nimport { px } from '../../utils/css'\n\n/** What the progress means, in colour. */\nexport type ProgressCircularTone = 'neutral' | 'accent' | 'danger' | 'success' | 'warning'\n\n/** How the arc ends. */\nexport type ProgressCircularShape = 'rounded' | 'square'\n\n/** What the default slot receives. */\nexport interface ProgressCircularSlotProps {\n /** The value, brought back into the range. */\n value: number\n /** The bound, zero or more. */\n max: number\n /** How far along it is, as a percentage and unrounded. */\n percent: number\n}\n\ninterface ProgressCircularProps {\n /** How far along it is. Anything outside the range is brought back into it. */\n value?: number\n /**\n * What is progressing, in words, for screen readers. It draws nothing on screen, and falls\n * back to the design system dictionary; an `aria-label` or `aria-labelledby` of your own\n * takes precedence over it.\n */\n label?: string\n /** What counts as finished. The other end is always zero. */\n max?: number\n indeterminate?: boolean\n /** What the progress means, expressed as a colour. */\n tone?: ProgressCircularTone\n /**\n * A colour of your own (hex, CSS name or `oklch()`), which replaces the tone. The\n * unfilled ring's shade is derived from it against the theme, so it follows the light\n * and the dark one.\n */\n color?: string\n /** The diameter, always in PIXELS: `96` and `'96'` both give 96px. */\n size?: number | string\n /** How thick the ring is, always in PIXELS: `8` and `'8'` both give 8px. */\n thickness?: number | string\n /** Whether the ends of the drawn arc are rounded or cut square. */\n shape?: ProgressCircularShape\n /**\n * Writes the percentage in the middle of the ring. It is ignored while the progress is\n * unmeasurable, there being no figure to write.\n */\n showValue?: boolean\n}\n\nconst props = withDefaults(defineProps<ProgressCircularProps>(), {\n value: 0,\n label: undefined,\n max: 100,\n indeterminate: false,\n tone: 'accent',\n color: undefined,\n size: undefined,\n thickness: undefined,\n shape: 'rounded',\n showValue: false,\n})\n\ndefineSlots<{\n /**\n * What to put in the middle of the ring instead of the percentage: a count of files,\n * an icon, a shortened figure.\n */\n default?(props: ProgressCircularSlotProps): unknown\n}>()\n\n/* The percent sign, and the non-breaking space French puts before it where English puts\n nothing, are a convention of the language: they belong in the dictionary rather than\n in this file. Any other format goes through the slot above. */\nconst m = useMessages()\n\nconst {\n max: normalizedMax,\n clamped,\n fraction,\n percent,\n roundedPercent,\n} = useProgressValue(\n () => props.value,\n () => props.max,\n)\n\n// @a11y\n// The canonical cascade: a consumer's `aria-labelledby`, then their `aria-label`, then the\n// `label` prop, then the dictionary. An indicator takes no name from the text inside it, so\n// without the last step it would have none at all.\nconst ariaLabel = useAriaLabel(() => props.label ?? m.value.progress.label)\n</script>\n\n<template>\n <span\n class=\"v-progress-circular v-tone\"\n role=\"progressbar\"\n :aria-label=\"ariaLabel\"\n :data-tone=\"tone\"\n :data-custom=\"color !== undefined ? '' : undefined\"\n :data-shape=\"shape\"\n :data-indeterminate=\"indeterminate ? '' : undefined\"\n :aria-valuenow=\"indeterminate ? undefined : clamped\"\n aria-valuemin=\"0\"\n :aria-valuemax=\"normalizedMax\"\n :style=\"{\n '--fill-fraction': String(fraction),\n '--custom-color': color,\n '--progress-diameter': px(size),\n '--progress-thickness': px(thickness),\n }\"\n >\n <svg class=\"v-progress-circular-svg\" aria-hidden=\"true\">\n <circle class=\"v-progress-circular-track\" pathLength=\"100\" />\n <circle class=\"v-progress-circular-bar\" pathLength=\"100\" />\n </svg>\n <span v-if=\"!indeterminate && (showValue || $slots.default)\" class=\"v-progress-circular-label\">\n <slot :value=\"clamped\" :max=\"normalizedMax\" :percent=\"percent\">\n {{ m.progress.percent(roundedPercent) }}\n </slot>\n </span>\n </span>\n</template>\n\n<style>\n@layer vectis.components {\n /*\n * The two dimensions are declared here as defaults, on the very element the props write to\n * inline; which makes an explicit size or thickness always win.\n */\n .v-progress-circular {\n --progress-diameter: var(--vectis-control-size-progress-circular-diameter);\n --progress-thickness: var(--vectis-control-size-progress-circular-thickness);\n /* Arc and track are the tone's solid and soft colours, read from the shared table\n (`.v-tone`, set in the template). No text colour is taken from it: the figure sits\n in the hole of the ring, against the page, in the ordinary text colour. */\n --progress-fill: var(--tone-bg-solid);\n --progress-track: var(--tone-bg-soft);\n display: inline-grid;\n inline-size: var(--progress-diameter);\n block-size: var(--progress-diameter);\n vertical-align: middle;\n }\n\n .v-progress-circular-svg,\n .v-progress-circular-label {\n grid-area: 1 / 1;\n }\n\n .v-progress-circular-svg {\n inline-size: 100%;\n block-size: 100%;\n /* Turns the ring so that it starts at twelve o'clock rather than at three. It is\n written as its own property and not as a transform, so that it COMPOSES with the\n spinning of the unmeasurable mode instead of being overwritten by it. */\n rotate: -90deg;\n }\n\n /*\n * In a right-to-left page the ring fills the other way round, following the reading\n * direction. These individual properties are applied in a fixed order; move, turn, then\n * mirror; so the mirroring is taken into account before the quarter turn above.\n */\n .v-progress-circular:dir(rtl) .v-progress-circular-svg {\n scale: 1 -1;\n }\n\n /*\n * Percentages are avoided deliberately: a radius given as a percentage is resolved against a\n * normalized diagonal rather than against the width, and there is no reason to expose the\n * component to that when the diameter is always a length to begin with.\n */\n .v-progress-circular-track,\n .v-progress-circular-bar {\n cx: calc(var(--progress-diameter) / 2);\n cy: calc(var(--progress-diameter) / 2);\n /* A thickness as large as the diameter would give a NEGATIVE radius, which is an\n error in SVG: the circle would simply not be drawn. The floor degrades that case\n to a radius of zero instead. */\n r: max(0px, calc((var(--progress-diameter) - var(--progress-thickness)) / 2));\n fill: none;\n stroke-width: var(--progress-thickness);\n }\n\n .v-progress-circular-track {\n stroke: var(--progress-track);\n }\n\n .v-progress-circular-bar {\n stroke: var(--progress-fill);\n stroke-linecap: round;\n stroke-dasharray: 100;\n stroke-dashoffset: calc(100 - 100 * var(--fill-fraction));\n transition: stroke-dashoffset var(--vectis-duration-base) var(--vectis-ease-default);\n }\n\n .v-progress-circular[data-shape='square'] .v-progress-circular-bar {\n stroke-linecap: butt;\n }\n\n .v-progress-circular-label {\n display: flex;\n align-items: center;\n justify-content: center;\n /*\n * This centres the BOX itself in its cell, and it is not redundant with the centring above.\n * The maximum width below stops the box from being stretched to fill the cell, and a\n * stretch that cannot apply falls back to the START edge: the figure would end up against\n * the side of the ring.\n */\n place-self: center;\n max-inline-size: calc(var(--progress-diameter) - var(--progress-thickness) * 2);\n color: var(--vectis-color-text);\n font-family: var(--vectis-text-family);\n /*\n * Sized as a fraction of the diameter so it stays in proportion at every size; the same\n * tolerance already granted to VSpinner's stroke; with a floor at the smallest type token,\n * below which it would be unreadable.\n */\n font-size: max(var(--vectis-text-caption-size), calc(var(--progress-diameter) / 4));\n font-weight: var(--vectis-text-control-weight);\n line-height: var(--vectis-text-control-leading);\n text-align: center;\n }\n\n /*\n * Their periods are deliberately not multiples of one another; were the arc to restart on\n * every rotation, the pair would repeat the same picture over and over and read as a\n * mechanical beat. At 1s and 1.5s they only realign every third turn; the slowed-down pair\n * below is 3s and 5s, so every fifth.\n */\n .v-progress-circular[data-indeterminate] .v-progress-circular-svg {\n animation: v-progress-circular-spin var(--vectis-duration-1000) linear infinite;\n }\n\n .v-progress-circular[data-indeterminate] .v-progress-circular-bar {\n animation: v-progress-circular-dash var(--vectis-duration-1500) var(--vectis-ease-default)\n infinite;\n transition: none;\n }\n\n /* The turn of the whole ring. VSpinner writes the same one under its own name: shared\n in the core sheet it cost every consumer the bytes, where the two copies only meet in\n an application that loads both components. */\n @keyframes v-progress-circular-spin {\n to {\n transform: rotate(1turn);\n }\n }\n\n @keyframes v-progress-circular-dash {\n 0% {\n stroke-dasharray: 5 100;\n stroke-dashoffset: 0;\n }\n\n 50% {\n stroke-dasharray: 70 100;\n stroke-dashoffset: -20;\n }\n\n 100% {\n stroke-dasharray: 5 100;\n stroke-dashoffset: -100;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-progress-circular-bar {\n transition: none;\n }\n\n .v-progress-circular[data-indeterminate] .v-progress-circular-svg {\n animation-duration: var(--vectis-duration-3000);\n }\n\n .v-progress-circular[data-indeterminate] .v-progress-circular-bar {\n animation-duration: var(--vectis-duration-5000);\n }\n }\n\n /* An SVG keeps its authored colours under Windows forced colours, so the ring would\n stay pale indigo on a system palette. It is drawn in the system colours instead: the\n remaining part in GrayText, the progress in Highlight. */\n @media (forced-colors: active) {\n .v-progress-circular {\n forced-color-adjust: none;\n }\n\n .v-progress-circular-track {\n stroke: GrayText;\n }\n\n .v-progress-circular-bar {\n stroke: Highlight;\n }\n\n .v-progress-circular-label {\n color: CanvasText;\n }\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2DA,IAAM,IAAQ,GAwBR,IAAI,EAAY,GAEhB,EACJ,KAAK,GACL,YACA,aACA,YACA,sBACE,QACI,EAAM,aACN,EAAM,GACd,GAMM,IAAY,QAAmB,EAAM,SAAS,EAAE,MAAM,SAAS,KAAK;yBAIxE,EA2BO,QAAA;GA1BL,OAAM;GACN,MAAK;GACJ,cAAY,EAAA,CAAA;GACZ,aAAW,EAAA;GACX,eAAa,EAAA,UAAU,KAAA,IAAiB,KAAA,IAAR;GAChC,cAAY,EAAA;GACZ,sBAAoB,EAAA,gBAAa,KAAQ,KAAA;GACzC,iBAAe,EAAA,gBAAgB,KAAA,IAAY,EAAA,CAAA;GAC5C,iBAAc;GACb,iBAAe,EAAA,CAAA;GACf,OAAK,EAAA;uBAA6B,OAAO,EAAA,CAAA,CAAQ;sBAA2B,EAAA;2BAAoC,EAAA,CAAA,CAAE,CAAC,EAAA,IAAI;4BAAiC,EAAA,CAAA,CAAE,CAAC,EAAA,SAAS;;eAOrK,EAGM,OAAA;GAHD,OAAM;GAA0B,eAAY;MAC/C,EAA6D,UAAA;GAArD,OAAM;GAA4B,YAAW;MACrD,EAA2D,UAAA;GAAnD,OAAM;GAA0B,YAAW;aAExC,EAAA,kBAAkB,EAAA,aAAaA,EAAAA,OAAO,YAAA,EAAA,GAAnD,EAIO,QAJP,GAIO,CAHL,EAEO,EAAA,QAAA,WAAA;GAFA,OAAO,EAAA,CAAA;GAAU,KAAK,EAAA,CAAA;GAAgB,SAAS,EAAA,CAAA;WAE/C,CAAA,EAAA,EADF,EAAA,CAAA,CAAC,CAAC,SAAS,QAAQ,EAAA,CAAA,CAAc,CAAA,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,GAAA,IAAA,CAAA"}
|
|
@@ -26,11 +26,7 @@ interface ProgressLinearProps {
|
|
|
26
26
|
label?: string;
|
|
27
27
|
/** What counts as finished. The other end is always zero. */
|
|
28
28
|
max?: number;
|
|
29
|
-
/**
|
|
30
|
-
* Says that the progress cannot be measured: the bar animates continuously and the
|
|
31
|
-
* value is ignored. It is what to use while waiting for a server that reports no
|
|
32
|
-
* percentage.
|
|
33
|
-
*/
|
|
29
|
+
/** It is what to use while waiting for a server that reports no percentage. */
|
|
34
30
|
indeterminate?: boolean;
|
|
35
31
|
/** What the progress means, expressed as a colour. */
|
|
36
32
|
tone?: ProgressLinearTone;
|
|
@@ -41,9 +37,8 @@ interface ProgressLinearProps {
|
|
|
41
37
|
*/
|
|
42
38
|
color?: string;
|
|
43
39
|
/**
|
|
44
|
-
* How thick the bar is, always
|
|
45
|
-
*
|
|
46
|
-
* explicit thickness.
|
|
40
|
+
* How thick the bar is, always in PIXELS: `12` and `'12'` both give 12px. It is 4px by
|
|
41
|
+
* default, and showing text inside a bar that thin needs an explicit thickness.
|
|
47
42
|
*/
|
|
48
43
|
thickness?: number | string;
|
|
49
44
|
/** Whether the ends of the bar are rounded or square. */
|
|
@@ -62,13 +57,7 @@ interface ProgressLinearProps {
|
|
|
62
57
|
orientation?: ProgressLinearOrientation;
|
|
63
58
|
}
|
|
64
59
|
type __VLS_Slots = {
|
|
65
|
-
/**
|
|
66
|
-
* What to write inside the bar instead of the percentage.
|
|
67
|
-
*
|
|
68
|
-
* It is rendered TWICE, once over the empty track and once over the filled part in a
|
|
69
|
-
* colour that contrasts with it, each copy cut at the fill's edge. So whatever it renders
|
|
70
|
-
* must be pure: anything with a side effect would happen twice.
|
|
71
|
-
*/
|
|
60
|
+
/** What to write inside the bar instead of the percentage. */
|
|
72
61
|
default?(props: ProgressLinearSlotProps): unknown;
|
|
73
62
|
};
|
|
74
63
|
declare const __VLS_base: import('vue').DefineComponent<ProgressLinearProps, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<ProgressLinearProps> & Readonly<{}>, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VProgressLinear.js","names":[],"sources":["../../../src/components/VProgressLinear/VProgressLinear.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * A bar filling up as something progresses. The element rendered IS the track, and the\n * whole geometry follows from a single number set on it — the fraction filled, with no\n * unit. Everything is written in logical properties, so turning the bar vertical needs\n * nothing but a change of writing direction.\n *\n * There is no behavioural JavaScript: the value is clamped and a percentage is\n * formatted, and that is all.\n *\n * On naming: pass a `label` saying what is progressing. The text shown inside the\n * bar cannot serve as that name — the role a progress bar carries makes its content\n * presentational, so screen readers do not announce it.\n */\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useProgressValue } from '../../composables/useProgressValue'\nimport { useMessages } from '../../i18n/state'\nimport { px } from '../../utils/css'\n\n/** What the progress means, in colour. */\nexport type ProgressLinearTone = 'neutral' | 'accent' | 'danger' | 'success' | 'warning'\n\n/** How the track and the fill end. */\nexport type ProgressLinearShape = 'rounded' | 'square'\n\n/** Where the value sits along the bar. */\nexport type ProgressLinearValuePosition = 'start' | 'center' | 'end'\n\n/** Which way the bar fills. */\nexport type ProgressLinearOrientation = 'horizontal' | 'vertical'\n\n/** What the default slot receives. */\nexport interface ProgressLinearSlotProps {\n /** The value, brought back into the range. */\n value: number\n /** The bound, zero or more. */\n max: number\n /** How far along it is, as a percentage and unrounded. */\n percent: number\n}\n\ninterface ProgressLinearProps {\n /** How far along it is. Anything outside the range is brought back into it. */\n value?: number\n /**\n * What is progressing, in words, for screen readers. It draws nothing on screen, and falls\n * back to the design system dictionary; an `aria-label` or `aria-labelledby` of your own\n * takes precedence over it.\n */\n label?: string\n /** What counts as finished. The other end is always zero. */\n max?: number\n /**\n * Says that the progress cannot be measured: the bar animates continuously and the\n * value is ignored. It is what to use while waiting for a server that reports no\n * percentage.\n */\n indeterminate?: boolean\n /** What the progress means, expressed as a colour. */\n tone?: ProgressLinearTone\n /**\n * A colour of your own (hex, CSS name or `oklch()`), which replaces the tone. The\n * track's own shade is derived from it against the theme, so it follows the light and\n * the dark one.\n */\n color?: string\n /**\n * How thick the bar is, always IN PIXELS: `12` and `'12'` both give 12px. It is 4px\n * by default, and showing text inside a bar that thin needs an\n * explicit thickness.\n */\n thickness?: number | string\n /** Whether the ends of the bar are rounded or square. */\n shape?: ProgressLinearShape\n /**\n * Writes the percentage inside the bar. It is ignored while the progress is\n * unmeasurable, there being no figure to write.\n */\n showValue?: boolean\n /**\n * Where that text sits along the bar. On a vertical bar the start is the zero end,\n * hence the bottom.\n */\n valuePosition?: ProgressLinearValuePosition\n /** Turns the bar upright, filling from the bottom up. */\n orientation?: ProgressLinearOrientation\n}\n\nconst props = withDefaults(defineProps<ProgressLinearProps>(), {\n value: 0,\n label: undefined,\n max: 100,\n indeterminate: false,\n tone: 'accent',\n color: undefined,\n thickness: undefined,\n shape: 'rounded',\n showValue: false,\n valuePosition: 'center',\n orientation: 'horizontal',\n})\n\ndefineSlots<{\n /**\n * What to write inside the bar instead of the percentage.\n *\n * It is rendered TWICE, once over the empty track and once over the filled part in a\n * colour that contrasts with it, each copy cut at the fill's edge. So whatever it renders\n * must be pure: anything with a side effect would happen twice.\n */\n default?(props: ProgressLinearSlotProps): unknown\n}>()\n\n/* The percent sign, and the non-breaking space French puts before it where English puts\n nothing, are a convention of the language: they belong in the dictionary rather than\n in this file. Any other format goes through the slot above. */\nconst m = useMessages()\n\nconst {\n max: normalizedMax,\n clamped,\n fraction,\n percent,\n roundedPercent,\n} = useProgressValue(\n () => props.value,\n () => props.max,\n)\n\n// @a11y\n// The canonical cascade: a consumer's `aria-labelledby`, then their `aria-label`, then the\n// `label` prop, then the dictionary. An indicator takes no name from the text inside it, so\n// without the last step it would have none at all.\nconst ariaLabel = useAriaLabel(() => props.label ?? m.value.progress.label)\n</script>\n\n<template>\n <div\n class=\"v-progress-linear v-tone\"\n role=\"progressbar\"\n :aria-label=\"ariaLabel\"\n :data-tone=\"tone\"\n :data-custom=\"color !== undefined ? '' : undefined\"\n :data-shape=\"shape\"\n :data-orientation=\"orientation\"\n :data-value-position=\"valuePosition\"\n :data-indeterminate=\"indeterminate ? '' : undefined\"\n :aria-valuenow=\"indeterminate ? undefined : clamped\"\n aria-valuemin=\"0\"\n :aria-valuemax=\"normalizedMax\"\n :style=\"{\n '--fill-fraction': String(fraction),\n '--custom-color': color,\n '--progress-thickness': px(thickness),\n }\"\n >\n <span class=\"v-progress-linear-fill\" />\n <!--\n The same text twice, each copy cut at the fill's edge so that the two complete\n each other exactly: the first in the ordinary text colour over the empty track,\n the second over the filled part, coloured to contrast with it. The second is\n hidden from screen readers, being a duplicate of text already there.\n -->\n <template v-if=\"!indeterminate && (showValue || $slots.default)\">\n <span class=\"v-progress-linear-text\">\n <slot :value=\"clamped\" :max=\"normalizedMax\" :percent=\"percent\">\n {{ m.progress.percent(roundedPercent) }}\n </slot>\n </span>\n <span class=\"v-progress-linear-text\" data-on-fill aria-hidden=\"true\">\n <slot :value=\"clamped\" :max=\"normalizedMax\" :percent=\"percent\">\n {{ m.progress.percent(roundedPercent) }}\n </slot>\n </span>\n </template>\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n /*\n * The element IS the track, and it takes the whole length available. Sizing it is the\n * consumer's business, through the parent or through a width of their own — a\n * consumer's style sits outside our layers and always wins.\n */\n .v-progress-linear {\n --progress-thickness: var(--vectis-control-size-progress-linear-thickness);\n /* Fill, track and the text over the fill are the tone's solid, soft and on-solid\n colours, read from the shared table (`.v-tone`, set in the template). */\n --progress-fill: var(--tone-bg-solid);\n --progress-track: var(--tone-bg-soft);\n --progress-text-fallback: var(--tone-text-solid);\n position: relative;\n display: block;\n inline-size: 100%;\n block-size: var(--progress-thickness);\n border-radius: var(--vectis-radius-pill);\n background: var(--progress-track);\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 .v-progress-linear[data-shape='square'] {\n border-radius: 0;\n }\n\n .v-progress-linear-fill {\n position: absolute;\n inset-block: 0;\n inset-inline-start: 0;\n inline-size: calc(100% * var(--fill-fraction));\n border-radius: inherit;\n background: var(--progress-fill);\n /*\n * The fill is animated by changing its LENGTH, which the browser has to lay out\n * again on every frame. Scaling it would be cheaper, but a scale is physical: it\n * would have to be undone for the vertical orientation and again for a\n * right-to-left page, where a logical length simply works.\n *\n * The duration and easing are repeated by the clip of the text over the fill, or the\n * colour boundary would drift away from the fill's own edge for the length of the\n * transition.\n */\n transition: inline-size var(--vectis-duration-base) var(--vectis-ease-default);\n }\n\n /* The text inside the bar, in two copies laid over the same box — the track's own,\n which is why a cut expressed as a fraction of it lands exactly on the fill's edge.\n Bear in mind that the default 4px thickness cannot hold text at all: showing any\n implies asking for a thicker bar.\n\n TRAP — the two copies are COMPLEMENTARY and never superimposed: this one is cut OUT\n of the filled part, the other cut TO it, so every letter is painted exactly once.\n Removing either clip raises no error and stays invisible for as long as both copies\n resolve to the SAME colour, which is what happens wherever the adaptive colour\n function is unsupported. Where it IS supported and the two disagree — black over an\n accent fill against white text in the dark theme — the copy underneath shows its\n antialiased edges all around the letters of the one on top, and the label reads as\n a halo. */\n .v-progress-linear-text {\n /* The two insets of the cut: one on the edge the fill grows FROM, one on the edge it\n grows towards. They are named after those roles rather than after physical sides,\n so the three geometry rules further down — horizontal, right-to-left, vertical —\n all read the same pair. This copy cuts on the start side; the one over the fill\n swaps them. */\n --progress-clip-start: calc(100% * var(--fill-fraction));\n --progress-clip-end: -100vmax;\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n padding-inline: var(--vectis-space-2);\n color: var(--vectis-color-text);\n /* The large negative inset on the two sides that do NOT carry the cut is what stops\n text taller or wider than the bar from being cropped by its own clip. */\n clip-path: inset(-100vmax var(--progress-clip-end) -100vmax var(--progress-clip-start));\n /* The same duration and easing as the fill's own length, or the colour boundary\n would drift away from the fill's edge for the length of the transition. */\n transition: clip-path var(--vectis-duration-base) var(--vectis-ease-default);\n /* The bar itself is turned on its side in vertical mode; the text is put back\n upright here, since a label read sideways is not the point. */\n writing-mode: horizontal-tb;\n white-space: nowrap;\n pointer-events: none;\n }\n\n .v-progress-linear[data-value-position='start'] .v-progress-linear-text {\n justify-content: start;\n }\n\n .v-progress-linear[data-value-position='end'] .v-progress-linear-text {\n justify-content: end;\n }\n\n .v-progress-linear-text[data-on-fill] {\n /* The exact complement of the copy above: the cut moves to the other end of the\n axis, so the two together cover the whole bar and overlap nowhere. */\n --progress-clip-start: -100vmax;\n --progress-clip-end: calc(100% * (1 - var(--fill-fraction)));\n /* The per-tone fallback colour. The adaptive one cannot simply be written as a\n second declaration after it: because that declaration contains a var(), a browser\n with no support does not reject it at parse time — it would win the cascade and\n only then turn invalid, which resets the colour to inherited and leaves the\n fallback never applied. The block below is the way round it, being evaluated\n before any var() substitution. */\n color: var(--progress-text-fallback);\n }\n\n /* Where the adaptive colour function exists, the text picks black or white against\n whatever colour the fill ended up with. */\n @supports (color: contrast-color(red)) {\n .v-progress-linear-text[data-on-fill] {\n color: contrast-color(var(--progress-fill));\n }\n }\n\n /* In a right-to-left page the fill grows from the right, so the two insets change\n physical sides — the variables themselves keep their meaning. */\n .v-progress-linear:dir(rtl) .v-progress-linear-text {\n clip-path: inset(-100vmax var(--progress-clip-start) -100vmax var(--progress-clip-end));\n }\n\n /* Upright, the bar fills from the bottom.\n\n Changing the writing direction on the element is enough to turn everything: the\n axis the fill grows along becomes vertical, so the length and the thickness swap\n places, and both the fill and the animation follow with no rule written twice.\n\n TRAP — putting zero at the bottom is NOT done by reversing the direction, which\n would also apply to the text of the two copies: bidirectional reordering would then\n display \"50 %\" as \"% 50\". The fill is anchored to the far end of the axis instead.\n\n The length comes from a token because there is nothing to inherit it from: in a\n parent of automatic height the bar would collapse to nothing. A consumer's own\n height overrides it, sitting outside our layers. */\n .v-progress-linear[data-orientation='vertical'] {\n writing-mode: vertical-lr;\n inline-size: var(--vectis-control-size-progress-linear-length);\n }\n\n .v-progress-linear[data-orientation='vertical'] .v-progress-linear-fill {\n inset-inline-start: auto;\n inset-inline-end: 0;\n }\n\n /* TRAP — a right-to-left page reverses the inline axis of a vertical writing mode too:\n `vertical-lr` then runs from the bottom up, so the far end anchored above is the TOP.\n The fill goes back to the start of the axis, which is now the bottom. Without this\n rule the bar fills downwards, and the clip of the text, which assumes a fill rising\n from the bottom, paints each copy over the wrong ground. */\n .v-progress-linear[data-orientation='vertical']:dir(rtl) .v-progress-linear-fill {\n inset-inline-start: 0;\n inset-inline-end: auto;\n }\n\n /* The text now stacks along the vertical axis, whose start is the zero end — the\n bottom of the bar. */\n .v-progress-linear[data-orientation='vertical'] .v-progress-linear-text {\n flex-direction: column-reverse;\n padding-inline: 0;\n padding-block: var(--vectis-space-2);\n }\n\n /* The cut moves to the vertical axis: the fill rises from the bottom, which is that\n axis' start. It is therefore the same in both reading directions, which means the\n right-to-left rule further up has to be neutralized.\n\n TRAP — the second selector is what neutralizes it, and it is written that way on\n purpose: it is one step MORE specific than that rule, where the first selector alone\n would merely tie with it and win by source order — a far more fragile arrangement. */\n .v-progress-linear[data-orientation='vertical'] .v-progress-linear-text,\n .v-progress-linear[data-orientation='vertical']:dir(rtl) .v-progress-linear-text {\n clip-path: inset(var(--progress-clip-end) -100vmax var(--progress-clip-start) -100vmax);\n }\n\n /* When the progress cannot be measured, a bar of fixed size crosses the track from\n just outside one end to just outside the other. At each extreme it is exactly flush\n with the edge without ever pulling away from it, which is what makes the loop\n invisible and keeps the track from ever looking empty — no second bar is needed.\n\n The easing carries the whole impression: a gradual entry, a quick crossing, a damped\n exit. A linear run, or an asymmetric curve, immediately reads as mechanical.\n\n The movement is expressed in LOGICAL properties — a position and a size as\n percentages of the track — rather than as a transform. One definition then serves\n the horizontal, the vertical and the right-to-left cases, where a transform, being\n physical, would need its own keyframes per axis and a flip per direction. */\n .v-progress-linear[data-indeterminate] {\n overflow: hidden;\n }\n\n .v-progress-linear[data-indeterminate] .v-progress-linear-fill {\n /* The starting position is derived from this size, and the two must stay tied: that\n is what has the bar begin exactly off the track rather than half on it. */\n --progress-bar: 40%;\n /* The anchoring is put back at the start of the axis, vertical case included — where\n a measurable progress anchors at the far end instead. */\n inset-inline-start: 0;\n inset-inline-end: auto;\n inline-size: var(--progress-bar);\n /* The transition of a measurable progress has no place here: switching to this mode\n would otherwise be animated as the bar growing to its new size. */\n transition: none;\n animation: v-progress-linear-indeterminate var(--vectis-duration-1500) var(--vectis-ease-in-out)\n infinite;\n }\n\n @keyframes v-progress-linear-indeterminate {\n from {\n inset-inline-start: calc(-1 * var(--progress-bar));\n }\n\n to {\n inset-inline-start: 100%;\n }\n }\n\n /* Turned upright, the axis runs downwards, so the bar would travel from the top down —\n the opposite of a measurable fill, which rises from the bottom. The same keyframes\n are simply read backwards, which changes nothing else BECAUSE the easing curve is\n symmetric; an asymmetric one would need a second set of keyframes.\n\n A horizontal right-to-left page needs nothing: the logical inset already follows the\n reading direction. A vertical one does, below. */\n .v-progress-linear[data-orientation='vertical'][data-indeterminate] .v-progress-linear-fill {\n animation-direction: reverse;\n }\n\n /* On a right-to-left page the vertical axis already runs upwards (see the trap above),\n so the keyframes are read forwards again. */\n .v-progress-linear[data-orientation='vertical'][data-indeterminate]:dir(rtl)\n .v-progress-linear-fill {\n animation-direction: normal;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-progress-linear-fill,\n .v-progress-linear-text {\n transition: none;\n }\n\n /* Slowed down and not stopped: a motionless loader no longer says that anything is\n happening, which is the one thing it exists to say. */\n .v-progress-linear[data-indeterminate] .v-progress-linear-fill {\n animation-duration: var(--vectis-duration-5000);\n }\n }\n\n /* Windows forced colours repaint every background as Canvas, which takes the track and\n the fill away together and leaves a floating figure at best. The bar is drawn in the\n system colours instead, the VSlider pair: an edge in CanvasText for the track, the\n Highlight pair for the fill and the text over it. `forced-color-adjust` inherits, so\n both copies of the text are given their colour here too. */\n @media (forced-colors: active) {\n .v-progress-linear {\n forced-color-adjust: none;\n background: Canvas;\n box-shadow: inset 0 0 0 var(--vectis-control-border-width) CanvasText;\n }\n\n .v-progress-linear-fill {\n background: Highlight;\n }\n\n .v-progress-linear-text {\n color: CanvasText;\n }\n\n .v-progress-linear-text[data-on-fill] {\n color: HighlightText;\n }\n }\n}\n</style>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"VProgressLinear.js","names":[],"sources":["../../../src/components/VProgressLinear/VProgressLinear.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * CSS draws the fill. JavaScript normalizes values shared by geometry, slots and progressbar\n * ARIA attributes.\n */\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useProgressValue } from '../../composables/useProgressValue'\nimport { useMessages } from '../../i18n/state'\nimport { px } from '../../utils/css'\n\n/** What the progress means, in colour. */\nexport type ProgressLinearTone = 'neutral' | 'accent' | 'danger' | 'success' | 'warning'\n\n/** How the track and the fill end. */\nexport type ProgressLinearShape = 'rounded' | 'square'\n\n/** Where the value sits along the bar. */\nexport type ProgressLinearValuePosition = 'start' | 'center' | 'end'\n\n/** Which way the bar fills. */\nexport type ProgressLinearOrientation = 'horizontal' | 'vertical'\n\n/** What the default slot receives. */\nexport interface ProgressLinearSlotProps {\n /** The value, brought back into the range. */\n value: number\n /** The bound, zero or more. */\n max: number\n /** How far along it is, as a percentage and unrounded. */\n percent: number\n}\n\ninterface ProgressLinearProps {\n /** How far along it is. Anything outside the range is brought back into it. */\n value?: number\n /**\n * What is progressing, in words, for screen readers. It draws nothing on screen, and falls\n * back to the design system dictionary; an `aria-label` or `aria-labelledby` of your own\n * takes precedence over it.\n */\n label?: string\n /** What counts as finished. The other end is always zero. */\n max?: number\n /** It is what to use while waiting for a server that reports no percentage. */\n indeterminate?: boolean\n /** What the progress means, expressed as a colour. */\n tone?: ProgressLinearTone\n /**\n * A colour of your own (hex, CSS name or `oklch()`), which replaces the tone. The\n * track's own shade is derived from it against the theme, so it follows the light and\n * the dark one.\n */\n color?: string\n /**\n * How thick the bar is, always in PIXELS: `12` and `'12'` both give 12px. It is 4px by\n * default, and showing text inside a bar that thin needs an explicit thickness.\n */\n thickness?: number | string\n /** Whether the ends of the bar are rounded or square. */\n shape?: ProgressLinearShape\n /**\n * Writes the percentage inside the bar. It is ignored while the progress is\n * unmeasurable, there being no figure to write.\n */\n showValue?: boolean\n /**\n * Where that text sits along the bar. On a vertical bar the start is the zero end,\n * hence the bottom.\n */\n valuePosition?: ProgressLinearValuePosition\n /** Turns the bar upright, filling from the bottom up. */\n orientation?: ProgressLinearOrientation\n}\n\nconst props = withDefaults(defineProps<ProgressLinearProps>(), {\n value: 0,\n label: undefined,\n max: 100,\n indeterminate: false,\n tone: 'accent',\n color: undefined,\n thickness: undefined,\n shape: 'rounded',\n showValue: false,\n valuePosition: 'center',\n orientation: 'horizontal',\n})\n\ndefineSlots<{\n /** What to write inside the bar instead of the percentage. */\n default?(props: ProgressLinearSlotProps): unknown\n}>()\n\n/* The percent sign, and the non-breaking space French puts before it where English puts\n nothing, are a convention of the language: they belong in the dictionary rather than\n in this file. Any other format goes through the slot above. */\nconst m = useMessages()\n\nconst {\n max: normalizedMax,\n clamped,\n fraction,\n percent,\n roundedPercent,\n} = useProgressValue(\n () => props.value,\n () => props.max,\n)\n\n// @a11y\n// The canonical cascade: a consumer's `aria-labelledby`, then their `aria-label`, then the\n// `label` prop, then the dictionary. An indicator takes no name from the text inside it, so\n// without the last step it would have none at all.\nconst ariaLabel = useAriaLabel(() => props.label ?? m.value.progress.label)\n</script>\n\n<template>\n <div\n class=\"v-progress-linear v-tone\"\n role=\"progressbar\"\n :aria-label=\"ariaLabel\"\n :data-tone=\"tone\"\n :data-custom=\"color !== undefined ? '' : undefined\"\n :data-shape=\"shape\"\n :data-orientation=\"orientation\"\n :data-value-position=\"valuePosition\"\n :data-indeterminate=\"indeterminate ? '' : undefined\"\n :aria-valuenow=\"indeterminate ? undefined : clamped\"\n aria-valuemin=\"0\"\n :aria-valuemax=\"normalizedMax\"\n :style=\"{\n '--fill-fraction': String(fraction),\n '--custom-color': color,\n '--progress-thickness': px(thickness),\n }\"\n >\n <span class=\"v-progress-linear-fill\" />\n <!--\n The same text twice, each copy cut at the fill's edge so that the two complete\n each other exactly: the first in the ordinary text colour over the empty track,\n the second over the filled part, coloured to contrast with it. The second is\n hidden from screen readers, being a duplicate of text already there.\n -->\n <template v-if=\"!indeterminate && (showValue || $slots.default)\">\n <span class=\"v-progress-linear-text\">\n <slot :value=\"clamped\" :max=\"normalizedMax\" :percent=\"percent\">\n {{ m.progress.percent(roundedPercent) }}\n </slot>\n </span>\n <span class=\"v-progress-linear-text\" data-on-fill aria-hidden=\"true\">\n <slot :value=\"clamped\" :max=\"normalizedMax\" :percent=\"percent\">\n {{ m.progress.percent(roundedPercent) }}\n </slot>\n </span>\n </template>\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n /*\n * The element IS the track, and it takes the whole length available. Sizing it is the\n * consumer's business, through the parent or through a width of their own; a consumer's style\n * sits outside our layers and always wins.\n */\n .v-progress-linear {\n --progress-thickness: var(--vectis-control-size-progress-linear-thickness);\n /* Fill, track and the text over the fill are the tone's solid, soft and on-solid\n colours, read from the shared table (`.v-tone`, set in the template). */\n --progress-fill: var(--tone-bg-solid);\n --progress-track: var(--tone-bg-soft);\n --progress-text-fallback: var(--tone-text-solid);\n position: relative;\n display: block;\n inline-size: 100%;\n block-size: var(--progress-thickness);\n border-radius: var(--vectis-radius-pill);\n background: var(--progress-track);\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 .v-progress-linear[data-shape='square'] {\n border-radius: 0;\n }\n\n .v-progress-linear-fill {\n position: absolute;\n inset-block: 0;\n inset-inline-start: 0;\n inline-size: calc(100% * var(--fill-fraction));\n border-radius: inherit;\n background: var(--progress-fill);\n /*\n * The fill is animated by changing its LENGTH, which the browser has to lay out again on\n * every frame. Scaling it would be cheaper, but a scale is physical: it would have to be\n * undone for the vertical orientation and again for a right-to-left page, where a logical\n * length simply works.\n */\n transition: inline-size var(--vectis-duration-base) var(--vectis-ease-default);\n }\n\n /*\n * The two copies are COMPLEMENTARY and never superimposed: this one is cut OUT of the filled\n * part, the other cut TO it, so every letter is painted exactly once. Removing either clip\n * raises no error and stays invisible for as long as both copies resolve to the same colour,\n * which happens wherever the adaptive colour function is unsupported.\n */\n .v-progress-linear-text {\n /*\n * The two insets of the cut: one on the edge the fill grows FROM, one on the edge it grows\n * towards. They are named after those roles rather than after physical sides, so the three\n * geometry rules further down; horizontal, right-to-left, vertical; all read the same pair.\n */\n --progress-clip-start: calc(100% * var(--fill-fraction));\n --progress-clip-end: -100vmax;\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n padding-inline: var(--vectis-space-2);\n color: var(--vectis-color-text);\n /*\n * The large negative inset on the two sides that do not carry the cut is what stops text\n * taller or wider than the bar from being cropped by its own clip.\n */\n clip-path: inset(-100vmax var(--progress-clip-end) -100vmax var(--progress-clip-start));\n /* The same duration and easing as the fill's own length, or the colour boundary\n would drift away from the fill's edge for the length of the transition. */\n transition: clip-path var(--vectis-duration-base) var(--vectis-ease-default);\n /* The bar itself is turned on its side in vertical mode; the text is put back\n upright here, since a label read sideways is not the point. */\n writing-mode: horizontal-tb;\n white-space: nowrap;\n pointer-events: none;\n }\n\n .v-progress-linear[data-value-position='start'] .v-progress-linear-text {\n justify-content: start;\n }\n\n .v-progress-linear[data-value-position='end'] .v-progress-linear-text {\n justify-content: end;\n }\n\n .v-progress-linear-text[data-on-fill] {\n /* The exact complement of the copy above: the cut moves to the other end of the\n axis, so the two together cover the whole bar and overlap nowhere. */\n --progress-clip-start: -100vmax;\n --progress-clip-end: calc(100% * (1 - var(--fill-fraction)));\n /*\n * The per-tone fallback colour. The adaptive one cannot simply be written as a second\n * declaration after it: because that declaration contains a var(), a browser with no\n * support does not reject it at parse time; it would win the cascade and only then turn\n * invalid, which resets the colour to inherited and leaves the fallback never applied.\n */\n color: var(--progress-text-fallback);\n }\n\n /* Where the adaptive colour function exists, the text picks black or white against\n whatever colour the fill ended up with. */\n @supports (color: contrast-color(red)) {\n .v-progress-linear-text[data-on-fill] {\n color: contrast-color(var(--progress-fill));\n }\n }\n\n /*\n * In a right-to-left page the fill grows from the right, so the two insets change physical\n * sides; the variables themselves keep their meaning.\n */\n .v-progress-linear:dir(rtl) .v-progress-linear-text {\n clip-path: inset(-100vmax var(--progress-clip-start) -100vmax var(--progress-clip-end));\n }\n\n /*\n * Putting zero at the bottom is not done by reversing the direction, which would also apply\n * to the text of the two copies: bidirectional reordering would then display \"50 %\" as \"%\n * 50\". The fill is anchored to the far end of the axis instead.\n */\n .v-progress-linear[data-orientation='vertical'] {\n writing-mode: vertical-lr;\n inline-size: var(--vectis-control-size-progress-linear-length);\n }\n\n .v-progress-linear[data-orientation='vertical'] .v-progress-linear-fill {\n inset-inline-start: auto;\n inset-inline-end: 0;\n }\n\n /*\n * A right-to-left page reverses the inline axis of a vertical writing mode too: `vertical-lr`\n * then runs from the bottom up, so the far end anchored above is the TOP. The fill goes back\n * to the start of the axis, which is now the bottom.\n */\n .v-progress-linear[data-orientation='vertical']:dir(rtl) .v-progress-linear-fill {\n inset-inline-start: 0;\n inset-inline-end: auto;\n }\n\n .v-progress-linear[data-orientation='vertical'] .v-progress-linear-text {\n flex-direction: column-reverse;\n padding-inline: 0;\n padding-block: var(--vectis-space-2);\n }\n\n /*\n * The second selector is what neutralizes it, and it is written that way on purpose: it is\n * one step MORE specific than that rule, where the first selector alone would merely tie with\n * it and win by source order; a far more fragile arrangement.\n */\n .v-progress-linear[data-orientation='vertical'] .v-progress-linear-text,\n .v-progress-linear[data-orientation='vertical']:dir(rtl) .v-progress-linear-text {\n clip-path: inset(var(--progress-clip-end) -100vmax var(--progress-clip-start) -100vmax);\n }\n\n /*\n * At each extreme it is exactly flush with the edge without ever pulling away from it, which\n * makes the loop invisible and keeps the track from ever looking empty; no second bar is\n * needed. The easing carries the whole impression: a gradual entry, a quick crossing, a\n * damped exit.\n */\n .v-progress-linear[data-indeterminate] {\n overflow: hidden;\n }\n\n .v-progress-linear[data-indeterminate] .v-progress-linear-fill {\n /* The starting position is derived from this size, and the two must stay tied: that\n is what has the bar begin exactly off the track rather than half on it. */\n --progress-bar: 40%;\n /*\n * The anchoring is put back at the start of the axis, vertical case included; where a\n * measurable progress anchors at the far end instead.\n */\n inset-inline-start: 0;\n inset-inline-end: auto;\n inline-size: var(--progress-bar);\n /* The transition of a measurable progress has no place here: switching to this mode\n would otherwise be animated as the bar growing to its new size. */\n transition: none;\n animation: v-progress-linear-indeterminate var(--vectis-duration-1500) var(--vectis-ease-in-out)\n infinite;\n }\n\n @keyframes v-progress-linear-indeterminate {\n from {\n inset-inline-start: calc(-1 * var(--progress-bar));\n }\n\n to {\n inset-inline-start: 100%;\n }\n }\n\n /*\n * The same keyframes are simply read backwards, which changes nothing else BECAUSE the easing\n * curve is symmetric; an asymmetric one would need a second set of keyframes. A horizontal\n * right-to-left page needs nothing: the logical inset already follows the reading direction.\n */\n .v-progress-linear[data-orientation='vertical'][data-indeterminate] .v-progress-linear-fill {\n animation-direction: reverse;\n }\n\n /* On a right-to-left page the vertical axis already runs upwards (see the trap above),\n so the keyframes are read forwards again. */\n .v-progress-linear[data-orientation='vertical'][data-indeterminate]:dir(rtl)\n .v-progress-linear-fill {\n animation-direction: normal;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-progress-linear-fill,\n .v-progress-linear-text {\n transition: none;\n }\n\n .v-progress-linear[data-indeterminate] .v-progress-linear-fill {\n animation-duration: var(--vectis-duration-5000);\n }\n }\n\n /* `forced-color-adjust` inherits, so both copies of the text are given their colour here too. */\n @media (forced-colors: active) {\n .v-progress-linear {\n forced-color-adjust: none;\n background: Canvas;\n box-shadow: inset 0 0 0 var(--vectis-control-border-width) CanvasText;\n }\n\n .v-progress-linear-fill {\n background: Highlight;\n }\n\n .v-progress-linear-text {\n color: CanvasText;\n }\n\n .v-progress-linear-text[data-on-fill] {\n color: HighlightText;\n }\n }\n}\n</style>\n"],"mappings":""}
|
package/dist/components/VProgressLinear/VProgressLinear.vue_vue_type_script_setup_true_lang.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VProgressLinear.vue_vue_type_script_setup_true_lang.js","names":["$slots"],"sources":["../../../src/components/VProgressLinear/VProgressLinear.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * A bar filling up as something progresses. The element rendered IS the track, and the\n * whole geometry follows from a single number set on it — the fraction filled, with no\n * unit. Everything is written in logical properties, so turning the bar vertical needs\n * nothing but a change of writing direction.\n *\n * There is no behavioural JavaScript: the value is clamped and a percentage is\n * formatted, and that is all.\n *\n * On naming: pass a `label` saying what is progressing. The text shown inside the\n * bar cannot serve as that name — the role a progress bar carries makes its content\n * presentational, so screen readers do not announce it.\n */\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useProgressValue } from '../../composables/useProgressValue'\nimport { useMessages } from '../../i18n/state'\nimport { px } from '../../utils/css'\n\n/** What the progress means, in colour. */\nexport type ProgressLinearTone = 'neutral' | 'accent' | 'danger' | 'success' | 'warning'\n\n/** How the track and the fill end. */\nexport type ProgressLinearShape = 'rounded' | 'square'\n\n/** Where the value sits along the bar. */\nexport type ProgressLinearValuePosition = 'start' | 'center' | 'end'\n\n/** Which way the bar fills. */\nexport type ProgressLinearOrientation = 'horizontal' | 'vertical'\n\n/** What the default slot receives. */\nexport interface ProgressLinearSlotProps {\n /** The value, brought back into the range. */\n value: number\n /** The bound, zero or more. */\n max: number\n /** How far along it is, as a percentage and unrounded. */\n percent: number\n}\n\ninterface ProgressLinearProps {\n /** How far along it is. Anything outside the range is brought back into it. */\n value?: number\n /**\n * What is progressing, in words, for screen readers. It draws nothing on screen, and falls\n * back to the design system dictionary; an `aria-label` or `aria-labelledby` of your own\n * takes precedence over it.\n */\n label?: string\n /** What counts as finished. The other end is always zero. */\n max?: number\n /**\n * Says that the progress cannot be measured: the bar animates continuously and the\n * value is ignored. It is what to use while waiting for a server that reports no\n * percentage.\n */\n indeterminate?: boolean\n /** What the progress means, expressed as a colour. */\n tone?: ProgressLinearTone\n /**\n * A colour of your own (hex, CSS name or `oklch()`), which replaces the tone. The\n * track's own shade is derived from it against the theme, so it follows the light and\n * the dark one.\n */\n color?: string\n /**\n * How thick the bar is, always IN PIXELS: `12` and `'12'` both give 12px. It is 4px\n * by default, and showing text inside a bar that thin needs an\n * explicit thickness.\n */\n thickness?: number | string\n /** Whether the ends of the bar are rounded or square. */\n shape?: ProgressLinearShape\n /**\n * Writes the percentage inside the bar. It is ignored while the progress is\n * unmeasurable, there being no figure to write.\n */\n showValue?: boolean\n /**\n * Where that text sits along the bar. On a vertical bar the start is the zero end,\n * hence the bottom.\n */\n valuePosition?: ProgressLinearValuePosition\n /** Turns the bar upright, filling from the bottom up. */\n orientation?: ProgressLinearOrientation\n}\n\nconst props = withDefaults(defineProps<ProgressLinearProps>(), {\n value: 0,\n label: undefined,\n max: 100,\n indeterminate: false,\n tone: 'accent',\n color: undefined,\n thickness: undefined,\n shape: 'rounded',\n showValue: false,\n valuePosition: 'center',\n orientation: 'horizontal',\n})\n\ndefineSlots<{\n /**\n * What to write inside the bar instead of the percentage.\n *\n * It is rendered TWICE, once over the empty track and once over the filled part in a\n * colour that contrasts with it, each copy cut at the fill's edge. So whatever it renders\n * must be pure: anything with a side effect would happen twice.\n */\n default?(props: ProgressLinearSlotProps): unknown\n}>()\n\n/* The percent sign, and the non-breaking space French puts before it where English puts\n nothing, are a convention of the language: they belong in the dictionary rather than\n in this file. Any other format goes through the slot above. */\nconst m = useMessages()\n\nconst {\n max: normalizedMax,\n clamped,\n fraction,\n percent,\n roundedPercent,\n} = useProgressValue(\n () => props.value,\n () => props.max,\n)\n\n// @a11y\n// The canonical cascade: a consumer's `aria-labelledby`, then their `aria-label`, then the\n// `label` prop, then the dictionary. An indicator takes no name from the text inside it, so\n// without the last step it would have none at all.\nconst ariaLabel = useAriaLabel(() => props.label ?? m.value.progress.label)\n</script>\n\n<template>\n <div\n class=\"v-progress-linear v-tone\"\n role=\"progressbar\"\n :aria-label=\"ariaLabel\"\n :data-tone=\"tone\"\n :data-custom=\"color !== undefined ? '' : undefined\"\n :data-shape=\"shape\"\n :data-orientation=\"orientation\"\n :data-value-position=\"valuePosition\"\n :data-indeterminate=\"indeterminate ? '' : undefined\"\n :aria-valuenow=\"indeterminate ? undefined : clamped\"\n aria-valuemin=\"0\"\n :aria-valuemax=\"normalizedMax\"\n :style=\"{\n '--fill-fraction': String(fraction),\n '--custom-color': color,\n '--progress-thickness': px(thickness),\n }\"\n >\n <span class=\"v-progress-linear-fill\" />\n <!--\n The same text twice, each copy cut at the fill's edge so that the two complete\n each other exactly: the first in the ordinary text colour over the empty track,\n the second over the filled part, coloured to contrast with it. The second is\n hidden from screen readers, being a duplicate of text already there.\n -->\n <template v-if=\"!indeterminate && (showValue || $slots.default)\">\n <span class=\"v-progress-linear-text\">\n <slot :value=\"clamped\" :max=\"normalizedMax\" :percent=\"percent\">\n {{ m.progress.percent(roundedPercent) }}\n </slot>\n </span>\n <span class=\"v-progress-linear-text\" data-on-fill aria-hidden=\"true\">\n <slot :value=\"clamped\" :max=\"normalizedMax\" :percent=\"percent\">\n {{ m.progress.percent(roundedPercent) }}\n </slot>\n </span>\n </template>\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n /*\n * The element IS the track, and it takes the whole length available. Sizing it is the\n * consumer's business, through the parent or through a width of their own — a\n * consumer's style sits outside our layers and always wins.\n */\n .v-progress-linear {\n --progress-thickness: var(--vectis-control-size-progress-linear-thickness);\n /* Fill, track and the text over the fill are the tone's solid, soft and on-solid\n colours, read from the shared table (`.v-tone`, set in the template). */\n --progress-fill: var(--tone-bg-solid);\n --progress-track: var(--tone-bg-soft);\n --progress-text-fallback: var(--tone-text-solid);\n position: relative;\n display: block;\n inline-size: 100%;\n block-size: var(--progress-thickness);\n border-radius: var(--vectis-radius-pill);\n background: var(--progress-track);\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 .v-progress-linear[data-shape='square'] {\n border-radius: 0;\n }\n\n .v-progress-linear-fill {\n position: absolute;\n inset-block: 0;\n inset-inline-start: 0;\n inline-size: calc(100% * var(--fill-fraction));\n border-radius: inherit;\n background: var(--progress-fill);\n /*\n * The fill is animated by changing its LENGTH, which the browser has to lay out\n * again on every frame. Scaling it would be cheaper, but a scale is physical: it\n * would have to be undone for the vertical orientation and again for a\n * right-to-left page, where a logical length simply works.\n *\n * The duration and easing are repeated by the clip of the text over the fill, or the\n * colour boundary would drift away from the fill's own edge for the length of the\n * transition.\n */\n transition: inline-size var(--vectis-duration-base) var(--vectis-ease-default);\n }\n\n /* The text inside the bar, in two copies laid over the same box — the track's own,\n which is why a cut expressed as a fraction of it lands exactly on the fill's edge.\n Bear in mind that the default 4px thickness cannot hold text at all: showing any\n implies asking for a thicker bar.\n\n TRAP — the two copies are COMPLEMENTARY and never superimposed: this one is cut OUT\n of the filled part, the other cut TO it, so every letter is painted exactly once.\n Removing either clip raises no error and stays invisible for as long as both copies\n resolve to the SAME colour, which is what happens wherever the adaptive colour\n function is unsupported. Where it IS supported and the two disagree — black over an\n accent fill against white text in the dark theme — the copy underneath shows its\n antialiased edges all around the letters of the one on top, and the label reads as\n a halo. */\n .v-progress-linear-text {\n /* The two insets of the cut: one on the edge the fill grows FROM, one on the edge it\n grows towards. They are named after those roles rather than after physical sides,\n so the three geometry rules further down — horizontal, right-to-left, vertical —\n all read the same pair. This copy cuts on the start side; the one over the fill\n swaps them. */\n --progress-clip-start: calc(100% * var(--fill-fraction));\n --progress-clip-end: -100vmax;\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n padding-inline: var(--vectis-space-2);\n color: var(--vectis-color-text);\n /* The large negative inset on the two sides that do NOT carry the cut is what stops\n text taller or wider than the bar from being cropped by its own clip. */\n clip-path: inset(-100vmax var(--progress-clip-end) -100vmax var(--progress-clip-start));\n /* The same duration and easing as the fill's own length, or the colour boundary\n would drift away from the fill's edge for the length of the transition. */\n transition: clip-path var(--vectis-duration-base) var(--vectis-ease-default);\n /* The bar itself is turned on its side in vertical mode; the text is put back\n upright here, since a label read sideways is not the point. */\n writing-mode: horizontal-tb;\n white-space: nowrap;\n pointer-events: none;\n }\n\n .v-progress-linear[data-value-position='start'] .v-progress-linear-text {\n justify-content: start;\n }\n\n .v-progress-linear[data-value-position='end'] .v-progress-linear-text {\n justify-content: end;\n }\n\n .v-progress-linear-text[data-on-fill] {\n /* The exact complement of the copy above: the cut moves to the other end of the\n axis, so the two together cover the whole bar and overlap nowhere. */\n --progress-clip-start: -100vmax;\n --progress-clip-end: calc(100% * (1 - var(--fill-fraction)));\n /* The per-tone fallback colour. The adaptive one cannot simply be written as a\n second declaration after it: because that declaration contains a var(), a browser\n with no support does not reject it at parse time — it would win the cascade and\n only then turn invalid, which resets the colour to inherited and leaves the\n fallback never applied. The block below is the way round it, being evaluated\n before any var() substitution. */\n color: var(--progress-text-fallback);\n }\n\n /* Where the adaptive colour function exists, the text picks black or white against\n whatever colour the fill ended up with. */\n @supports (color: contrast-color(red)) {\n .v-progress-linear-text[data-on-fill] {\n color: contrast-color(var(--progress-fill));\n }\n }\n\n /* In a right-to-left page the fill grows from the right, so the two insets change\n physical sides — the variables themselves keep their meaning. */\n .v-progress-linear:dir(rtl) .v-progress-linear-text {\n clip-path: inset(-100vmax var(--progress-clip-start) -100vmax var(--progress-clip-end));\n }\n\n /* Upright, the bar fills from the bottom.\n\n Changing the writing direction on the element is enough to turn everything: the\n axis the fill grows along becomes vertical, so the length and the thickness swap\n places, and both the fill and the animation follow with no rule written twice.\n\n TRAP — putting zero at the bottom is NOT done by reversing the direction, which\n would also apply to the text of the two copies: bidirectional reordering would then\n display \"50 %\" as \"% 50\". The fill is anchored to the far end of the axis instead.\n\n The length comes from a token because there is nothing to inherit it from: in a\n parent of automatic height the bar would collapse to nothing. A consumer's own\n height overrides it, sitting outside our layers. */\n .v-progress-linear[data-orientation='vertical'] {\n writing-mode: vertical-lr;\n inline-size: var(--vectis-control-size-progress-linear-length);\n }\n\n .v-progress-linear[data-orientation='vertical'] .v-progress-linear-fill {\n inset-inline-start: auto;\n inset-inline-end: 0;\n }\n\n /* TRAP — a right-to-left page reverses the inline axis of a vertical writing mode too:\n `vertical-lr` then runs from the bottom up, so the far end anchored above is the TOP.\n The fill goes back to the start of the axis, which is now the bottom. Without this\n rule the bar fills downwards, and the clip of the text, which assumes a fill rising\n from the bottom, paints each copy over the wrong ground. */\n .v-progress-linear[data-orientation='vertical']:dir(rtl) .v-progress-linear-fill {\n inset-inline-start: 0;\n inset-inline-end: auto;\n }\n\n /* The text now stacks along the vertical axis, whose start is the zero end — the\n bottom of the bar. */\n .v-progress-linear[data-orientation='vertical'] .v-progress-linear-text {\n flex-direction: column-reverse;\n padding-inline: 0;\n padding-block: var(--vectis-space-2);\n }\n\n /* The cut moves to the vertical axis: the fill rises from the bottom, which is that\n axis' start. It is therefore the same in both reading directions, which means the\n right-to-left rule further up has to be neutralized.\n\n TRAP — the second selector is what neutralizes it, and it is written that way on\n purpose: it is one step MORE specific than that rule, where the first selector alone\n would merely tie with it and win by source order — a far more fragile arrangement. */\n .v-progress-linear[data-orientation='vertical'] .v-progress-linear-text,\n .v-progress-linear[data-orientation='vertical']:dir(rtl) .v-progress-linear-text {\n clip-path: inset(var(--progress-clip-end) -100vmax var(--progress-clip-start) -100vmax);\n }\n\n /* When the progress cannot be measured, a bar of fixed size crosses the track from\n just outside one end to just outside the other. At each extreme it is exactly flush\n with the edge without ever pulling away from it, which is what makes the loop\n invisible and keeps the track from ever looking empty — no second bar is needed.\n\n The easing carries the whole impression: a gradual entry, a quick crossing, a damped\n exit. A linear run, or an asymmetric curve, immediately reads as mechanical.\n\n The movement is expressed in LOGICAL properties — a position and a size as\n percentages of the track — rather than as a transform. One definition then serves\n the horizontal, the vertical and the right-to-left cases, where a transform, being\n physical, would need its own keyframes per axis and a flip per direction. */\n .v-progress-linear[data-indeterminate] {\n overflow: hidden;\n }\n\n .v-progress-linear[data-indeterminate] .v-progress-linear-fill {\n /* The starting position is derived from this size, and the two must stay tied: that\n is what has the bar begin exactly off the track rather than half on it. */\n --progress-bar: 40%;\n /* The anchoring is put back at the start of the axis, vertical case included — where\n a measurable progress anchors at the far end instead. */\n inset-inline-start: 0;\n inset-inline-end: auto;\n inline-size: var(--progress-bar);\n /* The transition of a measurable progress has no place here: switching to this mode\n would otherwise be animated as the bar growing to its new size. */\n transition: none;\n animation: v-progress-linear-indeterminate var(--vectis-duration-1500) var(--vectis-ease-in-out)\n infinite;\n }\n\n @keyframes v-progress-linear-indeterminate {\n from {\n inset-inline-start: calc(-1 * var(--progress-bar));\n }\n\n to {\n inset-inline-start: 100%;\n }\n }\n\n /* Turned upright, the axis runs downwards, so the bar would travel from the top down —\n the opposite of a measurable fill, which rises from the bottom. The same keyframes\n are simply read backwards, which changes nothing else BECAUSE the easing curve is\n symmetric; an asymmetric one would need a second set of keyframes.\n\n A horizontal right-to-left page needs nothing: the logical inset already follows the\n reading direction. A vertical one does, below. */\n .v-progress-linear[data-orientation='vertical'][data-indeterminate] .v-progress-linear-fill {\n animation-direction: reverse;\n }\n\n /* On a right-to-left page the vertical axis already runs upwards (see the trap above),\n so the keyframes are read forwards again. */\n .v-progress-linear[data-orientation='vertical'][data-indeterminate]:dir(rtl)\n .v-progress-linear-fill {\n animation-direction: normal;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-progress-linear-fill,\n .v-progress-linear-text {\n transition: none;\n }\n\n /* Slowed down and not stopped: a motionless loader no longer says that anything is\n happening, which is the one thing it exists to say. */\n .v-progress-linear[data-indeterminate] .v-progress-linear-fill {\n animation-duration: var(--vectis-duration-5000);\n }\n }\n\n /* Windows forced colours repaint every background as Canvas, which takes the track and\n the fill away together and leaves a floating figure at best. The bar is drawn in the\n system colours instead, the VSlider pair: an edge in CanvasText for the track, the\n Highlight pair for the fill and the text over it. `forced-color-adjust` inherits, so\n both copies of the text are given their colour here too. */\n @media (forced-colors: active) {\n .v-progress-linear {\n forced-color-adjust: none;\n background: Canvas;\n box-shadow: inset 0 0 0 var(--vectis-control-border-width) CanvasText;\n }\n\n .v-progress-linear-fill {\n background: Highlight;\n }\n\n .v-progress-linear-text {\n color: CanvasText;\n }\n\n .v-progress-linear-text[data-on-fill] {\n color: HighlightText;\n }\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwFA,IAAM,IAAQ,GA4BR,IAAI,EAAY,GAEhB,EACJ,KAAK,GACL,YACA,aACA,YACA,sBACE,QACI,EAAM,aACN,EAAM,GACd,GAMM,IAAY,QAAmB,EAAM,SAAS,EAAE,MAAM,SAAS,KAAK;yBAIxE,EAsCM,OAAA;GArCJ,OAAM;GACN,MAAK;GACJ,cAAY,EAAA,CAAA;GACZ,aAAW,EAAA;GACX,eAAa,EAAA,UAAU,KAAA,IAAiB,KAAA,IAAR;GAChC,cAAY,EAAA;GACZ,oBAAkB,EAAA;GAClB,uBAAqB,EAAA;GACrB,sBAAoB,EAAA,gBAAa,KAAQ,KAAA;GACzC,iBAAe,EAAA,gBAAgB,KAAA,IAAY,EAAA,CAAA;GAC5C,iBAAc;GACb,iBAAe,EAAA,CAAA;GACf,OAAK,EAAA;uBAA6B,OAAO,EAAA,CAAA,CAAQ;sBAA2B,EAAA;4BAAqC,EAAA,CAAA,CAAE,CAAC,EAAA,SAAS;;eAM9H,EAAuC,QAAA,EAAjC,OAAM,yBAAwB,GAAA,MAAA,EAAA,GAAA,CAOnB,EAAA,kBAAkB,EAAA,aAAaA,EAAAA,OAAO,YAAA,EAAA,GAAvD,EAWW,GAAA,EAAA,KAAA,EAAA,GAAA,CAVT,EAIO,QAJP,GAIO,CAHL,EAEO,EAAA,QAAA,WAAA;GAFA,OAAO,EAAA,CAAA;GAAU,KAAK,EAAA,CAAA;GAAgB,SAAS,EAAA,CAAA;WAE/C,CAAA,EAAA,EADF,EAAA,CAAA,CAAC,CAAC,SAAS,QAAQ,EAAA,CAAA,CAAc,CAAA,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAGxC,EAIO,QAJP,GAIO,CAHL,EAEO,EAAA,QAAA,WAAA;GAFA,OAAO,EAAA,CAAA;GAAU,KAAK,EAAA,CAAA;GAAgB,SAAS,EAAA,CAAA;WAE/C,CAAA,EAAA,EADF,EAAA,CAAA,CAAC,CAAC,SAAS,QAAQ,EAAA,CAAA,CAAc,CAAA,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAAA,EAAA,KAAA,EAAA,IAAA,EAAA,CAAA,GAAA,IAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"VProgressLinear.vue_vue_type_script_setup_true_lang.js","names":["$slots"],"sources":["../../../src/components/VProgressLinear/VProgressLinear.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * CSS draws the fill. JavaScript normalizes values shared by geometry, slots and progressbar\n * ARIA attributes.\n */\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useProgressValue } from '../../composables/useProgressValue'\nimport { useMessages } from '../../i18n/state'\nimport { px } from '../../utils/css'\n\n/** What the progress means, in colour. */\nexport type ProgressLinearTone = 'neutral' | 'accent' | 'danger' | 'success' | 'warning'\n\n/** How the track and the fill end. */\nexport type ProgressLinearShape = 'rounded' | 'square'\n\n/** Where the value sits along the bar. */\nexport type ProgressLinearValuePosition = 'start' | 'center' | 'end'\n\n/** Which way the bar fills. */\nexport type ProgressLinearOrientation = 'horizontal' | 'vertical'\n\n/** What the default slot receives. */\nexport interface ProgressLinearSlotProps {\n /** The value, brought back into the range. */\n value: number\n /** The bound, zero or more. */\n max: number\n /** How far along it is, as a percentage and unrounded. */\n percent: number\n}\n\ninterface ProgressLinearProps {\n /** How far along it is. Anything outside the range is brought back into it. */\n value?: number\n /**\n * What is progressing, in words, for screen readers. It draws nothing on screen, and falls\n * back to the design system dictionary; an `aria-label` or `aria-labelledby` of your own\n * takes precedence over it.\n */\n label?: string\n /** What counts as finished. The other end is always zero. */\n max?: number\n /** It is what to use while waiting for a server that reports no percentage. */\n indeterminate?: boolean\n /** What the progress means, expressed as a colour. */\n tone?: ProgressLinearTone\n /**\n * A colour of your own (hex, CSS name or `oklch()`), which replaces the tone. The\n * track's own shade is derived from it against the theme, so it follows the light and\n * the dark one.\n */\n color?: string\n /**\n * How thick the bar is, always in PIXELS: `12` and `'12'` both give 12px. It is 4px by\n * default, and showing text inside a bar that thin needs an explicit thickness.\n */\n thickness?: number | string\n /** Whether the ends of the bar are rounded or square. */\n shape?: ProgressLinearShape\n /**\n * Writes the percentage inside the bar. It is ignored while the progress is\n * unmeasurable, there being no figure to write.\n */\n showValue?: boolean\n /**\n * Where that text sits along the bar. On a vertical bar the start is the zero end,\n * hence the bottom.\n */\n valuePosition?: ProgressLinearValuePosition\n /** Turns the bar upright, filling from the bottom up. */\n orientation?: ProgressLinearOrientation\n}\n\nconst props = withDefaults(defineProps<ProgressLinearProps>(), {\n value: 0,\n label: undefined,\n max: 100,\n indeterminate: false,\n tone: 'accent',\n color: undefined,\n thickness: undefined,\n shape: 'rounded',\n showValue: false,\n valuePosition: 'center',\n orientation: 'horizontal',\n})\n\ndefineSlots<{\n /** What to write inside the bar instead of the percentage. */\n default?(props: ProgressLinearSlotProps): unknown\n}>()\n\n/* The percent sign, and the non-breaking space French puts before it where English puts\n nothing, are a convention of the language: they belong in the dictionary rather than\n in this file. Any other format goes through the slot above. */\nconst m = useMessages()\n\nconst {\n max: normalizedMax,\n clamped,\n fraction,\n percent,\n roundedPercent,\n} = useProgressValue(\n () => props.value,\n () => props.max,\n)\n\n// @a11y\n// The canonical cascade: a consumer's `aria-labelledby`, then their `aria-label`, then the\n// `label` prop, then the dictionary. An indicator takes no name from the text inside it, so\n// without the last step it would have none at all.\nconst ariaLabel = useAriaLabel(() => props.label ?? m.value.progress.label)\n</script>\n\n<template>\n <div\n class=\"v-progress-linear v-tone\"\n role=\"progressbar\"\n :aria-label=\"ariaLabel\"\n :data-tone=\"tone\"\n :data-custom=\"color !== undefined ? '' : undefined\"\n :data-shape=\"shape\"\n :data-orientation=\"orientation\"\n :data-value-position=\"valuePosition\"\n :data-indeterminate=\"indeterminate ? '' : undefined\"\n :aria-valuenow=\"indeterminate ? undefined : clamped\"\n aria-valuemin=\"0\"\n :aria-valuemax=\"normalizedMax\"\n :style=\"{\n '--fill-fraction': String(fraction),\n '--custom-color': color,\n '--progress-thickness': px(thickness),\n }\"\n >\n <span class=\"v-progress-linear-fill\" />\n <!--\n The same text twice, each copy cut at the fill's edge so that the two complete\n each other exactly: the first in the ordinary text colour over the empty track,\n the second over the filled part, coloured to contrast with it. The second is\n hidden from screen readers, being a duplicate of text already there.\n -->\n <template v-if=\"!indeterminate && (showValue || $slots.default)\">\n <span class=\"v-progress-linear-text\">\n <slot :value=\"clamped\" :max=\"normalizedMax\" :percent=\"percent\">\n {{ m.progress.percent(roundedPercent) }}\n </slot>\n </span>\n <span class=\"v-progress-linear-text\" data-on-fill aria-hidden=\"true\">\n <slot :value=\"clamped\" :max=\"normalizedMax\" :percent=\"percent\">\n {{ m.progress.percent(roundedPercent) }}\n </slot>\n </span>\n </template>\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n /*\n * The element IS the track, and it takes the whole length available. Sizing it is the\n * consumer's business, through the parent or through a width of their own; a consumer's style\n * sits outside our layers and always wins.\n */\n .v-progress-linear {\n --progress-thickness: var(--vectis-control-size-progress-linear-thickness);\n /* Fill, track and the text over the fill are the tone's solid, soft and on-solid\n colours, read from the shared table (`.v-tone`, set in the template). */\n --progress-fill: var(--tone-bg-solid);\n --progress-track: var(--tone-bg-soft);\n --progress-text-fallback: var(--tone-text-solid);\n position: relative;\n display: block;\n inline-size: 100%;\n block-size: var(--progress-thickness);\n border-radius: var(--vectis-radius-pill);\n background: var(--progress-track);\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 .v-progress-linear[data-shape='square'] {\n border-radius: 0;\n }\n\n .v-progress-linear-fill {\n position: absolute;\n inset-block: 0;\n inset-inline-start: 0;\n inline-size: calc(100% * var(--fill-fraction));\n border-radius: inherit;\n background: var(--progress-fill);\n /*\n * The fill is animated by changing its LENGTH, which the browser has to lay out again on\n * every frame. Scaling it would be cheaper, but a scale is physical: it would have to be\n * undone for the vertical orientation and again for a right-to-left page, where a logical\n * length simply works.\n */\n transition: inline-size var(--vectis-duration-base) var(--vectis-ease-default);\n }\n\n /*\n * The two copies are COMPLEMENTARY and never superimposed: this one is cut OUT of the filled\n * part, the other cut TO it, so every letter is painted exactly once. Removing either clip\n * raises no error and stays invisible for as long as both copies resolve to the same colour,\n * which happens wherever the adaptive colour function is unsupported.\n */\n .v-progress-linear-text {\n /*\n * The two insets of the cut: one on the edge the fill grows FROM, one on the edge it grows\n * towards. They are named after those roles rather than after physical sides, so the three\n * geometry rules further down; horizontal, right-to-left, vertical; all read the same pair.\n */\n --progress-clip-start: calc(100% * var(--fill-fraction));\n --progress-clip-end: -100vmax;\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n padding-inline: var(--vectis-space-2);\n color: var(--vectis-color-text);\n /*\n * The large negative inset on the two sides that do not carry the cut is what stops text\n * taller or wider than the bar from being cropped by its own clip.\n */\n clip-path: inset(-100vmax var(--progress-clip-end) -100vmax var(--progress-clip-start));\n /* The same duration and easing as the fill's own length, or the colour boundary\n would drift away from the fill's edge for the length of the transition. */\n transition: clip-path var(--vectis-duration-base) var(--vectis-ease-default);\n /* The bar itself is turned on its side in vertical mode; the text is put back\n upright here, since a label read sideways is not the point. */\n writing-mode: horizontal-tb;\n white-space: nowrap;\n pointer-events: none;\n }\n\n .v-progress-linear[data-value-position='start'] .v-progress-linear-text {\n justify-content: start;\n }\n\n .v-progress-linear[data-value-position='end'] .v-progress-linear-text {\n justify-content: end;\n }\n\n .v-progress-linear-text[data-on-fill] {\n /* The exact complement of the copy above: the cut moves to the other end of the\n axis, so the two together cover the whole bar and overlap nowhere. */\n --progress-clip-start: -100vmax;\n --progress-clip-end: calc(100% * (1 - var(--fill-fraction)));\n /*\n * The per-tone fallback colour. The adaptive one cannot simply be written as a second\n * declaration after it: because that declaration contains a var(), a browser with no\n * support does not reject it at parse time; it would win the cascade and only then turn\n * invalid, which resets the colour to inherited and leaves the fallback never applied.\n */\n color: var(--progress-text-fallback);\n }\n\n /* Where the adaptive colour function exists, the text picks black or white against\n whatever colour the fill ended up with. */\n @supports (color: contrast-color(red)) {\n .v-progress-linear-text[data-on-fill] {\n color: contrast-color(var(--progress-fill));\n }\n }\n\n /*\n * In a right-to-left page the fill grows from the right, so the two insets change physical\n * sides; the variables themselves keep their meaning.\n */\n .v-progress-linear:dir(rtl) .v-progress-linear-text {\n clip-path: inset(-100vmax var(--progress-clip-start) -100vmax var(--progress-clip-end));\n }\n\n /*\n * Putting zero at the bottom is not done by reversing the direction, which would also apply\n * to the text of the two copies: bidirectional reordering would then display \"50 %\" as \"%\n * 50\". The fill is anchored to the far end of the axis instead.\n */\n .v-progress-linear[data-orientation='vertical'] {\n writing-mode: vertical-lr;\n inline-size: var(--vectis-control-size-progress-linear-length);\n }\n\n .v-progress-linear[data-orientation='vertical'] .v-progress-linear-fill {\n inset-inline-start: auto;\n inset-inline-end: 0;\n }\n\n /*\n * A right-to-left page reverses the inline axis of a vertical writing mode too: `vertical-lr`\n * then runs from the bottom up, so the far end anchored above is the TOP. The fill goes back\n * to the start of the axis, which is now the bottom.\n */\n .v-progress-linear[data-orientation='vertical']:dir(rtl) .v-progress-linear-fill {\n inset-inline-start: 0;\n inset-inline-end: auto;\n }\n\n .v-progress-linear[data-orientation='vertical'] .v-progress-linear-text {\n flex-direction: column-reverse;\n padding-inline: 0;\n padding-block: var(--vectis-space-2);\n }\n\n /*\n * The second selector is what neutralizes it, and it is written that way on purpose: it is\n * one step MORE specific than that rule, where the first selector alone would merely tie with\n * it and win by source order; a far more fragile arrangement.\n */\n .v-progress-linear[data-orientation='vertical'] .v-progress-linear-text,\n .v-progress-linear[data-orientation='vertical']:dir(rtl) .v-progress-linear-text {\n clip-path: inset(var(--progress-clip-end) -100vmax var(--progress-clip-start) -100vmax);\n }\n\n /*\n * At each extreme it is exactly flush with the edge without ever pulling away from it, which\n * makes the loop invisible and keeps the track from ever looking empty; no second bar is\n * needed. The easing carries the whole impression: a gradual entry, a quick crossing, a\n * damped exit.\n */\n .v-progress-linear[data-indeterminate] {\n overflow: hidden;\n }\n\n .v-progress-linear[data-indeterminate] .v-progress-linear-fill {\n /* The starting position is derived from this size, and the two must stay tied: that\n is what has the bar begin exactly off the track rather than half on it. */\n --progress-bar: 40%;\n /*\n * The anchoring is put back at the start of the axis, vertical case included; where a\n * measurable progress anchors at the far end instead.\n */\n inset-inline-start: 0;\n inset-inline-end: auto;\n inline-size: var(--progress-bar);\n /* The transition of a measurable progress has no place here: switching to this mode\n would otherwise be animated as the bar growing to its new size. */\n transition: none;\n animation: v-progress-linear-indeterminate var(--vectis-duration-1500) var(--vectis-ease-in-out)\n infinite;\n }\n\n @keyframes v-progress-linear-indeterminate {\n from {\n inset-inline-start: calc(-1 * var(--progress-bar));\n }\n\n to {\n inset-inline-start: 100%;\n }\n }\n\n /*\n * The same keyframes are simply read backwards, which changes nothing else BECAUSE the easing\n * curve is symmetric; an asymmetric one would need a second set of keyframes. A horizontal\n * right-to-left page needs nothing: the logical inset already follows the reading direction.\n */\n .v-progress-linear[data-orientation='vertical'][data-indeterminate] .v-progress-linear-fill {\n animation-direction: reverse;\n }\n\n /* On a right-to-left page the vertical axis already runs upwards (see the trap above),\n so the keyframes are read forwards again. */\n .v-progress-linear[data-orientation='vertical'][data-indeterminate]:dir(rtl)\n .v-progress-linear-fill {\n animation-direction: normal;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-progress-linear-fill,\n .v-progress-linear-text {\n transition: none;\n }\n\n .v-progress-linear[data-indeterminate] .v-progress-linear-fill {\n animation-duration: var(--vectis-duration-5000);\n }\n }\n\n /* `forced-color-adjust` inherits, so both copies of the text are given their colour here too. */\n @media (forced-colors: active) {\n .v-progress-linear {\n forced-color-adjust: none;\n background: Canvas;\n box-shadow: inset 0 0 0 var(--vectis-control-border-width) CanvasText;\n }\n\n .v-progress-linear-fill {\n background: Highlight;\n }\n\n .v-progress-linear-text {\n color: CanvasText;\n }\n\n .v-progress-linear-text[data-on-fill] {\n color: HighlightText;\n }\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0EA,IAAM,IAAQ,GAsBR,IAAI,EAAY,GAEhB,EACJ,KAAK,GACL,YACA,aACA,YACA,sBACE,QACI,EAAM,aACN,EAAM,GACd,GAMM,IAAY,QAAmB,EAAM,SAAS,EAAE,MAAM,SAAS,KAAK;yBAIxE,EAsCM,OAAA;GArCJ,OAAM;GACN,MAAK;GACJ,cAAY,EAAA,CAAA;GACZ,aAAW,EAAA;GACX,eAAa,EAAA,UAAU,KAAA,IAAiB,KAAA,IAAR;GAChC,cAAY,EAAA;GACZ,oBAAkB,EAAA;GAClB,uBAAqB,EAAA;GACrB,sBAAoB,EAAA,gBAAa,KAAQ,KAAA;GACzC,iBAAe,EAAA,gBAAgB,KAAA,IAAY,EAAA,CAAA;GAC5C,iBAAc;GACb,iBAAe,EAAA,CAAA;GACf,OAAK,EAAA;uBAA6B,OAAO,EAAA,CAAA,CAAQ;sBAA2B,EAAA;4BAAqC,EAAA,CAAA,CAAE,CAAC,EAAA,SAAS;;eAM9H,EAAuC,QAAA,EAAjC,OAAM,yBAAwB,GAAA,MAAA,EAAA,GAAA,CAOnB,EAAA,kBAAkB,EAAA,aAAaA,EAAAA,OAAO,YAAA,EAAA,GAAvD,EAWW,GAAA,EAAA,KAAA,EAAA,GAAA,CAVT,EAIO,QAJP,GAIO,CAHL,EAEO,EAAA,QAAA,WAAA;GAFA,OAAO,EAAA,CAAA;GAAU,KAAK,EAAA,CAAA;GAAgB,SAAS,EAAA,CAAA;WAE/C,CAAA,EAAA,EADF,EAAA,CAAA,CAAC,CAAC,SAAS,QAAQ,EAAA,CAAA,CAAc,CAAA,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAGxC,EAIO,QAJP,GAIO,CAHL,EAEO,EAAA,QAAA,WAAA;GAFA,OAAO,EAAA,CAAA;GAAU,KAAK,EAAA,CAAA;GAAgB,SAAS,EAAA,CAAA;WAE/C,CAAA,EAAA,EADF,EAAA,CAAA,CAAC,CAAC,SAAS,QAAQ,EAAA,CAAA,CAAc,CAAA,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAAA,EAAA,KAAA,EAAA,IAAA,EAAA,CAAA,GAAA,IAAA,CAAA"}
|
|
@@ -28,11 +28,7 @@ interface RadioProps {
|
|
|
28
28
|
invalid?: boolean;
|
|
29
29
|
/** Makes this choice unusable, greyed out through the colour tokens. */
|
|
30
30
|
disabled?: boolean;
|
|
31
|
-
/**
|
|
32
|
-
* Shows the selection without allowing it to be changed. The button can still be
|
|
33
|
-
* focused and is still submitted with its form; a click or an arrow key simply selects
|
|
34
|
-
* nothing. Set it on every button of the group.
|
|
35
|
-
*/
|
|
31
|
+
/** Shows the selection without allowing it to be changed. */
|
|
36
32
|
readonly?: boolean;
|
|
37
33
|
}
|
|
38
34
|
type __VLS_Props = RadioProps;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VRadio.js","names":[],"sources":["../../../src/components/VRadio/VRadio.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * A radio button whose dot is drawn by the design system, on the same principle as\n * VCheckbox: the real `<input type=\"radio\">` stays in place and only its own drawing\n * is hidden.\n *\n * The group is native as well. Several VRadio sharing the same `name` and the same\n * v-model form one choice, and it is the browser that then makes the arrow keys move\n * between them, that lets only one be selected, and that gives the group a single\n * stop in the tab order. There is no JavaScript here for any of it; the only piece this\n * component writes is the refusal `readonly` asks for, which a radio has no native form of.\n */\n\nimport { ref } from 'vue'\n\nimport { useFieldIds } from '../../composables/useFieldIds'\nimport { useRootAttrs } from '../../composables/useRootAttrs'\nimport type { ItemValue } from '../../types'\n\n/** Which side of the dot the label sits on. */\nexport type RadioLabelPosition = 'start' | 'end'\n\ninterface RadioProps {\n /**\n * What choosing this button means. The group's v-model holds the value of the\n * selected button, so this is what it becomes when this one is picked.\n */\n value: ItemValue\n /** The text beside the dot, which names it. The default slot replaces it. */\n label?: string\n /**\n * A line of help under the label. It is tied to the radio button for assistive\n * technology, so it is read out after the label rather than as part of it.\n */\n hint?: string\n /** Which side of the dot the label sits on. */\n labelPosition?: RadioLabelPosition\n /**\n * Pushes the label and the dot to opposite ends of the line, the row taking the\n * full width available.\n */\n spread?: boolean\n /**\n * Marks the field as invalid, which colours the dot and tells assistive technology\n * so. It is for a rule the browser cannot check by itself.\n */\n invalid?: boolean\n /** Makes this choice unusable, greyed out through the colour tokens. */\n disabled?: boolean\n /**\n * Shows the selection without allowing it to be changed. The button can still be\n * focused and is still submitted with its form; a click or an arrow key simply selects\n * nothing. Set it on every button of the group.\n */\n readonly?: boolean\n}\n\nconst props = withDefaults(defineProps<RadioProps>(), {\n label: undefined,\n hint: undefined,\n labelPosition: 'end',\n spread: false,\n invalid: false,\n disabled: false,\n readonly: false,\n})\n\n// @a11y — the redirection buys the whole keyboard. Moving between the buttons of a group is\n// the browser's job, but it only groups inputs that share a `name` — so redirecting the\n// attributes is what makes the arrow keys work at all. The root being a layout box, `name`\n// left on it would reach nothing.\ndefineOptions({ inheritAttrs: false })\nconst { attrs, rootClass, rootStyle, forwardedAttrs } = useRootAttrs()\nconst { hintId, describedBy } = useFieldIds(attrs, () => !!props.hint)\n\n/**\n * The value selected in the group, shared by every radio carrying the same `name`. It is\n * empty until one is chosen, and a radio is selected when it matches its own `value`.\n */\nconst model = defineModel<ItemValue>({ default: '' })\n\ndefineSlots<{\n /** The label, when it needs more than the `label` prop's text. It is clickable. */\n default?(): unknown\n}>()\n\nconst inputEl = ref<HTMLInputElement | null>(null)\n\n// @core\n// The native `readonly` attribute does nothing on a radio button. Cancelling the click is\n// what refuses the selection: the browser puts the group's previous selection back and fires\n// no `change`. It covers the arrow keys too, which select the next button of the group\n// through a click the browser dispatches on it — so the focus still moves, the selection\n// does not.\n//\n// No `aria-readonly` goes with it, unlike VCheckbox and VSwitch: ARIA allows it on a\n// `radiogroup` and not on a `radio`, and axe fails the page for it.\nfunction refuseWhenReadonly(event: MouseEvent) {\n if (props.readonly) event.preventDefault()\n}\n\n// The root is a wrapper, so a template ref on the component reaches the layout box and not\n// the control: these two are the way to the real radio button.\ndefineExpose({\n /** Moves the focus to the real radio button. */\n focus: (options?: FocusOptions) => inputEl.value?.focus(options),\n /** The real `<input type=\"radio\">`, for what `focus` does not cover. */\n el: inputEl,\n})\n</script>\n\n<template>\n <span\n class=\"v-radio v-choice\"\n :class=\"rootClass\"\n :style=\"rootStyle\"\n :data-label-position=\"labelPosition\"\n :data-spread=\"spread ? '' : undefined\"\n :data-readonly=\"readonly ? '' : undefined\"\n >\n <label class=\"v-choice-row\">\n <input\n ref=\"inputEl\"\n v-model=\"model\"\n type=\"radio\"\n class=\"v-radio-input v-hidden-input\"\n :aria-invalid=\"invalid || undefined\"\n v-bind=\"forwardedAttrs\"\n :value=\"value\"\n :disabled=\"disabled\"\n :aria-describedby=\"describedBy\"\n @click=\"refuseWhenReadonly\"\n />\n <span class=\"v-radio-dot\" aria-hidden=\"true\" />\n <span v-if=\"$slots.default || label\" class=\"v-radio-label v-choice-label\">\n <slot>{{ label }}</slot>\n </span>\n </label>\n <span v-if=\"hint\" :id=\"hintId\" class=\"v-radio-hint v-choice-hint\">{{ hint }}</span>\n </span>\n</template>\n\n<style>\n@layer vectis.components {\n /* The dot works exactly like VCheckbox's box, the accent filling it once the input is\n checked, with the small inner disc drawn as a pseudo-element in currentcolor so it\n follows whatever colour the state gives the ring's content. */\n .v-radio-dot {\n display: inline-grid;\n place-items: center;\n width: var(--vectis-control-size-check);\n height: var(--vectis-control-size-check);\n background: transparent;\n border: var(--vectis-control-border-width) solid var(--vectis-color-border-strong);\n border-radius: var(--vectis-radius-pill);\n color: var(--vectis-color-text-on-accent);\n transition:\n background-color var(--vectis-duration-fast) var(--vectis-ease-default),\n border-color var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n\n .v-radio-dot::before {\n content: '';\n width: var(--vectis-control-size-check-dot);\n height: var(--vectis-control-size-check-dot);\n border-radius: var(--vectis-radius-pill);\n background: currentcolor;\n opacity: 0;\n transition: opacity var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n\n .v-radio-input:checked + .v-radio-dot::before {\n opacity: 1;\n }\n\n /* The state painting, rule for rule the same as VCheckbox's with its own classes: keep the\n two ALIGNED. The states below weigh (0,3,0), bar the read-only base at (0,2,0), so their\n ORDER arbitrates them: checked, read-only, invalid, then disabled last.\n\n The two hovers sit at (0,7,0) and therefore beat every one of them on specificity, order\n or no order — which is why they have to EXCLUDE by hand each state they must not repaint.\n Forgetting the invalid pair is what once rubbed the danger border out under the pointer,\n on a control whose whole point at that moment is to look wrong. */\n .v-radio:not([data-readonly])\n .v-choice-row:hover\n .v-radio-input:not(:disabled, :checked, :user-invalid, [aria-invalid='true'])\n + .v-radio-dot {\n border-color: color-mix(\n in oklab,\n var(--vectis-color-border-strong),\n var(--vectis-color-text) 15%\n );\n }\n\n .v-radio-input:checked + .v-radio-dot {\n background: var(--vectis-color-accent);\n border-color: var(--vectis-color-accent);\n }\n\n .v-radio:not([data-readonly])\n .v-choice-row:hover\n .v-radio-input:not(:disabled, :user-invalid, [aria-invalid='true']):checked\n + .v-radio-dot {\n background: var(--vectis-color-accent-hover);\n border-color: var(--vectis-color-accent-hover);\n }\n\n /* Read-only sinks like a read-only field, and a selected control trades the accent for the\n muted text colour: still plainly on, no longer inviting a click. The inner disc takes the\n surface colour, which contrasts with that fill in both themes, where white would vanish\n against the light grey of the dark theme. `:where()` keeps both rules at the weight of\n the states they sit between. */\n :where(.v-radio[data-readonly]) .v-radio-input + .v-radio-dot {\n background: var(--vectis-color-surface-sunken);\n border-color: var(--vectis-color-border);\n }\n\n :where(.v-radio[data-readonly]) .v-radio-input:checked + .v-radio-dot {\n background: var(--vectis-color-text-muted);\n border-color: var(--vectis-color-text-muted);\n color: var(--vectis-color-surface);\n }\n\n .v-radio-input:user-invalid + .v-radio-dot,\n .v-radio-input[aria-invalid='true'] + .v-radio-dot {\n border-color: var(--vectis-color-danger);\n }\n\n .v-radio-input:disabled + .v-radio-dot {\n background: var(--vectis-color-surface-muted);\n border-color: var(--vectis-color-border);\n color: var(--vectis-color-text-subtle);\n }\n\n @media (forced-colors: active) {\n /* Windows forced colors erase every author colour: a `background` becomes `Canvas` and a\n `border-color` becomes `CanvasText`, so a selected radio loses its inner disc outright, that disc being\n a `background` on a `background` where a checkbox has a `stroke` that survives. The system\n Highlight pair is what says \"selected\" here, as it does on a pressed VToggleItem, a\n selected VChip and the current VPagination page.\n\n The class is repeated to (0,8,0) so the row's own hover rules, which reach (0,7,0),\n cannot repaint it: `forced-color-adjust: none` takes the forcing off this element, and\n a hover left winning would then paint its REAL grey over the system colour. */\n .v-radio-input.v-radio-input.v-radio-input.v-radio-input.v-radio-input:checked:not(:disabled)\n + .v-radio-dot {\n forced-color-adjust: none;\n background: Highlight;\n border-color: Highlight;\n color: HighlightText;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-radio-dot,\n .v-radio-dot::before {\n transition: none;\n }\n }\n}\n</style>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"VRadio.js","names":[],"sources":["../../../src/components/VRadio/VRadio.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Retain the native radio for keyboard selection and forms. Its hint stays outside the label so\n * it does not become part of the accessible name.\n */\n\nimport { ref } from 'vue'\n\nimport { useFieldIds } from '../../composables/useFieldIds'\nimport { useRootAttrs } from '../../composables/useRootAttrs'\nimport type { ItemValue } from '../../types'\n\n/** Which side of the dot the label sits on. */\nexport type RadioLabelPosition = 'start' | 'end'\n\ninterface RadioProps {\n /**\n * What choosing this button means. The group's v-model holds the value of the\n * selected button, so this is what it becomes when this one is picked.\n */\n value: ItemValue\n /** The text beside the dot, which names it. The default slot replaces it. */\n label?: string\n /**\n * A line of help under the label. It is tied to the radio button for assistive\n * technology, so it is read out after the label rather than as part of it.\n */\n hint?: string\n /** Which side of the dot the label sits on. */\n labelPosition?: RadioLabelPosition\n /**\n * Pushes the label and the dot to opposite ends of the line, the row taking the\n * full width available.\n */\n spread?: boolean\n /**\n * Marks the field as invalid, which colours the dot and tells assistive technology\n * so. It is for a rule the browser cannot check by itself.\n */\n invalid?: boolean\n /** Makes this choice unusable, greyed out through the colour tokens. */\n disabled?: boolean\n /** Shows the selection without allowing it to be changed. */\n readonly?: boolean\n}\n\nconst props = withDefaults(defineProps<RadioProps>(), {\n label: undefined,\n hint: undefined,\n labelPosition: 'end',\n spread: false,\n invalid: false,\n disabled: false,\n readonly: false,\n})\n\n// @a11y\n// The browser's job, but it only groups inputs that share a `name`; so redirecting the\n// attributes is what makes the arrow keys work at all. The root being a layout box, `name` left\n// on it would reach nothing.\ndefineOptions({ inheritAttrs: false })\nconst { attrs, rootClass, rootStyle, forwardedAttrs } = useRootAttrs()\nconst { hintId, describedBy } = useFieldIds(attrs, () => !!props.hint)\n\n/**\n * The value selected in the group, shared by every radio carrying the same `name`. It is\n * empty until one is chosen, and a radio is selected when it matches its own `value`.\n */\nconst model = defineModel<ItemValue>({ default: '' })\n\ndefineSlots<{\n /** The label, when it needs more than the `label` prop's text. It is clickable. */\n default?(): unknown\n}>()\n\nconst inputEl = ref<HTMLInputElement | null>(null)\n\n// @core\n// The native `readonly` attribute does nothing on a radio button. Cancelling the click is what\n// refuses the selection: the browser puts the group's previous selection back and fires no\n// `change`.\nfunction refuseWhenReadonly(event: MouseEvent) {\n if (props.readonly) event.preventDefault()\n}\n\n// The root is a wrapper, so a template ref on the component reaches the layout box and not\n// the control: these two are the way to the real radio button.\ndefineExpose({\n /** Moves the focus to the real radio button. */\n focus: (options?: FocusOptions) => inputEl.value?.focus(options),\n /** The real `<input type=\"radio\">`, for what `focus` does not cover. */\n el: inputEl,\n})\n</script>\n\n<template>\n <span\n class=\"v-radio v-choice\"\n :class=\"rootClass\"\n :style=\"rootStyle\"\n :data-label-position=\"labelPosition\"\n :data-spread=\"spread ? '' : undefined\"\n :data-readonly=\"readonly ? '' : undefined\"\n >\n <label class=\"v-choice-row\">\n <input\n ref=\"inputEl\"\n v-model=\"model\"\n type=\"radio\"\n class=\"v-radio-input v-hidden-input\"\n :aria-invalid=\"invalid || undefined\"\n v-bind=\"forwardedAttrs\"\n :value=\"value\"\n :disabled=\"disabled\"\n :aria-describedby=\"describedBy\"\n @click=\"refuseWhenReadonly\"\n />\n <span class=\"v-radio-dot\" aria-hidden=\"true\" />\n <span v-if=\"$slots.default || label\" class=\"v-radio-label v-choice-label\">\n <slot>{{ label }}</slot>\n </span>\n </label>\n <span v-if=\"hint\" :id=\"hintId\" class=\"v-radio-hint v-choice-hint\">{{ hint }}</span>\n </span>\n</template>\n\n<style>\n@layer vectis.components {\n /* The dot works exactly like VCheckbox's box, the accent filling it once the input is\n checked, with the small inner disc drawn as a pseudo-element in currentcolor so it\n follows whatever colour the state gives the ring's content. */\n .v-radio-dot {\n display: inline-grid;\n place-items: center;\n width: var(--vectis-control-size-check);\n height: var(--vectis-control-size-check);\n background: transparent;\n border: var(--vectis-control-border-width) solid var(--vectis-color-border-strong);\n border-radius: var(--vectis-radius-pill);\n color: var(--vectis-color-text-on-accent);\n transition:\n background-color var(--vectis-duration-fast) var(--vectis-ease-default),\n border-color var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n\n .v-radio-dot::before {\n content: '';\n width: var(--vectis-control-size-check-dot);\n height: var(--vectis-control-size-check-dot);\n border-radius: var(--vectis-radius-pill);\n background: currentcolor;\n opacity: 0;\n transition: opacity var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n\n .v-radio-input:checked + .v-radio-dot::before {\n opacity: 1;\n }\n\n /*\n * The states below weigh (0,3,0), bar the read-only base at (0,2,0), so their ORDER\n * arbitrates them: checked, read-only, invalid, then disabled last. The two hovers sit at\n * (0,7,0) and therefore beat every one of them on specificity, order or no order; which is\n * why they have to EXCLUDE by hand each state they must not repaint.\n */\n .v-radio:not([data-readonly])\n .v-choice-row:hover\n .v-radio-input:not(:disabled, :checked, :user-invalid, [aria-invalid='true'])\n + .v-radio-dot {\n border-color: color-mix(\n in oklab,\n var(--vectis-color-border-strong),\n var(--vectis-color-text) 15%\n );\n }\n\n .v-radio-input:checked + .v-radio-dot {\n background: var(--vectis-color-accent);\n border-color: var(--vectis-color-accent);\n }\n\n .v-radio:not([data-readonly])\n .v-choice-row:hover\n .v-radio-input:not(:disabled, :user-invalid, [aria-invalid='true']):checked\n + .v-radio-dot {\n background: var(--vectis-color-accent-hover);\n border-color: var(--vectis-color-accent-hover);\n }\n\n /*\n * The inner disc takes the surface colour, which contrasts with that fill in both themes,\n * where white would vanish against the light grey of the dark theme. `:where()` keeps both\n * rules at the weight of the states they sit between.\n */\n :where(.v-radio[data-readonly]) .v-radio-input + .v-radio-dot {\n background: var(--vectis-color-surface-sunken);\n border-color: var(--vectis-color-border);\n }\n\n :where(.v-radio[data-readonly]) .v-radio-input:checked + .v-radio-dot {\n background: var(--vectis-color-text-muted);\n border-color: var(--vectis-color-text-muted);\n color: var(--vectis-color-surface);\n }\n\n .v-radio-input:user-invalid + .v-radio-dot,\n .v-radio-input[aria-invalid='true'] + .v-radio-dot {\n border-color: var(--vectis-color-danger);\n }\n\n .v-radio-input:disabled + .v-radio-dot {\n background: var(--vectis-color-surface-muted);\n border-color: var(--vectis-color-border);\n color: var(--vectis-color-text-subtle);\n }\n\n @media (forced-colors: active) {\n /*\n * The class is repeated to (0,8,0) so the row's own hover rules, which reach (0,7,0),\n * cannot repaint it: `forced-color-adjust: none` takes the forcing off this element, and a\n * hover left winning would then paint its real grey over the system colour.\n */\n .v-radio-input.v-radio-input.v-radio-input.v-radio-input.v-radio-input:checked:not(:disabled)\n + .v-radio-dot {\n forced-color-adjust: none;\n background: Highlight;\n border-color: Highlight;\n color: HighlightText;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-radio-dot,\n .v-radio-dot::before {\n transition: none;\n }\n }\n}\n</style>\n"],"mappings":""}
|