vectis-ui 0.13.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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.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/VAlert/VAlert.js.map +1 -1
- package/dist/components/VAlert/VAlert.vue_vue_type_script_setup_true_lang.js.map +1 -1
- 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.js.map +1 -1
- package/dist/components/VAvatar/VAvatarGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VAvatar/context.js.map +1 -1
- package/dist/components/VBadge/VBadge.js.map +1 -1
- package/dist/components/VBadge/VBadge.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/VBadge/VBadge.vue_vue_type_script_setup_true_lang.js.map +1 -1
- 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.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.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.js.map +1 -1
- 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.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 +5 -17
- package/dist/components/VCalendar/VCalendarMonth.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCalendar/VCalendarTimeGrid.js.map +1 -1
- package/dist/components/VCalendar/VCalendarTimeGrid.vue_vue_type_script_setup_true_lang.js +19 -31
- 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.js.map +1 -1
- package/dist/components/VCalendar/edgeStep.js +1 -5
- package/dist/components/VCalendar/edgeStep.js.map +1 -1
- package/dist/components/VCalendar/gesture.js +4 -12
- package/dist/components/VCalendar/gesture.js.map +1 -1
- package/dist/components/VCalendar/keyboard.js.map +1 -1
- package/dist/components/VCalendar/layout.js +8 -12
- package/dist/components/VCalendar/layout.js.map +1 -1
- package/dist/components/VCalendar/timeGrid.js +5 -5
- package/dist/components/VCalendar/timeGrid.js.map +1 -1
- package/dist/components/VCard/VCard.js.map +1 -1
- package/dist/components/VCard/VCard.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCarousel/VCarousel.js.map +1 -1
- package/dist/components/VCarousel/VCarousel.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCarousel/VCarouselItem.js.map +1 -1
- package/dist/components/VCarousel/VCarouselItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCarousel/context.js.map +1 -1
- package/dist/components/VCheckbox/VCheckMark.js.map +1 -1
- package/dist/components/VCheckbox/VCheckMark.vue_vue_type_script_setup_true_lang.js.map +1 -1
- 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.js.map +1 -1
- package/dist/components/VChip/VChip.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VColorInput/VColorInput.js.map +1 -1
- package/dist/components/VColorInput/VColorInput.vue_vue_type_script_setup_true_lang.js +62 -62
- package/dist/components/VColorInput/VColorInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VColorPicker/VColorPicker.css +1 -1
- package/dist/components/VColorPicker/VColorPicker.js.map +1 -1
- package/dist/components/VColorPicker/VColorPicker.vue_vue_type_script_setup_true_lang.js +1 -5
- package/dist/components/VColorPicker/VColorPicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VColorPicker/color.js.map +1 -1
- package/dist/components/VCombobox/VCombobox.js.map +1 -1
- package/dist/components/VCombobox/VCombobox.vue_vue_type_script_setup_true_lang.js +114 -122
- package/dist/components/VCombobox/VCombobox.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCommandPalette/VCommandPalette.css +1 -1
- package/dist/components/VCommandPalette/VCommandPalette.js.map +1 -1
- package/dist/components/VCommandPalette/VCommandPalette.vue_vue_type_script_setup_true_lang.js +0 -1
- package/dist/components/VCommandPalette/VCommandPalette.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCommandPalette/VCommandPaletteItem.js.map +1 -1
- package/dist/components/VCommandPalette/VCommandPaletteItem.vue_vue_type_script_setup_true_lang.js +1 -5
- package/dist/components/VCommandPalette/VCommandPaletteItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VContextMenu/VContextMenu.js.map +1 -1
- package/dist/components/VContextMenu/VContextMenu.vue_vue_type_script_setup_true_lang.js +3 -5
- package/dist/components/VContextMenu/VContextMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VDataTable/VDataTable.js.map +1 -1
- package/dist/components/VDataTable/VDataTable.vue_vue_type_script_setup_true_lang.js +7 -10
- package/dist/components/VDataTable/VDataTable.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VDateInput/VDateInput.js.map +1 -1
- package/dist/components/VDateInput/VDateInput.vue_vue_type_script_setup_true_lang.js +35 -35
- package/dist/components/VDateInput/VDateInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VDateInput/mask.js.map +1 -1
- package/dist/components/VDatePicker/VDatePicker.js.map +1 -1
- package/dist/components/VDatePicker/VDatePicker.vue_vue_type_script_setup_true_lang.js +2 -1
- package/dist/components/VDatePicker/VDatePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VDatePicker/keyboard.js.map +1 -1
- package/dist/components/VDatePicker/names.js.map +1 -1
- package/dist/components/VDialog/VDialog.js.map +1 -1
- package/dist/components/VDialog/VDialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
- 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/VDrawer/VDrawer.js.map +1 -1
- package/dist/components/VDrawer/VDrawer.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VEmptyState/VEmptyState.js.map +1 -1
- package/dist/components/VEmptyState/VEmptyState.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VField/VField.js.map +1 -1
- package/dist/components/VField/VField.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VField/VFieldAnnouncer.js.map +1 -1
- package/dist/components/VField/VFieldAnnouncer.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VField/VFieldMessage.js.map +1 -1
- package/dist/components/VField/VFieldMessage.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VFieldset/VFieldset.js.map +1 -1
- package/dist/components/VFieldset/VFieldset.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VFileInput/VFileInput.js.map +1 -1
- package/dist/components/VFileInput/VFileInput.vue_vue_type_script_setup_true_lang.js +85 -85
- package/dist/components/VFileInput/VFileInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VFileInput/truncate.js.map +1 -1
- package/dist/components/VFilePicker/VFilePicker.js.map +1 -1
- package/dist/components/VFilePicker/VFilePicker.vue_vue_type_script_setup_true_lang.js +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.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.js +1 -1
- package/dist/components/VHotkeys/platform.js.map +1 -1
- package/dist/components/VHoverCard/VHoverCard.js.map +1 -1
- package/dist/components/VHoverCard/VHoverCard.vue_vue_type_script_setup_true_lang.js +2 -12
- package/dist/components/VHoverCard/VHoverCard.vue_vue_type_script_setup_true_lang.js.map +1 -1
- 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.js.map +1 -1
- package/dist/components/VIcon/icons/add.js.map +1 -1
- package/dist/components/VIcon/icons/arrow_downward.js.map +1 -1
- package/dist/components/VIcon/icons/arrow_downward_alt.js.map +1 -1
- package/dist/components/VIcon/icons/arrow_drop_down.js.map +1 -1
- package/dist/components/VIcon/icons/arrow_drop_up.js.map +1 -1
- package/dist/components/VIcon/icons/arrow_left_alt.js.map +1 -1
- package/dist/components/VIcon/icons/arrow_right_alt.js.map +1 -1
- package/dist/components/VIcon/icons/arrow_upward.js.map +1 -1
- package/dist/components/VIcon/icons/arrow_upward_alt.js.map +1 -1
- package/dist/components/VIcon/icons/attach_file.js.map +1 -1
- package/dist/components/VIcon/icons/audio_file.js.map +1 -1
- package/dist/components/VIcon/icons/calendar_today.js.map +1 -1
- package/dist/components/VIcon/icons/check.js.map +1 -1
- package/dist/components/VIcon/icons/check_circle.js.map +1 -1
- package/dist/components/VIcon/icons/chevron_left.js.map +1 -1
- package/dist/components/VIcon/icons/chevron_right.js.map +1 -1
- package/dist/components/VIcon/icons/close.js.map +1 -1
- package/dist/components/VIcon/icons/cloud_upload.js.map +1 -1
- package/dist/components/VIcon/icons/code.js.map +1 -1
- package/dist/components/VIcon/icons/colorize.js.map +1 -1
- package/dist/components/VIcon/icons/description.js.map +1 -1
- package/dist/components/VIcon/icons/error.js.map +1 -1
- package/dist/components/VIcon/icons/expand_less.js.map +1 -1
- package/dist/components/VIcon/icons/expand_more.js.map +1 -1
- package/dist/components/VIcon/icons/first_page.js.map +1 -1
- package/dist/components/VIcon/icons/folder_zip.js.map +1 -1
- package/dist/components/VIcon/icons/image.js.map +1 -1
- package/dist/components/VIcon/icons/inbox.js.map +1 -1
- package/dist/components/VIcon/icons/index.js.map +1 -1
- package/dist/components/VIcon/icons/info.js.map +1 -1
- package/dist/components/VIcon/icons/last_page.js.map +1 -1
- package/dist/components/VIcon/icons/more_horiz.js.map +1 -1
- package/dist/components/VIcon/icons/names.js.map +1 -1
- package/dist/components/VIcon/icons/notifications.js.map +1 -1
- package/dist/components/VIcon/icons/open_in_new.js.map +1 -1
- package/dist/components/VIcon/icons/picture_as_pdf.js.map +1 -1
- package/dist/components/VIcon/icons/priority_high.js.map +1 -1
- package/dist/components/VIcon/icons/remove.js.map +1 -1
- package/dist/components/VIcon/icons/schedule.js.map +1 -1
- package/dist/components/VIcon/icons/search.js.map +1 -1
- package/dist/components/VIcon/icons/search_off.js.map +1 -1
- package/dist/components/VIcon/icons/star.js.map +1 -1
- package/dist/components/VIcon/icons/swap_vert.js.map +1 -1
- package/dist/components/VIcon/icons/table_chart.js.map +1 -1
- package/dist/components/VIcon/icons/video_file.js.map +1 -1
- package/dist/components/VIcon/icons/viewBox.js.map +1 -1
- package/dist/components/VIcon/icons/warning.js.map +1 -1
- package/dist/components/VIcon/resolver.js.map +1 -1
- 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.js.map +1 -1
- package/dist/components/VInput/VInput.vue_vue_type_script_setup_true_lang.js +20 -20
- 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.map +1 -1
- package/dist/components/VInput/context.js.map +1 -1
- package/dist/components/VInputOTP/VInputOTP.js.map +1 -1
- package/dist/components/VInputOTP/VInputOTP.vue_vue_type_script_setup_true_lang.js +2 -8
- package/dist/components/VInputOTP/VInputOTP.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VLink/VLink.js.map +1 -1
- package/dist/components/VLink/VLink.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VListbox/VListboxChevron.js.map +1 -1
- package/dist/components/VListbox/VListboxChevron.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VListbox/VListboxGroup.js.map +1 -1
- package/dist/components/VListbox/VListboxGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VListbox/VListboxOption.js.map +1 -1
- package/dist/components/VListbox/VListboxOption.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VListbox/VListboxPanel.js.map +1 -1
- package/dist/components/VListbox/VListboxPanel.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VListbox/VListboxSeparator.js.map +1 -1
- package/dist/components/VListbox/VListboxSeparator.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VListbox/VListboxValues.js.map +1 -1
- package/dist/components/VListbox/VListboxValues.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.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.js.map +1 -1
- package/dist/components/VMenu/VMenuItem.vue_vue_type_script_setup_true_lang.js +6 -12
- package/dist/components/VMenu/VMenuItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VMenu/VMenuPanel.js.map +1 -1
- package/dist/components/VMenu/VMenuPanel.vue_vue_type_script_setup_true_lang.js +9 -10
- 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.js.map +1 -1
- package/dist/components/VMeter/VMeter.js.map +1 -1
- package/dist/components/VMeter/VMeter.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VNumberInput/VNumberInput.js.map +1 -1
- package/dist/components/VNumberInput/VNumberInput.vue_vue_type_script_setup_true_lang.js +86 -85
- package/dist/components/VNumberInput/VNumberInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VNumberInput/number.d.ts +2 -2
- package/dist/components/VNumberInput/number.js +1 -1
- package/dist/components/VNumberInput/number.js.map +1 -1
- package/dist/components/VPagination/VPagination.js.map +1 -1
- package/dist/components/VPagination/VPagination.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/VPagination/VPagination.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VPopover/VPopover.js.map +1 -1
- package/dist/components/VPopover/VPopover.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VProgressCircular/VProgressCircular.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.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.js.map +1 -1
- package/dist/components/VRadio/VRadio.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VRating/VRating.js.map +1 -1
- package/dist/components/VRating/VRating.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VResizable/VResizable.js.map +1 -1
- package/dist/components/VResizable/VResizable.vue_vue_type_script_setup_true_lang.js +8 -6
- package/dist/components/VResizable/VResizable.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VResizable/VResizablePanel.js.map +1 -1
- package/dist/components/VResizable/VResizablePanel.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VResizable/context.js.map +1 -1
- package/dist/components/VResizable/layout.js.map +1 -1
- package/dist/components/VSelect/VSelect.js.map +1 -1
- package/dist/components/VSelect/VSelect.vue_vue_type_script_setup_true_lang.js +182 -189
- package/dist/components/VSelect/VSelect.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSeparator/VSeparator.js.map +1 -1
- package/dist/components/VSeparator/VSeparator.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSideNavigation/VSideNavigation.js.map +1 -1
- package/dist/components/VSideNavigation/VSideNavigation.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/VSideNavigation/VSideNavigation.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSideNavigation/VSideNavigationGroup.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.js.map +1 -1
- package/dist/components/VSideNavigation/VSideNavigationItem.vue_vue_type_script_setup_true_lang.js +1 -5
- 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.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.js.map +1 -1
- package/dist/components/VSlider/VSlider.vue_vue_type_script_setup_true_lang.js +22 -22
- 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.js.map +1 -1
- package/dist/components/VSpinner/VSpinner.js.map +1 -1
- package/dist/components/VSpinner/VSpinner.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSplitButton/VSplitButton.js.map +1 -1
- package/dist/components/VSplitButton/VSplitButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VStepper/VStepper.js.map +1 -1
- package/dist/components/VStepper/VStepper.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.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.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.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.js.map +1 -1
- package/dist/components/VTimeInput/VTimeInput.vue_vue_type_script_setup_true_lang.js +45 -45
- package/dist/components/VTimeInput/VTimeInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTimeInput/search.js.map +1 -1
- package/dist/components/VTimePicker/VTimePicker.js.map +1 -1
- package/dist/components/VTimePicker/VTimePicker.vue_vue_type_script_setup_true_lang.js +10 -10
- package/dist/components/VTimePicker/VTimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTimePicker/limits.js.map +1 -1
- package/dist/components/VTimeline/VTimeline.js.map +1 -1
- package/dist/components/VTimeline/VTimeline.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTimeline/VTimelineItem.js.map +1 -1
- package/dist/components/VTimeline/VTimelineItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTimeline/context.js.map +1 -1
- package/dist/components/VTimeline/datetime.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 +1 -1
- package/dist/components/VToast/VToaster.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VToast/state.js.map +1 -1
- package/dist/components/VToggle/VToggle.js.map +1 -1
- package/dist/components/VToggle/VToggle.vue_vue_type_script_setup_true_lang.js +2 -8
- package/dist/components/VToggle/VToggle.vue_vue_type_script_setup_true_lang.js.map +1 -1
- 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.js.map +1 -1
- package/dist/components/VTooltip/VTooltip.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTreeView/VTreeView.js.map +1 -1
- package/dist/components/VTreeView/VTreeView.vue_vue_type_script_setup_true_lang.js +127 -135
- package/dist/components/VTreeView/VTreeView.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTypography/VTypography.js.map +1 -1
- package/dist/components/VTypography/VTypography.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VVirtualList/VVirtualList.js.map +1 -1
- package/dist/components/VVirtualList/VVirtualList.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/composables/useAriaLabel.js.map +1 -1
- package/dist/composables/useChoice.js.map +1 -1
- package/dist/composables/useClearable.js.map +1 -1
- package/dist/composables/useControlShape.js.map +1 -1
- package/dist/composables/useDebouncedSearch.js.map +1 -1
- package/dist/composables/useDetailsOpen.js.map +1 -1
- package/dist/composables/useEscapeDismiss.js.map +1 -1
- package/dist/composables/useFieldIds.js.map +1 -1
- package/dist/composables/useFieldPanel.js +3 -7
- package/dist/composables/useFieldPanel.js.map +1 -1
- package/dist/composables/useFileDrop.js.map +1 -1
- package/dist/composables/useFileField.js +2 -2
- package/dist/composables/useFileField.js.map +1 -1
- package/dist/composables/useFocusoutDismiss.js.map +1 -1
- package/dist/composables/useHotkeyListener.js +5 -2
- package/dist/composables/useHotkeyListener.js.map +1 -1
- package/dist/composables/useIconClickHandlers.js.map +1 -1
- package/dist/composables/useInertLink.js.map +1 -1
- package/dist/composables/useInfiniteScroll.js +4 -4
- package/dist/composables/useInfiniteScroll.js.map +1 -1
- package/dist/composables/useListbox.js +3 -9
- package/dist/composables/useListbox.js.map +1 -1
- package/dist/composables/useLiveAnnouncer.js.map +1 -1
- package/dist/composables/useMaskedField.js +28 -48
- package/dist/composables/useMaskedField.js.map +1 -1
- package/dist/composables/useModalDialog.js +1 -1
- package/dist/composables/useModalDialog.js.map +1 -1
- package/dist/composables/usePopover.js +1 -1
- package/dist/composables/usePopover.js.map +1 -1
- package/dist/composables/useProgressValue.js.map +1 -1
- package/dist/composables/useRootAttrs.js.map +1 -1
- package/dist/composables/useSlotNodes.js.map +1 -1
- package/dist/composables/useTextLimit.js.map +1 -1
- package/dist/composables/useTimer.js.map +1 -1
- package/dist/composables/useTypeahead.d.ts +13 -0
- package/dist/composables/useTypeahead.js +23 -0
- package/dist/composables/useTypeahead.js.map +1 -0
- package/dist/composables/useVirtualList.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 +1 -1
- package/dist/i18n/state.js +17 -6
- package/dist/i18n/state.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/tokens/css.js.map +1 -1
- package/dist/tokens/index.js.map +1 -1
- package/dist/tokens/primitives.js.map +1 -1
- package/dist/tokens/semantic.js.map +1 -1
- package/dist/tokens/themes/dark.js.map +1 -1
- package/dist/tokens/types.js.map +1 -1
- package/dist/utils/array.js.map +1 -1
- package/dist/utils/arrowNav.js.map +1 -1
- package/dist/utils/attrs.js.map +1 -1
- package/dist/utils/chip.js.map +1 -1
- package/dist/utils/clock.js +3 -1
- package/dist/utils/clock.js.map +1 -1
- package/dist/utils/css.js +1 -1
- package/dist/utils/css.js.map +1 -1
- package/dist/utils/date.js +4 -3
- package/dist/utils/date.js.map +1 -1
- package/dist/utils/direction.js.map +1 -1
- package/dist/utils/env.js.map +1 -1
- package/dist/utils/file.js +13 -31
- package/dist/utils/file.js.map +1 -1
- package/dist/utils/focus.js.map +1 -1
- package/dist/utils/hostWarns.js.map +1 -1
- package/dist/utils/ids.js.map +1 -1
- package/dist/utils/matcher.js.map +1 -1
- package/dist/utils/memo.js.map +1 -1
- package/dist/utils/number.js.map +1 -1
- package/dist/utils/text.js.map +1 -1
- package/dist/utils/time.js.map +1 -1
- package/dist/utils/vnode.js.map +1 -1
- package/package.json +19 -19
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VAccordion.js","names":[],"sources":["../../../src/components/VAccordion/VAccordion.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Native details elements own disclosure and exclusive groups; multiple removes the shared\n * group name.\n */\n\nimport { provide, useId } from 'vue'\n\nimport { expand_more as expandMoreIcon } from '../VIcon/icons/expand_more'\nimport type { IconSource } from '../VIcon/types'\n\nimport { accordionKey } from './context'\n\n/** How the group is set off from the page: nothing, a border, a shadow, or a muted fill. */\nexport type AccordionVariant = 'flat' | 'outline' | 'elevated' | 'filled'\n\ninterface AccordionProps {\n /**\n * Lets the reader keep several sections open at once. Left out, only one may stay\n * open and opening one closes the previous one, which the browser does on its own\n * once every item shares the same `<details>` name.\n */\n multiple?: boolean\n /**\n * How the group is set off from the page. `flat`, the default, draws nothing and lets\n * the accordion sit directly on the surface behind it. The other three frame it with\n * rounded corners, like a card: a border on the page surface (`outline`), a shadow over\n * a raised surface (`elevated`), or a muted fill with no border (`filled`).\n */\n variant?: AccordionVariant\n /**\n * The icon shown on a closed item: an icon name, or an explicit `{ src }` /\n * `{ component }`. It is a chevron by default, which rotates by 180° when the\n * item opens.\n */\n expandIcon?: IconSource\n /**\n * The icon shown on an open item. Leave it out and the `expandIcon` is simply\n * rotated 180°; provide one and the two icons are swapped instead.\n */\n collapseIcon?: IconSource\n /**\n * Reduced density: every padding loses 4px, while the text and the icons keep\n * their size.\n */\n compact?: boolean\n}\n\nconst props = withDefaults(defineProps<AccordionProps>(), {\n multiple: false,\n variant: 'flat',\n expandIcon: () => expandMoreIcon,\n collapseIcon: undefined,\n compact: false,\n})\n\ndefineSlots<{\n /** The `<VAccordionItem>`s that make up the group. */\n default(): unknown\n}>()\n\nconst groupName = useId()\nprovide(accordionKey, {\n get name() {\n return props.multiple ? undefined : groupName\n },\n get expandIcon() {\n return props.expandIcon\n },\n get collapseIcon() {\n return props.collapseIcon\n },\n})\n</script>\n\n<template>\n <div class=\"v-accordion\" :data-variant=\"variant\" :data-compact=\"compact ? '' : undefined\">\n <slot />\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n .v-accordion {\n --accordion-pad-delta: 0px;\n --accordion-pad-block: calc(var(--vectis-space-4) - var(--accordion-pad-delta));\n --accordion-pad-inline: calc(var(--vectis-space-5) - var(--accordion-pad-delta));\n --accordion-content-pad-start: calc(var(--vectis-space-2) - var(--accordion-pad-delta));\n\n font-family: var(--vectis-text-family);\n }\n\n /* Read by the first and last rows to round their hover. Without a frame there is no clip,\n so the rows carry the whole radius. */\n .v-accordion[data-variant='flat'] {\n --accordion-corner-radius: var(--vectis-radius-surface);\n }\n\n .v-accordion[data-compact] {\n --accordion-pad-delta: var(--vectis-space-1);\n }\n\n .v-accordion:is([data-variant='outline'], [data-variant='elevated'], [data-variant='filled']) {\n --accordion-corner-radius: calc(var(--vectis-radius-surface) - 1px);\n\n /* Transparent rather than absent on `filled`: forced colours paint it. `elevated` has\n none, so that the separators and the hover reach the edge its shadow draws. */\n border: 1px solid transparent;\n border-radius: var(--vectis-radius-surface);\n /* The clip is what keeps the first and last rows' hover inside the rounded corners, so\n it belongs to the variants that HAVE corners. `clip` and not `hidden`: `hidden` makes\n the box a scroll container, which captures every `position: sticky` in the content\n and pins it to the accordion instead of the page. */\n overflow: clip;\n }\n\n .v-accordion[data-variant='outline'] {\n background: var(--vectis-color-surface);\n border-color: var(--vectis-color-border);\n }\n\n .v-accordion[data-variant='elevated'] {\n --accordion-corner-radius: var(--vectis-radius-surface);\n\n border: none;\n background: var(--vectis-color-surface-raised);\n box-shadow: var(--vectis-shadow-sm);\n }\n\n /* The usual hover is the muted surface itself, which would vanish on this fill. */\n .v-accordion[data-variant='filled'] {\n --accordion-hover-bg: color-mix(\n in oklab,\n var(--vectis-color-surface-muted),\n var(--vectis-color-text) 4%\n );\n\n background: var(--vectis-color-surface-muted);\n }\n}\n</style>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"VAccordion.js","names":["_sfc_main","VAccordion_vue_vue_type_script_setup_true_lang_default","VAccordion_default"],"sources":["../../../src/components/VAccordion/VAccordion.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Native details elements own disclosure and exclusive groups; multiple removes the shared\n * group name.\n */\n\nimport { provide, useId } from 'vue'\n\nimport { expand_more as expandMoreIcon } from '../VIcon/icons/expand_more'\nimport type { IconSource } from '../VIcon/types'\n\nimport { accordionKey } from './context'\n\n/** How the group is set off from the page: nothing, a border, a shadow, or a muted fill. */\nexport type AccordionVariant = 'flat' | 'outline' | 'elevated' | 'filled'\n\ninterface AccordionProps {\n /**\n * Lets the reader keep several sections open at once. Left out, only one may stay\n * open and opening one closes the previous one, which the browser does on its own\n * once every item shares the same `<details>` name.\n */\n multiple?: boolean\n /**\n * How the group is set off from the page. `flat`, the default, draws nothing and lets\n * the accordion sit directly on the surface behind it. The other three frame it with\n * rounded corners, like a card: a border on the page surface (`outline`), a shadow over\n * a raised surface (`elevated`), or a muted fill with no border (`filled`).\n */\n variant?: AccordionVariant\n /**\n * The icon shown on a closed item: an icon name, or an explicit `{ src }` /\n * `{ component }`. It is a chevron by default, which rotates by 180° when the\n * item opens.\n */\n expandIcon?: IconSource\n /**\n * The icon shown on an open item. Leave it out and the `expandIcon` is simply\n * rotated 180°; provide one and the two icons are swapped instead.\n */\n collapseIcon?: IconSource\n /**\n * Reduced density: every padding loses 4px, while the text and the icons keep\n * their size.\n */\n compact?: boolean\n}\n\nconst props = withDefaults(defineProps<AccordionProps>(), {\n multiple: false,\n variant: 'flat',\n expandIcon: () => expandMoreIcon,\n collapseIcon: undefined,\n compact: false,\n})\n\ndefineSlots<{\n /** The `<VAccordionItem>`s that make up the group. */\n default(): unknown\n}>()\n\nconst groupName = useId()\nprovide(accordionKey, {\n get name() {\n return props.multiple ? undefined : groupName\n },\n get expandIcon() {\n return props.expandIcon\n },\n get collapseIcon() {\n return props.collapseIcon\n },\n})\n</script>\n\n<template>\n <div class=\"v-accordion\" :data-variant=\"variant\" :data-compact=\"compact ? '' : undefined\">\n <slot />\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n .v-accordion {\n --accordion-pad-delta: 0px;\n --accordion-pad-block: calc(var(--vectis-space-4) - var(--accordion-pad-delta));\n --accordion-pad-inline: calc(var(--vectis-space-5) - var(--accordion-pad-delta));\n --accordion-content-pad-start: calc(var(--vectis-space-2) - var(--accordion-pad-delta));\n\n font-family: var(--vectis-text-family);\n }\n\n /* Read by the first and last rows to round their hover. Without a frame there is no clip,\n so the rows carry the whole radius. */\n .v-accordion[data-variant='flat'] {\n --accordion-corner-radius: var(--vectis-radius-surface);\n }\n\n .v-accordion[data-compact] {\n --accordion-pad-delta: var(--vectis-space-1);\n }\n\n .v-accordion:is([data-variant='outline'], [data-variant='elevated'], [data-variant='filled']) {\n --accordion-corner-radius: calc(var(--vectis-radius-surface) - 1px);\n\n /* Transparent rather than absent on `filled`: forced colours paint it. `elevated` has\n none, so that the separators and the hover reach the edge its shadow draws. */\n border: 1px solid transparent;\n border-radius: var(--vectis-radius-surface);\n /* The clip is what keeps the first and last rows' hover inside the rounded corners, so\n it belongs to the variants that HAVE corners. `clip` and not `hidden`: `hidden` makes\n the box a scroll container, which captures every `position: sticky` in the content\n and pins it to the accordion instead of the page. */\n overflow: clip;\n }\n\n .v-accordion[data-variant='outline'] {\n background: var(--vectis-color-surface);\n border-color: var(--vectis-color-border);\n }\n\n .v-accordion[data-variant='elevated'] {\n --accordion-corner-radius: var(--vectis-radius-surface);\n\n border: none;\n background: var(--vectis-color-surface-raised);\n box-shadow: var(--vectis-shadow-sm);\n }\n\n /* The usual hover is the muted surface itself, which would vanish on this fill. */\n .v-accordion[data-variant='filled'] {\n --accordion-hover-bg: color-mix(\n in oklab,\n var(--vectis-color-surface-muted),\n var(--vectis-color-text) 4%\n );\n\n background: var(--vectis-color-surface-muted);\n }\n}\n</style>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VAccordion.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/VAccordion/VAccordion.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Native details elements own disclosure and exclusive groups; multiple removes the shared\n * group name.\n */\n\nimport { provide, useId } from 'vue'\n\nimport { expand_more as expandMoreIcon } from '../VIcon/icons/expand_more'\nimport type { IconSource } from '../VIcon/types'\n\nimport { accordionKey } from './context'\n\n/** How the group is set off from the page: nothing, a border, a shadow, or a muted fill. */\nexport type AccordionVariant = 'flat' | 'outline' | 'elevated' | 'filled'\n\ninterface AccordionProps {\n /**\n * Lets the reader keep several sections open at once. Left out, only one may stay\n * open and opening one closes the previous one, which the browser does on its own\n * once every item shares the same `<details>` name.\n */\n multiple?: boolean\n /**\n * How the group is set off from the page. `flat`, the default, draws nothing and lets\n * the accordion sit directly on the surface behind it. The other three frame it with\n * rounded corners, like a card: a border on the page surface (`outline`), a shadow over\n * a raised surface (`elevated`), or a muted fill with no border (`filled`).\n */\n variant?: AccordionVariant\n /**\n * The icon shown on a closed item: an icon name, or an explicit `{ src }` /\n * `{ component }`. It is a chevron by default, which rotates by 180° when the\n * item opens.\n */\n expandIcon?: IconSource\n /**\n * The icon shown on an open item. Leave it out and the `expandIcon` is simply\n * rotated 180°; provide one and the two icons are swapped instead.\n */\n collapseIcon?: IconSource\n /**\n * Reduced density: every padding loses 4px, while the text and the icons keep\n * their size.\n */\n compact?: boolean\n}\n\nconst props = withDefaults(defineProps<AccordionProps>(), {\n multiple: false,\n variant: 'flat',\n expandIcon: () => expandMoreIcon,\n collapseIcon: undefined,\n compact: false,\n})\n\ndefineSlots<{\n /** The `<VAccordionItem>`s that make up the group. */\n default(): unknown\n}>()\n\nconst groupName = useId()\nprovide(accordionKey, {\n get name() {\n return props.multiple ? undefined : groupName\n },\n get expandIcon() {\n return props.expandIcon\n },\n get collapseIcon() {\n return props.collapseIcon\n },\n})\n</script>\n\n<template>\n <div class=\"v-accordion\" :data-variant=\"variant\" :data-compact=\"compact ? '' : undefined\">\n <slot />\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n .v-accordion {\n --accordion-pad-delta: 0px;\n --accordion-pad-block: calc(var(--vectis-space-4) - var(--accordion-pad-delta));\n --accordion-pad-inline: calc(var(--vectis-space-5) - var(--accordion-pad-delta));\n --accordion-content-pad-start: calc(var(--vectis-space-2) - var(--accordion-pad-delta));\n\n font-family: var(--vectis-text-family);\n }\n\n /* Read by the first and last rows to round their hover. Without a frame there is no clip,\n so the rows carry the whole radius. */\n .v-accordion[data-variant='flat'] {\n --accordion-corner-radius: var(--vectis-radius-surface);\n }\n\n .v-accordion[data-compact] {\n --accordion-pad-delta: var(--vectis-space-1);\n }\n\n .v-accordion:is([data-variant='outline'], [data-variant='elevated'], [data-variant='filled']) {\n --accordion-corner-radius: calc(var(--vectis-radius-surface) - 1px);\n\n /* Transparent rather than absent on `filled`: forced colours paint it. `elevated` has\n none, so that the separators and the hover reach the edge its shadow draws. */\n border: 1px solid transparent;\n border-radius: var(--vectis-radius-surface);\n /* The clip is what keeps the first and last rows' hover inside the rounded corners, so\n it belongs to the variants that HAVE corners. `clip` and not `hidden`: `hidden` makes\n the box a scroll container, which captures every `position: sticky` in the content\n and pins it to the accordion instead of the page. */\n overflow: clip;\n }\n\n .v-accordion[data-variant='outline'] {\n background: var(--vectis-color-surface);\n border-color: var(--vectis-color-border);\n }\n\n .v-accordion[data-variant='elevated'] {\n --accordion-corner-radius: var(--vectis-radius-surface);\n\n border: none;\n background: var(--vectis-color-surface-raised);\n box-shadow: var(--vectis-shadow-sm);\n }\n\n /* The usual hover is the muted surface itself, which would vanish on this fill. */\n .v-accordion[data-variant='filled'] {\n --accordion-hover-bg: color-mix(\n in oklab,\n var(--vectis-color-surface-muted),\n var(--vectis-color-text) 4%\n );\n\n background: var(--vectis-color-surface-muted);\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;EAgDA,
|
|
1
|
+
{"version":3,"file":"VAccordion.vue_vue_type_script_setup_true_lang.js","names":["expandMoreIcon","_openBlock","_createElementBlock","_renderSlot","_hoisted_1","VAccordion_vue_vue_type_script_setup_true_lang_default","expand_more","props","__props","groupName","useId","provide","accordionKey","openBlock","createElementBlock","renderSlot","_ctx"],"sources":["../../../src/components/VAccordion/VAccordion.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Native details elements own disclosure and exclusive groups; multiple removes the shared\n * group name.\n */\n\nimport { provide, useId } from 'vue'\n\nimport { expand_more as expandMoreIcon } from '../VIcon/icons/expand_more'\nimport type { IconSource } from '../VIcon/types'\n\nimport { accordionKey } from './context'\n\n/** How the group is set off from the page: nothing, a border, a shadow, or a muted fill. */\nexport type AccordionVariant = 'flat' | 'outline' | 'elevated' | 'filled'\n\ninterface AccordionProps {\n /**\n * Lets the reader keep several sections open at once. Left out, only one may stay\n * open and opening one closes the previous one, which the browser does on its own\n * once every item shares the same `<details>` name.\n */\n multiple?: boolean\n /**\n * How the group is set off from the page. `flat`, the default, draws nothing and lets\n * the accordion sit directly on the surface behind it. The other three frame it with\n * rounded corners, like a card: a border on the page surface (`outline`), a shadow over\n * a raised surface (`elevated`), or a muted fill with no border (`filled`).\n */\n variant?: AccordionVariant\n /**\n * The icon shown on a closed item: an icon name, or an explicit `{ src }` /\n * `{ component }`. It is a chevron by default, which rotates by 180° when the\n * item opens.\n */\n expandIcon?: IconSource\n /**\n * The icon shown on an open item. Leave it out and the `expandIcon` is simply\n * rotated 180°; provide one and the two icons are swapped instead.\n */\n collapseIcon?: IconSource\n /**\n * Reduced density: every padding loses 4px, while the text and the icons keep\n * their size.\n */\n compact?: boolean\n}\n\nconst props = withDefaults(defineProps<AccordionProps>(), {\n multiple: false,\n variant: 'flat',\n expandIcon: () => expandMoreIcon,\n collapseIcon: undefined,\n compact: false,\n})\n\ndefineSlots<{\n /** The `<VAccordionItem>`s that make up the group. */\n default(): unknown\n}>()\n\nconst groupName = useId()\nprovide(accordionKey, {\n get name() {\n return props.multiple ? undefined : groupName\n },\n get expandIcon() {\n return props.expandIcon\n },\n get collapseIcon() {\n return props.collapseIcon\n },\n})\n</script>\n\n<template>\n <div class=\"v-accordion\" :data-variant=\"variant\" :data-compact=\"compact ? '' : undefined\">\n <slot />\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n .v-accordion {\n --accordion-pad-delta: 0px;\n --accordion-pad-block: calc(var(--vectis-space-4) - var(--accordion-pad-delta));\n --accordion-pad-inline: calc(var(--vectis-space-5) - var(--accordion-pad-delta));\n --accordion-content-pad-start: calc(var(--vectis-space-2) - var(--accordion-pad-delta));\n\n font-family: var(--vectis-text-family);\n }\n\n /* Read by the first and last rows to round their hover. Without a frame there is no clip,\n so the rows carry the whole radius. */\n .v-accordion[data-variant='flat'] {\n --accordion-corner-radius: var(--vectis-radius-surface);\n }\n\n .v-accordion[data-compact] {\n --accordion-pad-delta: var(--vectis-space-1);\n }\n\n .v-accordion:is([data-variant='outline'], [data-variant='elevated'], [data-variant='filled']) {\n --accordion-corner-radius: calc(var(--vectis-radius-surface) - 1px);\n\n /* Transparent rather than absent on `filled`: forced colours paint it. `elevated` has\n none, so that the separators and the hover reach the edge its shadow draws. */\n border: 1px solid transparent;\n border-radius: var(--vectis-radius-surface);\n /* The clip is what keeps the first and last rows' hover inside the rounded corners, so\n it belongs to the variants that HAVE corners. `clip` and not `hidden`: `hidden` makes\n the box a scroll container, which captures every `position: sticky` in the content\n and pins it to the accordion instead of the page. */\n overflow: clip;\n }\n\n .v-accordion[data-variant='outline'] {\n background: var(--vectis-color-surface);\n border-color: var(--vectis-color-border);\n }\n\n .v-accordion[data-variant='elevated'] {\n --accordion-corner-radius: var(--vectis-radius-surface);\n\n border: none;\n background: var(--vectis-color-surface-raised);\n box-shadow: var(--vectis-shadow-sm);\n }\n\n /* The usual hover is the muted surface itself, which would vanish on this fill. */\n .v-accordion[data-variant='filled'] {\n --accordion-hover-bg: color-mix(\n in oklab,\n var(--vectis-color-surface-muted),\n var(--vectis-color-text) 4%\n );\n\n background: var(--vectis-color-surface-muted);\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;EAgDA,IAAMO,IAAQC,GAaRC,IAAYC,EAAM;SACxBC,EAAQC,GAAc;GACpB,IAAI,OAAO;IACT,OAAOL,EAAM,WAAW,KAAA,IAAYE;GACtC;GACA,IAAI,aAAa;IACf,OAAOF,EAAM;GACf;GACA,IAAI,eAAe;IACjB,OAAOA,EAAM;GACf;EACF,CAAC,cAICN,EAAA,GAAAC,EAEM,OAAA;GAFD,OAAM;GAAe,gBAAcM,EAAA;GAAU,gBAAcA,EAAA,UAAO,KAAQ,KAAA;EAC7EL,GAAAA,CAAAA,EAAQa,EAAA,QAAA,SAAA,CAAA,GAAA,GAAAZ,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VAccordionItem.js","names":[],"sources":["../../../src/components/VAccordion/VAccordionItem.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Native details owns disclosure. useDetailsOpen bridges v-model and cancels activation of\n * disabled summaries.\n */\n\nimport { computed, inject, provide } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport { expand_more as expandMoreIcon } from '../VIcon/icons/expand_more'\nimport type { IconSource } from '../VIcon/types'\nimport VTypography from '../VTypography/VTypography.vue'\nimport { accordionKey } from './context'\n\nimport { useDetailsOpen } from '../../composables/useDetailsOpen'\n\ninterface AccordionItemProps {\n /**\n * The heading of the section, the line that stays visible when it is closed. Use the `#title`\n * slot instead when the heading needs markup rather than plain text.\n */\n title?: string\n /**\n * A secondary line under the title, for a short explanation or a status. The\n * `#subtitle` slot replaces it when markup is needed.\n */\n subtitle?: string\n /**\n * An icon placed before the title: an icon name, or an explicit render (`{ src }`,\n * `{ component }`…). The `#icon` slot replaces it.\n */\n icon?: IconSource\n /** Renders the section already open. Bind `v-model:open` to drive it instead. */\n defaultOpen?: boolean\n /** Makes the section inert. */\n disabled?: boolean\n}\n\nconst props = withDefaults(defineProps<AccordionItemProps>(), {\n title: undefined,\n subtitle: undefined,\n icon: undefined,\n defaultOpen: false,\n disabled: false,\n})\n\n// \"not bound\" is written as `null` and not `undefined`. A model typed as a plain boolean is\n// declared as such at runtime, and Vue casts an ABSENT boolean prop to `false`, which would\n// silently overwrite `defaultOpen`.\n/**\n * Whether the section is open, when the consumer wants to drive or observe it. Left\n * unbound, the browser keeps that state to itself, `defaultOpen` giving only the initial\n * value. `null` means unbound.\n */\nconst open = defineModel<boolean | null>('open', { default: null })\n\ndefineSlots<{\n /** The content revealed when the section is open. */\n default(): unknown\n /** A title made of markup, which replaces the `title` prop. */\n title?(): unknown\n /** A subtitle made of markup, which replaces the `subtitle` prop. */\n subtitle?(): unknown\n /** Free content before the title, which takes the place of `icon`. */\n icon?(): unknown\n}>()\n\nconst accordion = inject(accordionKey, null)\n// The group stops here: an item nested in this one's content without a VAccordion of its\n// own would otherwise share this group's name, and the browser closes every other member\n// of a name group when one opens, the section holding it included.\nprovide(accordionKey, null)\n\n/**\n * Both icons are chosen on the enclosing group. The chevron fallback is what keeps\n * an item rendering correctly when it is used outside a VAccordion.\n */\nconst expandIcon = computed(() => accordion?.expandIcon ?? expandMoreIcon)\nconst collapseIcon = computed(() => accordion?.collapseIcon)\n\nconst { openAttr, onToggle, onSummaryClick } = useDetailsOpen(open, {\n defaultOpen: () => props.defaultOpen,\n disabled: () => props.disabled,\n})\n</script>\n\n<template>\n <details\n class=\"v-accordion-item v-disclosure\"\n :name=\"accordion?.name\"\n :open=\"openAttr\"\n :data-swap=\"collapseIcon ? '' : undefined\"\n @toggle=\"onToggle\"\n >\n <summary\n class=\"v-accordion-summary\"\n :data-disabled=\"disabled ? '' : undefined\"\n :aria-disabled=\"disabled || undefined\"\n :tabindex=\"disabled ? -1 : undefined\"\n @click=\"onSummaryClick\"\n >\n <slot name=\"icon\">\n <VIcon v-if=\"icon\" class=\"v-accordion-icon\" v-bind=\"iconProps(icon)\" />\n </slot>\n <span class=\"v-accordion-heading\">\n <span class=\"v-accordion-title\"\n ><slot name=\"title\">{{ title }}</slot></span\n >\n <VTypography\n v-if=\"subtitle !== undefined || $slots.subtitle\"\n as=\"span\"\n variant=\"caption\"\n tone=\"muted\"\n class=\"v-accordion-subtitle\"\n ><slot name=\"subtitle\">{{ subtitle }}</slot></VTypography\n >\n </span>\n <VIcon class=\"v-accordion-chevron v-disclosure-chevron\" v-bind=\"iconProps(expandIcon)\" />\n <VIcon\n v-if=\"collapseIcon\"\n class=\"v-accordion-chevron v-accordion-chevron-open v-disclosure-chevron v-disclosure-chevron-open\"\n v-bind=\"iconProps(collapseIcon)\"\n />\n </summary>\n <div class=\"v-accordion-content\">\n <slot />\n </div>\n </details>\n</template>\n\n<style>\n@layer vectis.components {\n .v-accordion-item + .v-accordion-item {\n border-block-start: 1px solid var(--vectis-color-border);\n }\n\n .v-accordion-summary {\n --vectis-icon-size: var(--vectis-icon-size-md);\n --vectis-icon-opsz: 20;\n\n display: flex;\n align-items: center;\n gap: var(--vectis-space-3);\n padding: var(--accordion-pad-block, var(--vectis-space-4))\n var(--accordion-pad-inline, var(--vectis-space-5));\n cursor: pointer;\n font-size: var(--vectis-text-label-size);\n font-weight: var(--vectis-text-label-weight);\n color: var(--vectis-color-text);\n }\n\n .v-accordion-summary:hover:not([data-disabled]) {\n background: var(--accordion-hover-bg, var(--vectis-color-surface-muted));\n }\n\n .v-accordion-summary:focus-visible {\n outline: var(--vectis-focus-ring-width) solid var(--vectis-focus-ring-color);\n outline-offset: calc(-1 * var(--vectis-focus-ring-width));\n }\n\n .v-accordion-item:first-child > .v-accordion-summary {\n border-start-start-radius: var(--accordion-corner-radius, 0);\n border-start-end-radius: var(--accordion-corner-radius, 0);\n }\n\n .v-accordion-item:last-child:not([open]) > .v-accordion-summary {\n border-end-start-radius: var(--accordion-corner-radius, 0);\n border-end-end-radius: var(--accordion-corner-radius, 0);\n }\n\n .v-accordion-heading {\n flex: 1;\n display: flex;\n flex-direction: column;\n line-height: var(--vectis-text-label-leading);\n }\n\n .v-accordion-icon {\n flex: none;\n color: var(--vectis-color-text-muted);\n }\n\n /* A disabled item greys out through the colour tokens and never through\n `opacity`, the rule every control in the DS follows. */\n .v-accordion-summary[data-disabled] {\n color: var(--vectis-color-text-subtle);\n cursor: not-allowed;\n }\n\n /* The icon and the subtitle default to text-muted, which is DARKER than the\n text-subtle a disabled title takes: left to themselves they would come out\n stronger than the label they belong to, so they inherit it instead. The chevron\n gets the same treatment from `styles/disclosure.css`. */\n .v-accordion-summary[data-disabled] .v-accordion-icon,\n .v-accordion-summary[data-disabled] .v-accordion-subtitle {\n color: inherit;\n }\n\n .v-accordion-content {\n padding: var(--accordion-content-pad-start, var(--vectis-space-2))\n var(--accordion-pad-inline, var(--vectis-space-5))\n var(--accordion-pad-block, var(--vectis-space-4));\n font-size: var(--vectis-text-body-md-size);\n line-height: var(--vectis-text-body-md-leading);\n color: var(--vectis-color-text-muted);\n }\n\n /* The disclosure animation, the chevron's rotation or swap and the WebKit marker come\n from `styles/disclosure.css`, reduced-motion block included. */\n}\n</style>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"VAccordionItem.js","names":["_sfc_main","VAccordionItem_vue_vue_type_script_setup_true_lang_default","VAccordionItem_default"],"sources":["../../../src/components/VAccordion/VAccordionItem.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Native details owns disclosure. useDetailsOpen bridges v-model and cancels activation of\n * disabled summaries.\n */\n\nimport { computed, inject, provide } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport { expand_more as expandMoreIcon } from '../VIcon/icons/expand_more'\nimport type { IconSource } from '../VIcon/types'\nimport VTypography from '../VTypography/VTypography.vue'\nimport { accordionKey } from './context'\n\nimport { useDetailsOpen } from '../../composables/useDetailsOpen'\n\ninterface AccordionItemProps {\n /**\n * The heading of the section, the line that stays visible when it is closed. Use the `#title`\n * slot instead when the heading needs markup rather than plain text.\n */\n title?: string\n /**\n * A secondary line under the title, for a short explanation or a status. The\n * `#subtitle` slot replaces it when markup is needed.\n */\n subtitle?: string\n /**\n * An icon placed before the title: an icon name, or an explicit render (`{ src }`,\n * `{ component }`…). The `#icon` slot replaces it.\n */\n icon?: IconSource\n /** Renders the section already open. Bind `v-model:open` to drive it instead. */\n defaultOpen?: boolean\n /** Makes the section inert. */\n disabled?: boolean\n}\n\nconst props = withDefaults(defineProps<AccordionItemProps>(), {\n title: undefined,\n subtitle: undefined,\n icon: undefined,\n defaultOpen: false,\n disabled: false,\n})\n\n// \"not bound\" is written as `null` and not `undefined`. A model typed as a plain boolean is\n// declared as such at runtime, and Vue casts an ABSENT boolean prop to `false`, which would\n// silently overwrite `defaultOpen`.\n/**\n * Whether the section is open, when the consumer wants to drive or observe it. Left\n * unbound, the browser keeps that state to itself, `defaultOpen` giving only the initial\n * value. `null` means unbound.\n */\nconst open = defineModel<boolean | null>('open', { default: null })\n\ndefineSlots<{\n /** The content revealed when the section is open. */\n default(): unknown\n /** A title made of markup, which replaces the `title` prop. */\n title?(): unknown\n /** A subtitle made of markup, which replaces the `subtitle` prop. */\n subtitle?(): unknown\n /** Free content before the title, which takes the place of `icon`. */\n icon?(): unknown\n}>()\n\nconst accordion = inject(accordionKey, null)\n// The group stops here: an item nested in this one's content without a VAccordion of its\n// own would otherwise share this group's name, and the browser closes every other member\n// of a name group when one opens, the section holding it included.\nprovide(accordionKey, null)\n\n/**\n * Both icons are chosen on the enclosing group. The chevron fallback is what keeps\n * an item rendering correctly when it is used outside a VAccordion.\n */\nconst expandIcon = computed(() => accordion?.expandIcon ?? expandMoreIcon)\nconst collapseIcon = computed(() => accordion?.collapseIcon)\n\nconst { openAttr, onToggle, onSummaryClick } = useDetailsOpen(open, {\n defaultOpen: () => props.defaultOpen,\n disabled: () => props.disabled,\n})\n</script>\n\n<template>\n <details\n class=\"v-accordion-item v-disclosure\"\n :name=\"accordion?.name\"\n :open=\"openAttr\"\n :data-swap=\"collapseIcon ? '' : undefined\"\n @toggle=\"onToggle\"\n >\n <summary\n class=\"v-accordion-summary\"\n :data-disabled=\"disabled ? '' : undefined\"\n :aria-disabled=\"disabled || undefined\"\n :tabindex=\"disabled ? -1 : undefined\"\n @click=\"onSummaryClick\"\n >\n <slot name=\"icon\">\n <VIcon v-if=\"icon\" class=\"v-accordion-icon\" v-bind=\"iconProps(icon)\" />\n </slot>\n <span class=\"v-accordion-heading\">\n <span class=\"v-accordion-title\"\n ><slot name=\"title\">{{ title }}</slot></span\n >\n <VTypography\n v-if=\"subtitle !== undefined || $slots.subtitle\"\n as=\"span\"\n variant=\"caption\"\n tone=\"muted\"\n class=\"v-accordion-subtitle\"\n ><slot name=\"subtitle\">{{ subtitle }}</slot></VTypography\n >\n </span>\n <VIcon class=\"v-accordion-chevron v-disclosure-chevron\" v-bind=\"iconProps(expandIcon)\" />\n <VIcon\n v-if=\"collapseIcon\"\n class=\"v-accordion-chevron v-accordion-chevron-open v-disclosure-chevron v-disclosure-chevron-open\"\n v-bind=\"iconProps(collapseIcon)\"\n />\n </summary>\n <div class=\"v-accordion-content\">\n <slot />\n </div>\n </details>\n</template>\n\n<style>\n@layer vectis.components {\n .v-accordion-item + .v-accordion-item {\n border-block-start: 1px solid var(--vectis-color-border);\n }\n\n .v-accordion-summary {\n --vectis-icon-size: var(--vectis-icon-size-md);\n --vectis-icon-opsz: 20;\n\n display: flex;\n align-items: center;\n gap: var(--vectis-space-3);\n padding: var(--accordion-pad-block, var(--vectis-space-4))\n var(--accordion-pad-inline, var(--vectis-space-5));\n cursor: pointer;\n font-size: var(--vectis-text-label-size);\n font-weight: var(--vectis-text-label-weight);\n color: var(--vectis-color-text);\n }\n\n .v-accordion-summary:hover:not([data-disabled]) {\n background: var(--accordion-hover-bg, var(--vectis-color-surface-muted));\n }\n\n .v-accordion-summary:focus-visible {\n outline: var(--vectis-focus-ring-width) solid var(--vectis-focus-ring-color);\n outline-offset: calc(-1 * var(--vectis-focus-ring-width));\n }\n\n .v-accordion-item:first-child > .v-accordion-summary {\n border-start-start-radius: var(--accordion-corner-radius, 0);\n border-start-end-radius: var(--accordion-corner-radius, 0);\n }\n\n .v-accordion-item:last-child:not([open]) > .v-accordion-summary {\n border-end-start-radius: var(--accordion-corner-radius, 0);\n border-end-end-radius: var(--accordion-corner-radius, 0);\n }\n\n .v-accordion-heading {\n flex: 1;\n display: flex;\n flex-direction: column;\n line-height: var(--vectis-text-label-leading);\n }\n\n .v-accordion-icon {\n flex: none;\n color: var(--vectis-color-text-muted);\n }\n\n /* A disabled item greys out through the colour tokens and never through\n `opacity`, the rule every control in the DS follows. */\n .v-accordion-summary[data-disabled] {\n color: var(--vectis-color-text-subtle);\n cursor: not-allowed;\n }\n\n /* The icon and the subtitle default to text-muted, which is DARKER than the\n text-subtle a disabled title takes: left to themselves they would come out\n stronger than the label they belong to, so they inherit it instead. The chevron\n gets the same treatment from `styles/disclosure.css`. */\n .v-accordion-summary[data-disabled] .v-accordion-icon,\n .v-accordion-summary[data-disabled] .v-accordion-subtitle {\n color: inherit;\n }\n\n .v-accordion-content {\n padding: var(--accordion-content-pad-start, var(--vectis-space-2))\n var(--accordion-pad-inline, var(--vectis-space-5))\n var(--accordion-pad-block, var(--vectis-space-4));\n font-size: var(--vectis-text-body-md-size);\n line-height: var(--vectis-text-body-md-leading);\n color: var(--vectis-color-text-muted);\n }\n\n /* The disclosure animation, the chevron's rotation or swap and the WebKit marker come\n from `styles/disclosure.css`, reduced-motion block included. */\n}\n</style>\n"],"mappings":""}
|
package/dist/components/VAccordion/VAccordionItem.vue_vue_type_script_setup_true_lang.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VAccordionItem.vue_vue_type_script_setup_true_lang.js","names":["$slots"],"sources":["../../../src/components/VAccordion/VAccordionItem.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Native details owns disclosure. useDetailsOpen bridges v-model and cancels activation of\n * disabled summaries.\n */\n\nimport { computed, inject, provide } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport { expand_more as expandMoreIcon } from '../VIcon/icons/expand_more'\nimport type { IconSource } from '../VIcon/types'\nimport VTypography from '../VTypography/VTypography.vue'\nimport { accordionKey } from './context'\n\nimport { useDetailsOpen } from '../../composables/useDetailsOpen'\n\ninterface AccordionItemProps {\n /**\n * The heading of the section, the line that stays visible when it is closed. Use the `#title`\n * slot instead when the heading needs markup rather than plain text.\n */\n title?: string\n /**\n * A secondary line under the title, for a short explanation or a status. The\n * `#subtitle` slot replaces it when markup is needed.\n */\n subtitle?: string\n /**\n * An icon placed before the title: an icon name, or an explicit render (`{ src }`,\n * `{ component }`…). The `#icon` slot replaces it.\n */\n icon?: IconSource\n /** Renders the section already open. Bind `v-model:open` to drive it instead. */\n defaultOpen?: boolean\n /** Makes the section inert. */\n disabled?: boolean\n}\n\nconst props = withDefaults(defineProps<AccordionItemProps>(), {\n title: undefined,\n subtitle: undefined,\n icon: undefined,\n defaultOpen: false,\n disabled: false,\n})\n\n// \"not bound\" is written as `null` and not `undefined`. A model typed as a plain boolean is\n// declared as such at runtime, and Vue casts an ABSENT boolean prop to `false`, which would\n// silently overwrite `defaultOpen`.\n/**\n * Whether the section is open, when the consumer wants to drive or observe it. Left\n * unbound, the browser keeps that state to itself, `defaultOpen` giving only the initial\n * value. `null` means unbound.\n */\nconst open = defineModel<boolean | null>('open', { default: null })\n\ndefineSlots<{\n /** The content revealed when the section is open. */\n default(): unknown\n /** A title made of markup, which replaces the `title` prop. */\n title?(): unknown\n /** A subtitle made of markup, which replaces the `subtitle` prop. */\n subtitle?(): unknown\n /** Free content before the title, which takes the place of `icon`. */\n icon?(): unknown\n}>()\n\nconst accordion = inject(accordionKey, null)\n// The group stops here: an item nested in this one's content without a VAccordion of its\n// own would otherwise share this group's name, and the browser closes every other member\n// of a name group when one opens, the section holding it included.\nprovide(accordionKey, null)\n\n/**\n * Both icons are chosen on the enclosing group. The chevron fallback is what keeps\n * an item rendering correctly when it is used outside a VAccordion.\n */\nconst expandIcon = computed(() => accordion?.expandIcon ?? expandMoreIcon)\nconst collapseIcon = computed(() => accordion?.collapseIcon)\n\nconst { openAttr, onToggle, onSummaryClick } = useDetailsOpen(open, {\n defaultOpen: () => props.defaultOpen,\n disabled: () => props.disabled,\n})\n</script>\n\n<template>\n <details\n class=\"v-accordion-item v-disclosure\"\n :name=\"accordion?.name\"\n :open=\"openAttr\"\n :data-swap=\"collapseIcon ? '' : undefined\"\n @toggle=\"onToggle\"\n >\n <summary\n class=\"v-accordion-summary\"\n :data-disabled=\"disabled ? '' : undefined\"\n :aria-disabled=\"disabled || undefined\"\n :tabindex=\"disabled ? -1 : undefined\"\n @click=\"onSummaryClick\"\n >\n <slot name=\"icon\">\n <VIcon v-if=\"icon\" class=\"v-accordion-icon\" v-bind=\"iconProps(icon)\" />\n </slot>\n <span class=\"v-accordion-heading\">\n <span class=\"v-accordion-title\"\n ><slot name=\"title\">{{ title }}</slot></span\n >\n <VTypography\n v-if=\"subtitle !== undefined || $slots.subtitle\"\n as=\"span\"\n variant=\"caption\"\n tone=\"muted\"\n class=\"v-accordion-subtitle\"\n ><slot name=\"subtitle\">{{ subtitle }}</slot></VTypography\n >\n </span>\n <VIcon class=\"v-accordion-chevron v-disclosure-chevron\" v-bind=\"iconProps(expandIcon)\" />\n <VIcon\n v-if=\"collapseIcon\"\n class=\"v-accordion-chevron v-accordion-chevron-open v-disclosure-chevron v-disclosure-chevron-open\"\n v-bind=\"iconProps(collapseIcon)\"\n />\n </summary>\n <div class=\"v-accordion-content\">\n <slot />\n </div>\n </details>\n</template>\n\n<style>\n@layer vectis.components {\n .v-accordion-item + .v-accordion-item {\n border-block-start: 1px solid var(--vectis-color-border);\n }\n\n .v-accordion-summary {\n --vectis-icon-size: var(--vectis-icon-size-md);\n --vectis-icon-opsz: 20;\n\n display: flex;\n align-items: center;\n gap: var(--vectis-space-3);\n padding: var(--accordion-pad-block, var(--vectis-space-4))\n var(--accordion-pad-inline, var(--vectis-space-5));\n cursor: pointer;\n font-size: var(--vectis-text-label-size);\n font-weight: var(--vectis-text-label-weight);\n color: var(--vectis-color-text);\n }\n\n .v-accordion-summary:hover:not([data-disabled]) {\n background: var(--accordion-hover-bg, var(--vectis-color-surface-muted));\n }\n\n .v-accordion-summary:focus-visible {\n outline: var(--vectis-focus-ring-width) solid var(--vectis-focus-ring-color);\n outline-offset: calc(-1 * var(--vectis-focus-ring-width));\n }\n\n .v-accordion-item:first-child > .v-accordion-summary {\n border-start-start-radius: var(--accordion-corner-radius, 0);\n border-start-end-radius: var(--accordion-corner-radius, 0);\n }\n\n .v-accordion-item:last-child:not([open]) > .v-accordion-summary {\n border-end-start-radius: var(--accordion-corner-radius, 0);\n border-end-end-radius: var(--accordion-corner-radius, 0);\n }\n\n .v-accordion-heading {\n flex: 1;\n display: flex;\n flex-direction: column;\n line-height: var(--vectis-text-label-leading);\n }\n\n .v-accordion-icon {\n flex: none;\n color: var(--vectis-color-text-muted);\n }\n\n /* A disabled item greys out through the colour tokens and never through\n `opacity`, the rule every control in the DS follows. */\n .v-accordion-summary[data-disabled] {\n color: var(--vectis-color-text-subtle);\n cursor: not-allowed;\n }\n\n /* The icon and the subtitle default to text-muted, which is DARKER than the\n text-subtle a disabled title takes: left to themselves they would come out\n stronger than the label they belong to, so they inherit it instead. The chevron\n gets the same treatment from `styles/disclosure.css`. */\n .v-accordion-summary[data-disabled] .v-accordion-icon,\n .v-accordion-summary[data-disabled] .v-accordion-subtitle {\n color: inherit;\n }\n\n .v-accordion-content {\n padding: var(--accordion-content-pad-start, var(--vectis-space-2))\n var(--accordion-pad-inline, var(--vectis-space-5))\n var(--accordion-pad-block, var(--vectis-space-4));\n font-size: var(--vectis-text-body-md-size);\n line-height: var(--vectis-text-body-md-leading);\n color: var(--vectis-color-text-muted);\n }\n\n /* The disclosure animation, the chevron's rotation or swap and the WebKit marker come\n from `styles/disclosure.css`, reduced-motion block included. */\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuCA,IAAM,IAAQ,GAgBR,IAAO,EAA2B,GAAC,MAAyB,GAa5D,IAAY,EAAO,GAAc,IAAI;EAI3C,EAAQ,GAAc,IAAI;EAM1B,IAAM,IAAa,QAAe,GAAW,cAAc,CAAc,GACnE,IAAe,QAAe,GAAW,YAAY,GAErD,EAAE,aAAU,aAAU,sBAAmB,EAAe,GAAM;GAClE,mBAAmB,EAAM;GACzB,gBAAgB,EAAM;EACxB,CAAC;yBAIC,EAwCU,WAAA;GAvCR,OAAM;GACL,MAAM,EAAA,CAAA,CAAS,EAAE;GACjB,MAAM,EAAA,CAAA;GACN,aAAW,EAAA,QAAY,KAAQ,KAAA;GAC/B,UAAM,AAAA,EAAA,QAAA,GAAA,MAAE,EAAA,CAAA,KAAA,EAAA,CAAA,CAAA,CAAA,GAAA,CAAA;MAET,EA6BU,WAAA;GA5BR,OAAM;GACL,iBAAe,EAAA,WAAQ,KAAQ,KAAA;GAC/B,iBAAe,EAAA,YAAY,KAAA;GAC3B,UAAU,EAAA,WAAQ,KAAQ,KAAA;GAC1B,SAAK,AAAA,EAAA,QAAA,GAAA,MAAE,EAAA,CAAA,KAAA,EAAA,CAAA,CAAA,CAAA,GAAA,CAAA;;GAER,EAEO,EAAA,QAAA,QAAA,CAAA,SAAA,CADQ,EAAA,QAAA,EAAA,GAAb,EAAuE,GAAvE,EAAuE;;IAApD,OAAM;MAA2B,EAAA,CAAA,CAAS,CAAC,EAAA,IAAI,CAAA,GAAA,MAAA,EAAA,KAAA,EAAA,IAAA,EAAA,CAAA,CAAA;GAEpE,EAYO,QAZP,GAYO,CAXL,EAEC,QAFD,GAEC,CADE,EAAqC,EAAA,QAAA,SAAA,CAAA,SAAA,CAAA,EAAA,EAAf,EAAA,KAAK,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAGtB,EAAA,aAAa,KAAA,KAAaA,EAAAA,OAAO,YAAA,EAAA,GADzC,EAOC,GAAA;;IALC,IAAG;IACH,SAAQ;IACR,MAAK;IACL,OAAM;;qBACsC,CAA3C,EAA2C,EAAA,QAAA,YAAA,CAAA,SAAA,CAAA,EAAA,EAAlB,EAAA,QAAQ,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA;;;GAGtC,EAAyF,GAAzF,EAAyF,EAAlF,OAAM,2CAA0C,GAAS,EAAA,CAAA,CAAS,CAAC,EAAA,KAAU,CAAA,GAAA,MAAA,EAAA;GAE5E,EAAA,SAAA,EAAA,GADR,EAIE,GAJF,EAIE;;IAFA,OAAM;MACE,EAAA,CAAA,CAAS,CAAC,EAAA,KAAY,CAAA,GAAA,MAAA,EAAA,KAAA,EAAA,IAAA,EAAA;YAGlC,EAEM,OAFN,GAEM,CADJ,EAAQ,EAAA,QAAA,SAAA,CAAA,CAAA,CAAA,GAAA,IAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"VAccordionItem.vue_vue_type_script_setup_true_lang.js","names":["$slots","_useModel","expandMoreIcon","_openBlock","_createElementBlock","_unref","_createElementVNode","_renderSlot","_createBlock","VIcon","_mergeProps","_createCommentVNode","_createTextVNode","_toDisplayString","VTypography","_withCtx","_createVNode","VIcon_default","VTypography_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","VAccordionItem_vue_vue_type_script_setup_true_lang_default","\"open\"","\"openModifiers\"","props","__props","open","useModel","accordion","inject","accordionKey","expandIcon","computed","expand_more","collapseIcon","useDetailsOpen","openBlock","createElementBlock","unref","openAttr","_cache","args","onToggle","createElementVNode","onSummaryClick","renderSlot","_ctx","createBlock","mergeProps","iconProps","createCommentVNode","createTextVNode","toDisplayString","withCtx","createVNode"],"sources":["../../../src/components/VAccordion/VAccordionItem.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Native details owns disclosure. useDetailsOpen bridges v-model and cancels activation of\n * disabled summaries.\n */\n\nimport { computed, inject, provide } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport { expand_more as expandMoreIcon } from '../VIcon/icons/expand_more'\nimport type { IconSource } from '../VIcon/types'\nimport VTypography from '../VTypography/VTypography.vue'\nimport { accordionKey } from './context'\n\nimport { useDetailsOpen } from '../../composables/useDetailsOpen'\n\ninterface AccordionItemProps {\n /**\n * The heading of the section, the line that stays visible when it is closed. Use the `#title`\n * slot instead when the heading needs markup rather than plain text.\n */\n title?: string\n /**\n * A secondary line under the title, for a short explanation or a status. The\n * `#subtitle` slot replaces it when markup is needed.\n */\n subtitle?: string\n /**\n * An icon placed before the title: an icon name, or an explicit render (`{ src }`,\n * `{ component }`…). The `#icon` slot replaces it.\n */\n icon?: IconSource\n /** Renders the section already open. Bind `v-model:open` to drive it instead. */\n defaultOpen?: boolean\n /** Makes the section inert. */\n disabled?: boolean\n}\n\nconst props = withDefaults(defineProps<AccordionItemProps>(), {\n title: undefined,\n subtitle: undefined,\n icon: undefined,\n defaultOpen: false,\n disabled: false,\n})\n\n// \"not bound\" is written as `null` and not `undefined`. A model typed as a plain boolean is\n// declared as such at runtime, and Vue casts an ABSENT boolean prop to `false`, which would\n// silently overwrite `defaultOpen`.\n/**\n * Whether the section is open, when the consumer wants to drive or observe it. Left\n * unbound, the browser keeps that state to itself, `defaultOpen` giving only the initial\n * value. `null` means unbound.\n */\nconst open = defineModel<boolean | null>('open', { default: null })\n\ndefineSlots<{\n /** The content revealed when the section is open. */\n default(): unknown\n /** A title made of markup, which replaces the `title` prop. */\n title?(): unknown\n /** A subtitle made of markup, which replaces the `subtitle` prop. */\n subtitle?(): unknown\n /** Free content before the title, which takes the place of `icon`. */\n icon?(): unknown\n}>()\n\nconst accordion = inject(accordionKey, null)\n// The group stops here: an item nested in this one's content without a VAccordion of its\n// own would otherwise share this group's name, and the browser closes every other member\n// of a name group when one opens, the section holding it included.\nprovide(accordionKey, null)\n\n/**\n * Both icons are chosen on the enclosing group. The chevron fallback is what keeps\n * an item rendering correctly when it is used outside a VAccordion.\n */\nconst expandIcon = computed(() => accordion?.expandIcon ?? expandMoreIcon)\nconst collapseIcon = computed(() => accordion?.collapseIcon)\n\nconst { openAttr, onToggle, onSummaryClick } = useDetailsOpen(open, {\n defaultOpen: () => props.defaultOpen,\n disabled: () => props.disabled,\n})\n</script>\n\n<template>\n <details\n class=\"v-accordion-item v-disclosure\"\n :name=\"accordion?.name\"\n :open=\"openAttr\"\n :data-swap=\"collapseIcon ? '' : undefined\"\n @toggle=\"onToggle\"\n >\n <summary\n class=\"v-accordion-summary\"\n :data-disabled=\"disabled ? '' : undefined\"\n :aria-disabled=\"disabled || undefined\"\n :tabindex=\"disabled ? -1 : undefined\"\n @click=\"onSummaryClick\"\n >\n <slot name=\"icon\">\n <VIcon v-if=\"icon\" class=\"v-accordion-icon\" v-bind=\"iconProps(icon)\" />\n </slot>\n <span class=\"v-accordion-heading\">\n <span class=\"v-accordion-title\"\n ><slot name=\"title\">{{ title }}</slot></span\n >\n <VTypography\n v-if=\"subtitle !== undefined || $slots.subtitle\"\n as=\"span\"\n variant=\"caption\"\n tone=\"muted\"\n class=\"v-accordion-subtitle\"\n ><slot name=\"subtitle\">{{ subtitle }}</slot></VTypography\n >\n </span>\n <VIcon class=\"v-accordion-chevron v-disclosure-chevron\" v-bind=\"iconProps(expandIcon)\" />\n <VIcon\n v-if=\"collapseIcon\"\n class=\"v-accordion-chevron v-accordion-chevron-open v-disclosure-chevron v-disclosure-chevron-open\"\n v-bind=\"iconProps(collapseIcon)\"\n />\n </summary>\n <div class=\"v-accordion-content\">\n <slot />\n </div>\n </details>\n</template>\n\n<style>\n@layer vectis.components {\n .v-accordion-item + .v-accordion-item {\n border-block-start: 1px solid var(--vectis-color-border);\n }\n\n .v-accordion-summary {\n --vectis-icon-size: var(--vectis-icon-size-md);\n --vectis-icon-opsz: 20;\n\n display: flex;\n align-items: center;\n gap: var(--vectis-space-3);\n padding: var(--accordion-pad-block, var(--vectis-space-4))\n var(--accordion-pad-inline, var(--vectis-space-5));\n cursor: pointer;\n font-size: var(--vectis-text-label-size);\n font-weight: var(--vectis-text-label-weight);\n color: var(--vectis-color-text);\n }\n\n .v-accordion-summary:hover:not([data-disabled]) {\n background: var(--accordion-hover-bg, var(--vectis-color-surface-muted));\n }\n\n .v-accordion-summary:focus-visible {\n outline: var(--vectis-focus-ring-width) solid var(--vectis-focus-ring-color);\n outline-offset: calc(-1 * var(--vectis-focus-ring-width));\n }\n\n .v-accordion-item:first-child > .v-accordion-summary {\n border-start-start-radius: var(--accordion-corner-radius, 0);\n border-start-end-radius: var(--accordion-corner-radius, 0);\n }\n\n .v-accordion-item:last-child:not([open]) > .v-accordion-summary {\n border-end-start-radius: var(--accordion-corner-radius, 0);\n border-end-end-radius: var(--accordion-corner-radius, 0);\n }\n\n .v-accordion-heading {\n flex: 1;\n display: flex;\n flex-direction: column;\n line-height: var(--vectis-text-label-leading);\n }\n\n .v-accordion-icon {\n flex: none;\n color: var(--vectis-color-text-muted);\n }\n\n /* A disabled item greys out through the colour tokens and never through\n `opacity`, the rule every control in the DS follows. */\n .v-accordion-summary[data-disabled] {\n color: var(--vectis-color-text-subtle);\n cursor: not-allowed;\n }\n\n /* The icon and the subtitle default to text-muted, which is DARKER than the\n text-subtle a disabled title takes: left to themselves they would come out\n stronger than the label they belong to, so they inherit it instead. The chevron\n gets the same treatment from `styles/disclosure.css`. */\n .v-accordion-summary[data-disabled] .v-accordion-icon,\n .v-accordion-summary[data-disabled] .v-accordion-subtitle {\n color: inherit;\n }\n\n .v-accordion-content {\n padding: var(--accordion-content-pad-start, var(--vectis-space-2))\n var(--accordion-pad-inline, var(--vectis-space-5))\n var(--accordion-pad-block, var(--vectis-space-4));\n font-size: var(--vectis-text-body-md-size);\n line-height: var(--vectis-text-body-md-leading);\n color: var(--vectis-color-text-muted);\n }\n\n /* The disclosure animation, the chevron's rotation or swap and the WebKit marker come\n from `styles/disclosure.css`, reduced-motion block included. */\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuCA,IAAM2B,IAAQC,GAgBRC,IAAO5B,EAA2B2B,GAAC,MAAyB,GAa5DG,IAAYC,EAAOC,GAAc,IAAI;EAI3C,EAAQA,GAAc,IAAI;EAM1B,IAAMC,IAAaC,QAAeJ,GAAW,cAAc7B,CAAc,GACnEmC,IAAeF,QAAeJ,GAAW,YAAY,GAErD,EAAE,aAAU,aAAU,sBAAmBO,EAAeT,GAAM;GAClE,mBAAmBF,EAAM;GACzB,gBAAgBA,EAAM;EACxB,CAAC;oBAICxB,EAAA,GAAAC,EAwCU,WAAA;GAvCR,OAAM;GACL,MAAMC,EAAA0B,CAAA,CAAS,EAAE;GACjB,MAAM1B,EAAAqC,CAAA;GACN,aAAWL,EAAA,QAAY,KAAQ,KAAA;GAC/B,UAAM,AAAAM,EAAA,QAAE,GAAAC,MAAAvC,EAAAwC,CAAA,KAAAxC,EAAAwC,CAAA,CAAA,CAAA,GAAAD,CAAA;EAETtC,GAAAA,CAAAA,EA6BU,WAAA;GA5BR,OAAM;GACL,iBAAesB,EAAA,WAAQ,KAAQ,KAAA;GAC/B,iBAAeA,EAAA,YAAY,KAAA;GAC3B,UAAUA,EAAA,WAAQ,KAAQ,KAAA;GAC1B,SAAK,AAAAe,EAAA,QAAE,GAAAC,MAAAvC,EAAA0C,CAAA,KAAA1C,EAAA0C,CAAA,CAAA,CAAA,GAAAH,CAAA;;GAERrC,EAEO0C,EAAA,QAAA,QAAA,CAAA,SAAA,CADQrB,EAAA,QAAbzB,EAAA,GAAAK,EAAuEC,GAAvEC,EAAuE;;IAApD,OAAM;GAA2B,GAAAL,EAAA+C,CAAA,CAAS,CAACxB,EAAA,IAAI,CAAA,GAAA,MAAA,EAAA,KAAAyB,EAAA,IAAA,EAAA,CAAA,CAAA;GAEpE/C,EAYO,QAZPe,GAYO,CAXLf,EAEC,QAFDgB,GAEC,CADEf,EAAqC0C,EAAA,QAAA,SAAA,CAAA,SAAA,CAAfrC,EAAAC,EAAAe,EAAA,KAAK,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAGtBA,EAAA,aAAa,KAAA,KAAa5B,EAAAA,OAAO,YADzCG,EAAA,GAAAK,EAOCM,GAAA;;IALC,IAAG;IACH,SAAQ;IACR,MAAK;IACL,OAAM;;IACL,SAAAC,QAA2C,CAA3CR,EAA2C0C,EAAA,QAAA,YAAA,CAAA,SAAA,CAAlBrC,EAAAC,EAAAe,EAAA,QAAQ,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA;;;GAGtCZ,EAAyFP,GAAzFC,EAAyF,EAAlF,OAAM,2CAA0C,GAASL,EAAA+C,CAAA,CAAS,CAAClB,EAAA,KAAU,CAAA,GAAA,MAAA,EAAA;GAE5EG,EAAA,SADRlC,EAAA,GAAAK,EAIEC,GAJFC,EAIE;;IAFA,OAAM;GACE,GAAAL,EAAA+C,CAAA,CAAS,CAACf,EAAA,KAAY,CAAA,GAAA,MAAA,EAAA,KAAAgB,EAAA,IAAA,EAAA;EAGlC/C,GAAAA,GAAAA,CAAAA,GAAAA,EAEM,OAFNiB,GAEM,CADJhB,EAAQ0C,EAAA,QAAA,SAAA,CAAA,CAAA,CAAA,GAAA,IAAA9B,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","names":[],"sources":["../../../src/components/VAccordion/context.ts"],"sourcesContent":["/** Share group icons through context; compact spacing inherits through CSS variables. */\n\nimport type { InjectionKey } from 'vue'\n\nimport type { IconSource } from '../VIcon/types'\n\nexport interface AccordionContext {\n /** Group name for <details name>; undefined = several items may stay open at once. */\n name: string | undefined\n /** Icon in the closed state: an icon name, or an explicit render. */\n expandIcon: IconSource\n /** Icon in the open state; undefined = a rotation of `expandIcon`. */\n collapseIcon: IconSource | undefined\n}\n\n/**\n * `null` is what an item provides to its own content: an item placed straight inside\n * another one must not join the outer group, since opening it would then close the section\n * that holds it.\n */\nexport const accordionKey: InjectionKey<AccordionContext | null> = Symbol('v-accordion')\n"],"mappings":";AAoBA,
|
|
1
|
+
{"version":3,"file":"context.js","names":["accordionKey"],"sources":["../../../src/components/VAccordion/context.ts"],"sourcesContent":["/** Share group icons through context; compact spacing inherits through CSS variables. */\n\nimport type { InjectionKey } from 'vue'\n\nimport type { IconSource } from '../VIcon/types'\n\nexport interface AccordionContext {\n /** Group name for <details name>; undefined = several items may stay open at once. */\n name: string | undefined\n /** Icon in the closed state: an icon name, or an explicit render. */\n expandIcon: IconSource\n /** Icon in the open state; undefined = a rotation of `expandIcon`. */\n collapseIcon: IconSource | undefined\n}\n\n/**\n * `null` is what an item provides to its own content: an item placed straight inside\n * another one must not join the outer group, since opening it would then close the section\n * that holds it.\n */\nexport const accordionKey: InjectionKey<AccordionContext | null> = Symbol('v-accordion')\n"],"mappings":";AAoBA,IAAaA,IAAsD,OAAO,aAAa"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VAlert.js","names":[],"sources":["../../../src/components/VAlert/VAlert.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @a11y\n/**\n * A message that stays in the flow of the page. It carries no live role unless asked: a page\n * that renders alerts on load would otherwise have them all read out at once.\n */\n\nimport { computed } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport { check_circle as checkCircleIcon } from '../VIcon/icons/check_circle'\nimport { close as closeIcon } from '../VIcon/icons/close'\nimport { error as errorIcon } from '../VIcon/icons/error'\nimport { info as infoIcon } from '../VIcon/icons/info'\nimport { warning as warningIcon } from '../VIcon/icons/warning'\nimport type { IconSource } from '../VIcon/types'\nimport VIconButton from '../VIconButton/VIconButton.vue'\nimport { useMessages } from '../../i18n/state'\n\n/** How the alert is painted: a tinted surface, or the page surface inside a tinted border. */\nexport type AlertVariant = 'soft' | 'outline'\n/** What the alert means, in colour. */\nexport type AlertTone = 'neutral' | 'accent' | 'danger' | 'success' | 'warning'\n\ninterface AlertProps {\n /**\n * How the alert is painted: a surface tinted with the tone (`soft`, the default), or the page\n * surface inside a border of the tone (`outline`), for an alert that should weigh less.\n */\n variant?: AlertVariant\n /** What the alert means, expressed as a colour. It also picks the default icon. */\n tone?: AlertTone\n /** A short line above the message, in bold. The `#title` slot replaces it. */\n title?: string\n /**\n * The icon before the text: an icon name, or an explicit render (the VIcon contract). Left\n * out, the tone brings its own.\n */\n icon?: IconSource\n /** Draws no icon at all, neither the one given nor the tone's. */\n hideIcon?: boolean\n /** Adds a close cross, which sets `open` to false and emits `close`. */\n closable?: boolean\n /** What the close cross does, in words. It falls back to the design system dictionary. */\n closeLabel?: string\n /**\n * Makes the alert a live region, for a message that appears in answer to what the reader\n * did: `role=\"alert\"` for the `danger` tone, which interrupts, `role=\"status\"` otherwise.\n */\n live?: boolean\n}\n\nconst props = withDefaults(defineProps<AlertProps>(), {\n variant: 'soft',\n tone: 'accent',\n title: undefined,\n icon: undefined,\n hideIcon: false,\n closable: false,\n closeLabel: undefined,\n live: false,\n})\n\n/**\n * Whether the alert is shown. It is true by default, unlike other boolean props: an alert is\n * there until something takes it away, and binding the model is only needed to bring it back.\n */\nconst open = defineModel<boolean>('open', { default: true })\n\nconst emit = defineEmits<{\n /** The reader closed the alert with its cross. `open` has already turned false. */\n close: []\n}>()\n\ndefineSlots<{\n /** The message. */\n default?(): unknown\n /** Replaces the `title` prop with content of your own. */\n title?(): unknown\n /** Buttons or links under the message. */\n actions?(): unknown\n}>()\n\nconst m = useMessages()\nconst resolvedCloseLabel = computed(() => props.closeLabel ?? m.value.common.close)\n\nconst DEFAULT_ICONS: Record<AlertTone, IconSource> = {\n neutral: infoIcon,\n accent: infoIcon,\n success: checkCircleIcon,\n danger: errorIcon,\n warning: warningIcon,\n}\n\nconst resolvedIcon = computed(() =>\n props.hideIcon ? undefined : iconProps(props.icon ?? DEFAULT_ICONS[props.tone]),\n)\n\nconst role = computed(() =>\n props.live ? (props.tone === 'danger' ? 'alert' : 'status') : undefined,\n)\n\nfunction close() {\n open.value = false\n emit('close')\n}\n</script>\n\n<template>\n <div v-if=\"open\" :role=\"role\" class=\"v-alert v-tone\" :data-variant=\"variant\" :data-tone=\"tone\">\n <VIcon v-if=\"resolvedIcon\" class=\"v-alert-icon\" v-bind=\"resolvedIcon\" />\n <div class=\"v-alert-body\">\n <p v-if=\"$slots.title || title\" class=\"v-alert-title\">\n <slot name=\"title\">{{ title }}</slot>\n </p>\n <div v-if=\"$slots.default\" class=\"v-alert-message\">\n <slot />\n </div>\n <div v-if=\"$slots.actions\" class=\"v-alert-actions\">\n <slot name=\"actions\" />\n </div>\n </div>\n <VIconButton\n v-if=\"closable\"\n class=\"v-alert-close\"\n :label=\"resolvedCloseLabel\"\n size=\"sm\"\n @click=\"close\"\n >\n <VIcon :name=\"closeIcon\" />\n </VIconButton>\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n /*\n * The colours come from the shared tone table (styles/tones.css, `.v-tone`), read here rather\n * than through `.v-variant`: the alert paints its own border and keeps the message in the body\n * text colour, which no shared variant does.\n */\n .v-alert {\n /* The height of one line of text, which the icon and the cross are centred against. */\n --alert-line: calc(var(--vectis-text-body-md-size) * var(--vectis-text-body-md-leading));\n\n display: flex;\n align-items: flex-start;\n gap: var(--vectis-space-3);\n padding: var(--vectis-space-3) var(--vectis-space-4);\n border: 1px solid var(--tone-border-soft);\n border-radius: var(--vectis-radius-surface);\n color: var(--vectis-color-text);\n font-family: var(--vectis-text-family);\n font-size: var(--vectis-text-body-md-size);\n font-weight: var(--vectis-text-body-md-weight);\n line-height: var(--vectis-text-body-md-leading);\n }\n\n .v-alert[data-variant='soft'] {\n background: var(--tone-bg-soft);\n }\n\n .v-alert[data-variant='outline'] {\n background: var(--vectis-color-surface);\n }\n\n .v-alert-icon {\n --vectis-icon-size: var(--vectis-icon-size-md);\n flex: none;\n margin-block: calc((var(--alert-line) - var(--vectis-icon-size-md)) / 2);\n color: var(--tone-text-tinted);\n }\n\n /* Long unbroken text, a URL in an error message, wraps instead of widening the alert. */\n .v-alert-body {\n display: flex;\n flex: 1;\n flex-direction: column;\n gap: var(--vectis-space-1);\n min-inline-size: 0;\n overflow-wrap: anywhere;\n }\n\n .v-alert-title {\n color: var(--tone-text-tinted);\n /*\n * The heavier weight marks the title against its own message, which is emphasis rather than\n * a typographic role; hence a font token read directly.\n */\n font-weight: var(--vectis-font-weight-semibold);\n }\n\n .v-alert-actions {\n display: flex;\n flex-wrap: wrap;\n gap: var(--vectis-space-2);\n margin-block-start: var(--vectis-space-2);\n }\n\n /*\n * The cross keeps the height of a small control but is centred on the first line, and gives\n * back its own padding so it does not double the alert's gutter.\n */\n .v-alert-close {\n flex: none;\n margin-block: calc((var(--alert-line) - var(--vectis-control-height-sm)) / 2);\n margin-inline-end: calc(-1 * var(--vectis-space-2));\n }\n\n /*\n * A neutral ghost hovers in grey, which turns muddy on a tinted surface: the cross hovers in a\n * tint of the alert's own tone instead. The tone table sits in a lower layer, so this rebind\n * wins whatever the specificity of the button's `[data-tone]` row.\n */\n .v-alert .v-alert-close[data-tone] {\n --tone-text-tinted: var(--vectis-color-text-muted);\n --tone-bg-soft: color-mix(in oklab, currentcolor, transparent 88%);\n }\n}\n</style>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"VAlert.js","names":["_sfc_main","VAlert_vue_vue_type_script_setup_true_lang_default","VAlert_default"],"sources":["../../../src/components/VAlert/VAlert.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @a11y\n/**\n * A message that stays in the flow of the page. It carries no live role unless asked: a page\n * that renders alerts on load would otherwise have them all read out at once.\n */\n\nimport { computed } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport { check_circle as checkCircleIcon } from '../VIcon/icons/check_circle'\nimport { close as closeIcon } from '../VIcon/icons/close'\nimport { error as errorIcon } from '../VIcon/icons/error'\nimport { info as infoIcon } from '../VIcon/icons/info'\nimport { warning as warningIcon } from '../VIcon/icons/warning'\nimport type { IconSource } from '../VIcon/types'\nimport VIconButton from '../VIconButton/VIconButton.vue'\nimport { useMessages } from '../../i18n/state'\n\n/** How the alert is painted: a tinted surface, or the page surface inside a tinted border. */\nexport type AlertVariant = 'soft' | 'outline'\n/** What the alert means, in colour. */\nexport type AlertTone = 'neutral' | 'accent' | 'danger' | 'success' | 'warning'\n\ninterface AlertProps {\n /**\n * How the alert is painted: a surface tinted with the tone (`soft`, the default), or the page\n * surface inside a border of the tone (`outline`), for an alert that should weigh less.\n */\n variant?: AlertVariant\n /** What the alert means, expressed as a colour. It also picks the default icon. */\n tone?: AlertTone\n /** A short line above the message, in bold. The `#title` slot replaces it. */\n title?: string\n /**\n * The icon before the text: an icon name, or an explicit render (the VIcon contract). Left\n * out, the tone brings its own.\n */\n icon?: IconSource\n /** Draws no icon at all, neither the one given nor the tone's. */\n hideIcon?: boolean\n /** Adds a close cross, which sets `open` to false and emits `close`. */\n closable?: boolean\n /** What the close cross does, in words. It falls back to the design system dictionary. */\n closeLabel?: string\n /**\n * Makes the alert a live region, for a message that appears in answer to what the reader\n * did: `role=\"alert\"` for the `danger` tone, which interrupts, `role=\"status\"` otherwise.\n */\n live?: boolean\n}\n\nconst props = withDefaults(defineProps<AlertProps>(), {\n variant: 'soft',\n tone: 'accent',\n title: undefined,\n icon: undefined,\n hideIcon: false,\n closable: false,\n closeLabel: undefined,\n live: false,\n})\n\n/**\n * Whether the alert is shown. It is true by default, unlike other boolean props: an alert is\n * there until something takes it away, and binding the model is only needed to bring it back.\n */\nconst open = defineModel<boolean>('open', { default: true })\n\nconst emit = defineEmits<{\n /** The reader closed the alert with its cross. `open` has already turned false. */\n close: []\n}>()\n\ndefineSlots<{\n /** The message. */\n default?(): unknown\n /** Replaces the `title` prop with content of your own. */\n title?(): unknown\n /** Buttons or links under the message. */\n actions?(): unknown\n}>()\n\nconst m = useMessages()\nconst resolvedCloseLabel = computed(() => props.closeLabel ?? m.value.common.close)\n\nconst DEFAULT_ICONS: Record<AlertTone, IconSource> = {\n neutral: infoIcon,\n accent: infoIcon,\n success: checkCircleIcon,\n danger: errorIcon,\n warning: warningIcon,\n}\n\nconst resolvedIcon = computed(() =>\n props.hideIcon ? undefined : iconProps(props.icon ?? DEFAULT_ICONS[props.tone]),\n)\n\nconst role = computed(() =>\n props.live ? (props.tone === 'danger' ? 'alert' : 'status') : undefined,\n)\n\nfunction close() {\n open.value = false\n emit('close')\n}\n</script>\n\n<template>\n <div v-if=\"open\" :role=\"role\" class=\"v-alert v-tone\" :data-variant=\"variant\" :data-tone=\"tone\">\n <VIcon v-if=\"resolvedIcon\" class=\"v-alert-icon\" v-bind=\"resolvedIcon\" />\n <div class=\"v-alert-body\">\n <p v-if=\"$slots.title || title\" class=\"v-alert-title\">\n <slot name=\"title\">{{ title }}</slot>\n </p>\n <div v-if=\"$slots.default\" class=\"v-alert-message\">\n <slot />\n </div>\n <div v-if=\"$slots.actions\" class=\"v-alert-actions\">\n <slot name=\"actions\" />\n </div>\n </div>\n <VIconButton\n v-if=\"closable\"\n class=\"v-alert-close\"\n :label=\"resolvedCloseLabel\"\n size=\"sm\"\n @click=\"close\"\n >\n <VIcon :name=\"closeIcon\" />\n </VIconButton>\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n /*\n * The colours come from the shared tone table (styles/tones.css, `.v-tone`), read here rather\n * than through `.v-variant`: the alert paints its own border and keeps the message in the body\n * text colour, which no shared variant does.\n */\n .v-alert {\n /* The height of one line of text, which the icon and the cross are centred against. */\n --alert-line: calc(var(--vectis-text-body-md-size) * var(--vectis-text-body-md-leading));\n\n display: flex;\n align-items: flex-start;\n gap: var(--vectis-space-3);\n padding: var(--vectis-space-3) var(--vectis-space-4);\n border: 1px solid var(--tone-border-soft);\n border-radius: var(--vectis-radius-surface);\n color: var(--vectis-color-text);\n font-family: var(--vectis-text-family);\n font-size: var(--vectis-text-body-md-size);\n font-weight: var(--vectis-text-body-md-weight);\n line-height: var(--vectis-text-body-md-leading);\n }\n\n .v-alert[data-variant='soft'] {\n background: var(--tone-bg-soft);\n }\n\n .v-alert[data-variant='outline'] {\n background: var(--vectis-color-surface);\n }\n\n .v-alert-icon {\n --vectis-icon-size: var(--vectis-icon-size-md);\n flex: none;\n margin-block: calc((var(--alert-line) - var(--vectis-icon-size-md)) / 2);\n color: var(--tone-text-tinted);\n }\n\n /* Long unbroken text, a URL in an error message, wraps instead of widening the alert. */\n .v-alert-body {\n display: flex;\n flex: 1;\n flex-direction: column;\n gap: var(--vectis-space-1);\n min-inline-size: 0;\n overflow-wrap: anywhere;\n }\n\n .v-alert-title {\n color: var(--tone-text-tinted);\n /*\n * The heavier weight marks the title against its own message, which is emphasis rather than\n * a typographic role; hence a font token read directly.\n */\n font-weight: var(--vectis-font-weight-semibold);\n }\n\n .v-alert-actions {\n display: flex;\n flex-wrap: wrap;\n gap: var(--vectis-space-2);\n margin-block-start: var(--vectis-space-2);\n }\n\n /*\n * The cross keeps the height of a small control but is centred on the first line, and gives\n * back its own padding so it does not double the alert's gutter.\n */\n .v-alert-close {\n flex: none;\n margin-block: calc((var(--alert-line) - var(--vectis-control-height-sm)) / 2);\n margin-inline-end: calc(-1 * var(--vectis-space-2));\n }\n\n /*\n * A neutral ghost hovers in grey, which turns muddy on a tinted surface: the cross hovers in a\n * tint of the alert's own tone instead. The tone table sits in a lower layer, so this rebind\n * wins whatever the specificity of the button's `[data-tone]` row.\n */\n .v-alert .v-alert-close[data-tone] {\n --tone-text-tinted: var(--vectis-color-text-muted);\n --tone-bg-soft: color-mix(in oklab, currentcolor, transparent 88%);\n }\n}\n</style>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VAlert.vue_vue_type_script_setup_true_lang.js","names":["$slots"],"sources":["../../../src/components/VAlert/VAlert.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @a11y\n/**\n * A message that stays in the flow of the page. It carries no live role unless asked: a page\n * that renders alerts on load would otherwise have them all read out at once.\n */\n\nimport { computed } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport { check_circle as checkCircleIcon } from '../VIcon/icons/check_circle'\nimport { close as closeIcon } from '../VIcon/icons/close'\nimport { error as errorIcon } from '../VIcon/icons/error'\nimport { info as infoIcon } from '../VIcon/icons/info'\nimport { warning as warningIcon } from '../VIcon/icons/warning'\nimport type { IconSource } from '../VIcon/types'\nimport VIconButton from '../VIconButton/VIconButton.vue'\nimport { useMessages } from '../../i18n/state'\n\n/** How the alert is painted: a tinted surface, or the page surface inside a tinted border. */\nexport type AlertVariant = 'soft' | 'outline'\n/** What the alert means, in colour. */\nexport type AlertTone = 'neutral' | 'accent' | 'danger' | 'success' | 'warning'\n\ninterface AlertProps {\n /**\n * How the alert is painted: a surface tinted with the tone (`soft`, the default), or the page\n * surface inside a border of the tone (`outline`), for an alert that should weigh less.\n */\n variant?: AlertVariant\n /** What the alert means, expressed as a colour. It also picks the default icon. */\n tone?: AlertTone\n /** A short line above the message, in bold. The `#title` slot replaces it. */\n title?: string\n /**\n * The icon before the text: an icon name, or an explicit render (the VIcon contract). Left\n * out, the tone brings its own.\n */\n icon?: IconSource\n /** Draws no icon at all, neither the one given nor the tone's. */\n hideIcon?: boolean\n /** Adds a close cross, which sets `open` to false and emits `close`. */\n closable?: boolean\n /** What the close cross does, in words. It falls back to the design system dictionary. */\n closeLabel?: string\n /**\n * Makes the alert a live region, for a message that appears in answer to what the reader\n * did: `role=\"alert\"` for the `danger` tone, which interrupts, `role=\"status\"` otherwise.\n */\n live?: boolean\n}\n\nconst props = withDefaults(defineProps<AlertProps>(), {\n variant: 'soft',\n tone: 'accent',\n title: undefined,\n icon: undefined,\n hideIcon: false,\n closable: false,\n closeLabel: undefined,\n live: false,\n})\n\n/**\n * Whether the alert is shown. It is true by default, unlike other boolean props: an alert is\n * there until something takes it away, and binding the model is only needed to bring it back.\n */\nconst open = defineModel<boolean>('open', { default: true })\n\nconst emit = defineEmits<{\n /** The reader closed the alert with its cross. `open` has already turned false. */\n close: []\n}>()\n\ndefineSlots<{\n /** The message. */\n default?(): unknown\n /** Replaces the `title` prop with content of your own. */\n title?(): unknown\n /** Buttons or links under the message. */\n actions?(): unknown\n}>()\n\nconst m = useMessages()\nconst resolvedCloseLabel = computed(() => props.closeLabel ?? m.value.common.close)\n\nconst DEFAULT_ICONS: Record<AlertTone, IconSource> = {\n neutral: infoIcon,\n accent: infoIcon,\n success: checkCircleIcon,\n danger: errorIcon,\n warning: warningIcon,\n}\n\nconst resolvedIcon = computed(() =>\n props.hideIcon ? undefined : iconProps(props.icon ?? DEFAULT_ICONS[props.tone]),\n)\n\nconst role = computed(() =>\n props.live ? (props.tone === 'danger' ? 'alert' : 'status') : undefined,\n)\n\nfunction close() {\n open.value = false\n emit('close')\n}\n</script>\n\n<template>\n <div v-if=\"open\" :role=\"role\" class=\"v-alert v-tone\" :data-variant=\"variant\" :data-tone=\"tone\">\n <VIcon v-if=\"resolvedIcon\" class=\"v-alert-icon\" v-bind=\"resolvedIcon\" />\n <div class=\"v-alert-body\">\n <p v-if=\"$slots.title || title\" class=\"v-alert-title\">\n <slot name=\"title\">{{ title }}</slot>\n </p>\n <div v-if=\"$slots.default\" class=\"v-alert-message\">\n <slot />\n </div>\n <div v-if=\"$slots.actions\" class=\"v-alert-actions\">\n <slot name=\"actions\" />\n </div>\n </div>\n <VIconButton\n v-if=\"closable\"\n class=\"v-alert-close\"\n :label=\"resolvedCloseLabel\"\n size=\"sm\"\n @click=\"close\"\n >\n <VIcon :name=\"closeIcon\" />\n </VIconButton>\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n /*\n * The colours come from the shared tone table (styles/tones.css, `.v-tone`), read here rather\n * than through `.v-variant`: the alert paints its own border and keeps the message in the body\n * text colour, which no shared variant does.\n */\n .v-alert {\n /* The height of one line of text, which the icon and the cross are centred against. */\n --alert-line: calc(var(--vectis-text-body-md-size) * var(--vectis-text-body-md-leading));\n\n display: flex;\n align-items: flex-start;\n gap: var(--vectis-space-3);\n padding: var(--vectis-space-3) var(--vectis-space-4);\n border: 1px solid var(--tone-border-soft);\n border-radius: var(--vectis-radius-surface);\n color: var(--vectis-color-text);\n font-family: var(--vectis-text-family);\n font-size: var(--vectis-text-body-md-size);\n font-weight: var(--vectis-text-body-md-weight);\n line-height: var(--vectis-text-body-md-leading);\n }\n\n .v-alert[data-variant='soft'] {\n background: var(--tone-bg-soft);\n }\n\n .v-alert[data-variant='outline'] {\n background: var(--vectis-color-surface);\n }\n\n .v-alert-icon {\n --vectis-icon-size: var(--vectis-icon-size-md);\n flex: none;\n margin-block: calc((var(--alert-line) - var(--vectis-icon-size-md)) / 2);\n color: var(--tone-text-tinted);\n }\n\n /* Long unbroken text, a URL in an error message, wraps instead of widening the alert. */\n .v-alert-body {\n display: flex;\n flex: 1;\n flex-direction: column;\n gap: var(--vectis-space-1);\n min-inline-size: 0;\n overflow-wrap: anywhere;\n }\n\n .v-alert-title {\n color: var(--tone-text-tinted);\n /*\n * The heavier weight marks the title against its own message, which is emphasis rather than\n * a typographic role; hence a font token read directly.\n */\n font-weight: var(--vectis-font-weight-semibold);\n }\n\n .v-alert-actions {\n display: flex;\n flex-wrap: wrap;\n gap: var(--vectis-space-2);\n margin-block-start: var(--vectis-space-2);\n }\n\n /*\n * The cross keeps the height of a small control but is centred on the first line, and gives\n * back its own padding so it does not double the alert's gutter.\n */\n .v-alert-close {\n flex: none;\n margin-block: calc((var(--alert-line) - var(--vectis-control-height-sm)) / 2);\n margin-inline-end: calc(-1 * var(--vectis-space-2));\n }\n\n /*\n * A neutral ghost hovers in grey, which turns muddy on a tinted surface: the cross hovers in a\n * tint of the alert's own tone instead. The tone table sits in a lower layer, so this rebind\n * wins whatever the specificity of the button's `[data-tone]` row.\n */\n .v-alert .v-alert-close[data-tone] {\n --tone-text-tinted: var(--vectis-color-text-muted);\n --tone-bg-soft: color-mix(in oklab, currentcolor, transparent 88%);\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqDA,
|
|
1
|
+
{"version":3,"file":"VAlert.vue_vue_type_script_setup_true_lang.js","names":["$slots","_useModel","infoIcon","checkCircleIcon","errorIcon","warningIcon","close","_openBlock","_createElementBlock","_createBlock","VIcon","_mergeProps","_createCommentVNode","_createElementVNode","_renderSlot","_createTextVNode","_toDisplayString","VIconButton","_withCtx","_createVNode","_unref","closeIcon","VIcon_default","VIconButton_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","VAlert_vue_vue_type_script_setup_true_lang_default","\"open\"","\"openModifiers\"","__emit","props","__props","open","useModel","emit","m","useMessages","resolvedCloseLabel","computed","DEFAULT_ICONS","info","check_circle","error","resolvedIcon","iconProps","role","close$1","openBlock","createElementBlock","createBlock","mergeProps","createCommentVNode","createElementVNode","_ctx","renderSlot","createTextVNode","toDisplayString","withCtx","createVNode","unref","close"],"sources":["../../../src/components/VAlert/VAlert.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @a11y\n/**\n * A message that stays in the flow of the page. It carries no live role unless asked: a page\n * that renders alerts on load would otherwise have them all read out at once.\n */\n\nimport { computed } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport { check_circle as checkCircleIcon } from '../VIcon/icons/check_circle'\nimport { close as closeIcon } from '../VIcon/icons/close'\nimport { error as errorIcon } from '../VIcon/icons/error'\nimport { info as infoIcon } from '../VIcon/icons/info'\nimport { warning as warningIcon } from '../VIcon/icons/warning'\nimport type { IconSource } from '../VIcon/types'\nimport VIconButton from '../VIconButton/VIconButton.vue'\nimport { useMessages } from '../../i18n/state'\n\n/** How the alert is painted: a tinted surface, or the page surface inside a tinted border. */\nexport type AlertVariant = 'soft' | 'outline'\n/** What the alert means, in colour. */\nexport type AlertTone = 'neutral' | 'accent' | 'danger' | 'success' | 'warning'\n\ninterface AlertProps {\n /**\n * How the alert is painted: a surface tinted with the tone (`soft`, the default), or the page\n * surface inside a border of the tone (`outline`), for an alert that should weigh less.\n */\n variant?: AlertVariant\n /** What the alert means, expressed as a colour. It also picks the default icon. */\n tone?: AlertTone\n /** A short line above the message, in bold. The `#title` slot replaces it. */\n title?: string\n /**\n * The icon before the text: an icon name, or an explicit render (the VIcon contract). Left\n * out, the tone brings its own.\n */\n icon?: IconSource\n /** Draws no icon at all, neither the one given nor the tone's. */\n hideIcon?: boolean\n /** Adds a close cross, which sets `open` to false and emits `close`. */\n closable?: boolean\n /** What the close cross does, in words. It falls back to the design system dictionary. */\n closeLabel?: string\n /**\n * Makes the alert a live region, for a message that appears in answer to what the reader\n * did: `role=\"alert\"` for the `danger` tone, which interrupts, `role=\"status\"` otherwise.\n */\n live?: boolean\n}\n\nconst props = withDefaults(defineProps<AlertProps>(), {\n variant: 'soft',\n tone: 'accent',\n title: undefined,\n icon: undefined,\n hideIcon: false,\n closable: false,\n closeLabel: undefined,\n live: false,\n})\n\n/**\n * Whether the alert is shown. It is true by default, unlike other boolean props: an alert is\n * there until something takes it away, and binding the model is only needed to bring it back.\n */\nconst open = defineModel<boolean>('open', { default: true })\n\nconst emit = defineEmits<{\n /** The reader closed the alert with its cross. `open` has already turned false. */\n close: []\n}>()\n\ndefineSlots<{\n /** The message. */\n default?(): unknown\n /** Replaces the `title` prop with content of your own. */\n title?(): unknown\n /** Buttons or links under the message. */\n actions?(): unknown\n}>()\n\nconst m = useMessages()\nconst resolvedCloseLabel = computed(() => props.closeLabel ?? m.value.common.close)\n\nconst DEFAULT_ICONS: Record<AlertTone, IconSource> = {\n neutral: infoIcon,\n accent: infoIcon,\n success: checkCircleIcon,\n danger: errorIcon,\n warning: warningIcon,\n}\n\nconst resolvedIcon = computed(() =>\n props.hideIcon ? undefined : iconProps(props.icon ?? DEFAULT_ICONS[props.tone]),\n)\n\nconst role = computed(() =>\n props.live ? (props.tone === 'danger' ? 'alert' : 'status') : undefined,\n)\n\nfunction close() {\n open.value = false\n emit('close')\n}\n</script>\n\n<template>\n <div v-if=\"open\" :role=\"role\" class=\"v-alert v-tone\" :data-variant=\"variant\" :data-tone=\"tone\">\n <VIcon v-if=\"resolvedIcon\" class=\"v-alert-icon\" v-bind=\"resolvedIcon\" />\n <div class=\"v-alert-body\">\n <p v-if=\"$slots.title || title\" class=\"v-alert-title\">\n <slot name=\"title\">{{ title }}</slot>\n </p>\n <div v-if=\"$slots.default\" class=\"v-alert-message\">\n <slot />\n </div>\n <div v-if=\"$slots.actions\" class=\"v-alert-actions\">\n <slot name=\"actions\" />\n </div>\n </div>\n <VIconButton\n v-if=\"closable\"\n class=\"v-alert-close\"\n :label=\"resolvedCloseLabel\"\n size=\"sm\"\n @click=\"close\"\n >\n <VIcon :name=\"closeIcon\" />\n </VIconButton>\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n /*\n * The colours come from the shared tone table (styles/tones.css, `.v-tone`), read here rather\n * than through `.v-variant`: the alert paints its own border and keeps the message in the body\n * text colour, which no shared variant does.\n */\n .v-alert {\n /* The height of one line of text, which the icon and the cross are centred against. */\n --alert-line: calc(var(--vectis-text-body-md-size) * var(--vectis-text-body-md-leading));\n\n display: flex;\n align-items: flex-start;\n gap: var(--vectis-space-3);\n padding: var(--vectis-space-3) var(--vectis-space-4);\n border: 1px solid var(--tone-border-soft);\n border-radius: var(--vectis-radius-surface);\n color: var(--vectis-color-text);\n font-family: var(--vectis-text-family);\n font-size: var(--vectis-text-body-md-size);\n font-weight: var(--vectis-text-body-md-weight);\n line-height: var(--vectis-text-body-md-leading);\n }\n\n .v-alert[data-variant='soft'] {\n background: var(--tone-bg-soft);\n }\n\n .v-alert[data-variant='outline'] {\n background: var(--vectis-color-surface);\n }\n\n .v-alert-icon {\n --vectis-icon-size: var(--vectis-icon-size-md);\n flex: none;\n margin-block: calc((var(--alert-line) - var(--vectis-icon-size-md)) / 2);\n color: var(--tone-text-tinted);\n }\n\n /* Long unbroken text, a URL in an error message, wraps instead of widening the alert. */\n .v-alert-body {\n display: flex;\n flex: 1;\n flex-direction: column;\n gap: var(--vectis-space-1);\n min-inline-size: 0;\n overflow-wrap: anywhere;\n }\n\n .v-alert-title {\n color: var(--tone-text-tinted);\n /*\n * The heavier weight marks the title against its own message, which is emphasis rather than\n * a typographic role; hence a font token read directly.\n */\n font-weight: var(--vectis-font-weight-semibold);\n }\n\n .v-alert-actions {\n display: flex;\n flex-wrap: wrap;\n gap: var(--vectis-space-2);\n margin-block-start: var(--vectis-space-2);\n }\n\n /*\n * The cross keeps the height of a small control but is centred on the first line, and gives\n * back its own padding so it does not double the alert's gutter.\n */\n .v-alert-close {\n flex: none;\n margin-block: calc((var(--alert-line) - var(--vectis-control-height-sm)) / 2);\n margin-inline-end: calc(-1 * var(--vectis-space-2));\n }\n\n /*\n * A neutral ghost hovers in grey, which turns muddy on a tinted surface: the cross hovers in a\n * tint of the alert's own tone instead. The tone table sits in a lower layer, so this rebind\n * wins whatever the specificity of the button's `[data-tone]` row.\n */\n .v-alert .v-alert-close[data-tone] {\n --tone-text-tinted: var(--vectis-color-text-muted);\n --tone-bg-soft: color-mix(in oklab, currentcolor, transparent 88%);\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqDA,IAAMiC,IAAQC,GAeRC,IAAOlC,EAAoBiC,GAAC,MAAyB,GAErDG,IAAOL,GAcPM,IAAIC,EAAY,GAChBC,IAAqBC,QAAeR,EAAM,cAAcK,EAAE,MAAM,OAAO,KAAK,GAE5EI,IAA+C;GACnD,SAASxC;GACT,QAAQA;GACR,SAASC;GACT,QAAQC;GACCC;EACX,GAEMyC,IAAeL,QACnBR,EAAM,WAAW,KAAA,IAAYc,EAAUd,EAAM,QAAQS,EAAcT,EAAM,KAAK,CAChF,GAEMe,IAAOP,QACXR,EAAM,OAAQA,EAAM,SAAS,WAAW,UAAU,WAAY,KAAA,CAChE;EAEA,SAAS3B,IAAQ;GAEf,AADA,EAAK,QAAQ,IACb+B,EAAK,OAAO;EACd;mBAIaF,EAAA,SAAX5B,EAAA,GAAAC,EAsBM,OAAA;;GAtBY,MAAMwC,EAAA;GAAM,OAAM;GAAkB,gBAAcd,EAAA;GAAU,aAAWA,EAAA;;GAC1EY,EAAA,SAAbvC,EAAA,GAAAE,EAAwEC,GAAxEC,EAAwE;;IAA7C,OAAM;GAAuB,GAAAmC,EAAA,KAAY,GAAA,MAAA,EAAA,KAAAQ,EAAA,IAAA,EAAA;GACpEzC,EAUM,OAVNY,GAUM;IATKzB,EAAAA,OAAO,SAASkC,EAAA,SAAzB3B,EAAA,GAAAC,EAEI,KAFJkB,GAEI,CADFZ,EAAqC0C,EAAA,QAAA,SAAA,CAAA,SAAA,CAAfzC,EAAAC,EAAAkB,EAAA,KAAK,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,KAAAoB,EAAA,IAAA,EAAA;IAElBtD,EAAAA,OAAO,WAAlBO,EAAA,GAAAC,EAEM,OAFNmB,GAEM,CADJb,EAAQ0C,EAAA,QAAA,SAAA,CAAA,CAAA,KAAAF,EAAA,IAAA,EAAA;IAECtD,EAAAA,OAAO,WAAlBO,EAAA,GAAAC,EAEM,OAFNoB,GAEM,CADJd,EAAuB0C,EAAA,QAAA,SAAA,CAAA,CAAA,KAAAF,EAAA,IAAA,EAAA;;GAInBpB,EAAA,YADR3B,EAAA,GAAAE,EAQcQ,GAAA;;IANZ,OAAM;IACL,OAAOuB,EAAA;IACR,MAAK;IACJ,SAAOlC;;IAER,SAAAY,QAA2B,CAA3BC,EAA2BT,GAAA,EAAnB,MAAMU,EAAAC,CAAA,EAAS,GAAA,MAAA,GAAA,CAAA,MAAA,CAAA,CAAA,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VAvatar.js","names":[],"sources":["../../../src/components/VAvatar/VAvatar.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Resolve image, icon and initials in priority order. JavaScript handles failed images, inert\n * links and merging private colour variables with consumer styles.\n */\n\nimport { computed, inject, onMounted, ref, useAttrs, useSlots, useTemplateRef, watch } from 'vue'\nimport type { StyleValue } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport type { IconSource } from '../VIcon/types'\nimport { AVATAR_DEFAULT_SIZE, avatarGroupKey } from './context'\n\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useInertLink } from '../../composables/useInertLink'\nimport { customColorStyle } from '../../utils/css'\nimport { isDev } from '../../utils/env'\n\n/** The diameter of the disc, from the control size scale. */\nexport type AvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'\n\ninterface AvatarProps {\n /**\n * The picture to show. It is what the avatar prefers above everything else, and an image\n * that fails to load hands over to the icon or the initials rather than leaving a gap.\n */\n src?: string\n /**\n * The icon to show when there is no picture. It comes before the initials, so an avatar\n * given both an icon and a name shows the icon.\n */\n icon?: IconSource\n /** The person's full name. */\n name?: string\n /**\n * The accessible name, when it should not simply be `name`: an avatar standing for a team\n * rather than a person, say. It wins over `name`, and a consumer `aria-label` wins over it.\n */\n alt?: string\n /**\n * A colour of your own, as a hex value, a CSS colour name or an `oklch()`. It REPLACES the\n * hue otherwise derived from `name`, and the text on it is always white, so a light colour\n * is the consumer's own risk.\n */\n color?: string\n /**\n * The diameter of the disc, from the size scale shared by every control. Leaving it out\n * inside a VAvatarGroup takes the group's size, which is the point of not defaulting it\n * here; on its own it is `md`.\n */\n size?: AvatarSize\n /** Takes 4px off the diameter, as it does on every other control. */\n compact?: boolean\n /**\n * Turns the avatar into an `<a>` pointing at this address. A disabled link becomes inert:\n * the address is dropped, so it can be neither focused nor followed.\n */\n href?: string\n /**\n * Turns the avatar into a `<button>`. It is ignored as soon as `href` makes it a link.\n * A VTooltip wrapping the avatar reaches this button through fallthrough.\n */\n clickable?: boolean\n /**\n * Makes an interactive avatar unusable: it stops responding, leaves the tab order and greys\n * out. It says nothing on a plain avatar, which was never interactive to begin with.\n */\n disabled?: boolean\n}\n\nconst props = withDefaults(defineProps<AvatarProps>(), {\n src: undefined,\n icon: undefined,\n name: undefined,\n alt: undefined,\n color: undefined,\n size: undefined,\n compact: false,\n href: undefined,\n clickable: false,\n disabled: false,\n})\n\ndefineSlots<{\n /** Fallback content (replaces the initials), e.g. VAvatarGroup's \"+X\". */\n default?(): unknown\n}>()\n\ndefineOptions({ inheritAttrs: false })\n\nconst attrs = useAttrs()\nconst group = inject(avatarGroupKey, null)\n\n// The size is the avatar's own answer first, then the group's; the density is cumulative,\n// the two terms written out in context.ts.\nconst resolvedSize = computed<AvatarSize>(() => props.size ?? group?.size ?? AVATAR_DEFAULT_SIZE)\nconst resolvedCompact = computed(() => props.compact || Boolean(group?.compact))\n\n// Fallthrough without `style`, which rootStyle merges with the component's own; the click\n// handler is also dropped on an inert link.\nconst {\n isLink,\n isInertLink,\n linkHref,\n attrs: passedAttrs,\n} = useInertLink({\n href: () => props.href,\n inert: () => props.disabled,\n attrs: () => Object.fromEntries(Object.entries(attrs).filter(([key]) => key !== 'style')),\n})\n\nconst isInteractive = computed(() => isLink.value || props.clickable)\nconst tag = computed(() => (isLink.value ? 'a' : props.clickable ? 'button' : 'span'))\n\n// @core\n// The image failed to load: the initials take over, so an avatar is never an empty box.\nconst failed = ref(false)\nwatch(\n () => props.src,\n () => {\n failed.value = false\n },\n)\nconst showImage = computed(() => Boolean(props.src) && !failed.value)\n\n/*\n * On a server-rendered page the browser may give up on the picture before hydration attaches\n * `@error`, and that event is never sent again: the disc would stay an empty circle. A picture\n * already settled with no pixels at mount is one that failed.\n */\nconst imageEl = useTemplateRef<HTMLImageElement>('image')\nonMounted(() => {\n const img = imageEl.value\n if (img?.complete && img.naturalWidth === 0) failed.value = true\n})\n\n// @a11y\n/*\n * The name bound on the root: a consumer `aria-labelledby` removes it, a consumer `aria-label`\n * replaces it, and otherwise it is `alt`, then `name`. A picture on show carries that name as\n * its own `alt`, so the root then names itself only with what the consumer wrote.\n */\nconst ariaLabel = useAriaLabel(() => (showImage.value ? undefined : (props.alt ?? props.name)))\nconst named = computed(() => ariaLabel.value !== undefined || attrs['aria-labelledby'] != null)\n\n// @core\nconst initials = computed(() => {\n if (!props.name) return ''\n /* Whole characters, not UTF-16 halves: `part[0]` of \"😀\" is a lone surrogate, drawn as a\n replacement box. And `toUpperCase` rather than its locale-aware sibling, whose answer\n depends on the runtime's locale, which the server and the browser need not share. */\n return props.name\n .split(/\\s+/)\n .filter(Boolean)\n .slice(0, 2)\n .map((part) => [...part][0]?.toUpperCase() ?? '')\n .join('')\n})\n\n// @core\n/*\n * Only the hue is inline (a unitless scalar); the CSS composes background/text with L/C fixed\n * per theme (light/dark adaptation without depending on contrast-color). A colour computed\n * outside the tokens, a deliberate exception.\n */\nconst hue = computed(() => {\n if (!props.name) return null\n let hash = 0\n for (let i = 0; i < props.name.length; i++) {\n hash = (hash * 31 + props.name.charCodeAt(i)) | 0\n }\n return Math.abs(hash) % 360\n})\nconst isAuto = computed(() => props.color === undefined && hue.value !== null)\n\n// @a11y\n// A static avatar with no picture is an image named by `alt`/ `name`. Anything else keeps the\n// role that arrived in the attributes; `link` on an inert link, a consumer's own otherwise.\nconst role = computed(() =>\n !isInteractive.value && !showImage.value && named.value\n ? 'img'\n : (passedAttrs.value.role as string | undefined),\n)\n\n// @devwarn\n// A button or a link named by nothing: no `name`, no `alt`, no `aria-*` and no slot text. A\n// picture alone does not count, its `alt` coming from the same two props.\nif (isDev) {\n const slots = useSlots()\n onMounted(() => {\n if (isInteractive.value && !named.value && !props.alt && !props.name && !slots.default) {\n console.warn(\n '[VAvatar] a clickable or linked avatar needs an accessible name: set `name`, `alt` or `aria-label`.',\n )\n }\n })\n}\n\nconst rootStyle = computed<StyleValue>(() => [\n customColorStyle(props.color) ??\n (isAuto.value ? { '--avatar-hue': String(hue.value) } : undefined),\n attrs.style as StyleValue,\n])\n</script>\n\n<template>\n <component\n :is=\"tag\"\n :aria-disabled=\"isInertLink ? 'true' : undefined\"\n v-bind=\"passedAttrs\"\n class=\"v-avatar v-control\"\n :style=\"rootStyle\"\n :data-size=\"resolvedSize\"\n :data-compact=\"resolvedCompact ? '' : undefined\"\n :data-custom=\"color !== undefined ? '' : undefined\"\n :data-auto=\"isAuto ? '' : undefined\"\n :href=\"linkHref\"\n :type=\"tag === 'button' ? 'button' : undefined\"\n :disabled=\"tag === 'button' ? disabled : undefined\"\n :role=\"role\"\n :aria-label=\"ariaLabel\"\n >\n <img\n v-if=\"showImage\"\n ref=\"image\"\n class=\"v-avatar-image\"\n :src=\"src\"\n :alt=\"alt ?? name ?? ''\"\n @error=\"failed = true\"\n />\n <VIcon v-else-if=\"icon\" v-bind=\"iconProps(icon)\" class=\"v-avatar-icon\" />\n <slot v-else>\n <span class=\"v-avatar-initials\" aria-hidden=\"true\">{{ initials }}</span>\n </slot>\n </component>\n</template>\n\n<style>\n@layer vectis.components {\n .v-avatar {\n --avatar-bg: var(--vectis-color-surface-muted);\n --avatar-text: var(--vectis-color-text-muted);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n inline-size: var(--control-height);\n block-size: var(--control-height);\n flex: none;\n overflow: hidden;\n padding: 0;\n border: none;\n background: var(--avatar-bg);\n color: var(--avatar-text);\n border-radius: var(--vectis-radius-pill);\n font-family: var(--vectis-text-family);\n font-size: var(--control-font-size);\n font-weight: var(--vectis-font-weight-semibold);\n line-height: var(--vectis-text-control-leading);\n text-decoration: none;\n user-select: none;\n /*\n * The `transparent` fallback is what lets a lone avatar render ringless, and it is also\n * what makes a divergence silent: rename it on one side and the discs in a group simply\n * stop being separated, with no error and nothing missing from the box.\n */\n box-shadow: 0 0 0 var(--vectis-control-size-avatar-ring) var(--avatar-ring-color, transparent);\n transition:\n background-color var(--vectis-duration-fast) var(--vectis-ease-default),\n box-shadow var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n\n /*\n * The lightness/chroma pairs are set on the THEME scopes and inherited, rather than written\n * in a `[data-theme='dark'] .v-avatar` rule: a descendant selector matches ANY dark ancestor,\n * so a light subtree nested in a dark page kept the dark discs. An inherited value is\n * resolved by the NEAREST scope, which is exactly how the semantic tokens behave.\n */\n :root,\n [data-theme='light'] {\n --avatar-auto-bg-lc: 0.9 0.06;\n --avatar-auto-text-lc: 0.42 0.13;\n }\n\n [data-theme='dark'] {\n --avatar-auto-bg-lc: 0.42 0.09;\n --avatar-auto-text-lc: 0.92 0.05;\n }\n\n .v-avatar[data-auto] {\n --avatar-bg: oklch(var(--avatar-auto-bg-lc) var(--avatar-hue));\n --avatar-text: oklch(var(--avatar-auto-text-lc) var(--avatar-hue));\n }\n\n /* Custom colour (--custom-color inline): wins, with a fixed white text (contrast\n is the consumer's responsibility). */\n .v-avatar[data-custom] {\n --avatar-bg: var(--custom-color);\n --avatar-text: var(--vectis-color-text-on-accent);\n }\n\n .v-avatar-image {\n inline-size: 100%;\n block-size: 100%;\n object-fit: cover;\n }\n\n .v-avatar-icon {\n --vectis-icon-size: calc(var(--control-height) * 0.55);\n }\n\n :is(a, button).v-avatar {\n cursor: pointer;\n }\n\n :is(a, button).v-avatar:hover:not([aria-disabled='true'], :disabled) {\n background: color-mix(in oklab, var(--avatar-bg), var(--vectis-color-text) 10%);\n }\n\n :is(a, button).v-avatar:focus-visible {\n outline: var(--vectis-focus-ring-width) solid var(--vectis-focus-ring-color);\n outline-offset: var(--vectis-focus-ring-offset);\n }\n\n .v-avatar:is(:disabled, [aria-disabled='true']) {\n cursor: not-allowed;\n background: var(--vectis-color-surface-muted);\n color: var(--vectis-color-text-subtle);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-avatar {\n transition: none;\n }\n }\n\n /* The outline gives each disc its circle back; the focus ring, at (0,2,0), still wins over it. */\n @media (forced-colors: active) {\n .v-avatar {\n outline: var(--vectis-control-border-width) solid CanvasText;\n outline-offset: calc(-1 * var(--vectis-control-border-width));\n }\n }\n}\n</style>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"VAvatar.js","names":["_sfc_main","VAvatar_vue_vue_type_script_setup_true_lang_default","VAvatar_default"],"sources":["../../../src/components/VAvatar/VAvatar.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Resolve image, icon and initials in priority order. JavaScript handles failed images, inert\n * links and merging private colour variables with consumer styles.\n */\n\nimport { computed, inject, onMounted, ref, useAttrs, useSlots, useTemplateRef, watch } from 'vue'\nimport type { StyleValue } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport type { IconSource } from '../VIcon/types'\nimport { AVATAR_DEFAULT_SIZE, avatarGroupKey } from './context'\n\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useInertLink } from '../../composables/useInertLink'\nimport { customColorStyle } from '../../utils/css'\nimport { isDev } from '../../utils/env'\n\n/** The diameter of the disc, from the control size scale. */\nexport type AvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'\n\ninterface AvatarProps {\n /**\n * The picture to show. It is what the avatar prefers above everything else, and an image\n * that fails to load hands over to the icon or the initials rather than leaving a gap.\n */\n src?: string\n /**\n * The icon to show when there is no picture. It comes before the initials, so an avatar\n * given both an icon and a name shows the icon.\n */\n icon?: IconSource\n /** The person's full name. */\n name?: string\n /**\n * The accessible name, when it should not simply be `name`: an avatar standing for a team\n * rather than a person, say. It wins over `name`, and a consumer `aria-label` wins over it.\n */\n alt?: string\n /**\n * A colour of your own, as a hex value, a CSS colour name or an `oklch()`. It REPLACES the\n * hue otherwise derived from `name`, and the text on it is always white, so a light colour\n * is the consumer's own risk.\n */\n color?: string\n /**\n * The diameter of the disc, from the size scale shared by every control. Leaving it out\n * inside a VAvatarGroup takes the group's size, which is the point of not defaulting it\n * here; on its own it is `md`.\n */\n size?: AvatarSize\n /** Takes 4px off the diameter, as it does on every other control. */\n compact?: boolean\n /**\n * Turns the avatar into an `<a>` pointing at this address. A disabled link becomes inert:\n * the address is dropped, so it can be neither focused nor followed.\n */\n href?: string\n /**\n * Turns the avatar into a `<button>`. It is ignored as soon as `href` makes it a link.\n * A VTooltip wrapping the avatar reaches this button through fallthrough.\n */\n clickable?: boolean\n /**\n * Makes an interactive avatar unusable: it stops responding, leaves the tab order and greys\n * out. It says nothing on a plain avatar, which was never interactive to begin with.\n */\n disabled?: boolean\n}\n\nconst props = withDefaults(defineProps<AvatarProps>(), {\n src: undefined,\n icon: undefined,\n name: undefined,\n alt: undefined,\n color: undefined,\n size: undefined,\n compact: false,\n href: undefined,\n clickable: false,\n disabled: false,\n})\n\ndefineSlots<{\n /** Fallback content (replaces the initials), e.g. VAvatarGroup's \"+X\". */\n default?(): unknown\n}>()\n\ndefineOptions({ inheritAttrs: false })\n\nconst attrs = useAttrs()\nconst group = inject(avatarGroupKey, null)\n\n// The size is the avatar's own answer first, then the group's; the density is cumulative,\n// the two terms written out in context.ts.\nconst resolvedSize = computed<AvatarSize>(() => props.size ?? group?.size ?? AVATAR_DEFAULT_SIZE)\nconst resolvedCompact = computed(() => props.compact || Boolean(group?.compact))\n\n// Fallthrough without `style`, which rootStyle merges with the component's own; the click\n// handler is also dropped on an inert link.\nconst {\n isLink,\n isInertLink,\n linkHref,\n attrs: passedAttrs,\n} = useInertLink({\n href: () => props.href,\n inert: () => props.disabled,\n attrs: () => Object.fromEntries(Object.entries(attrs).filter(([key]) => key !== 'style')),\n})\n\nconst isInteractive = computed(() => isLink.value || props.clickable)\nconst tag = computed(() => (isLink.value ? 'a' : props.clickable ? 'button' : 'span'))\n\n// @core\n// The image failed to load: the initials take over, so an avatar is never an empty box.\nconst failed = ref(false)\nwatch(\n () => props.src,\n () => {\n failed.value = false\n },\n)\nconst showImage = computed(() => Boolean(props.src) && !failed.value)\n\n/*\n * On a server-rendered page the browser may give up on the picture before hydration attaches\n * `@error`, and that event is never sent again: the disc would stay an empty circle. A picture\n * already settled with no pixels at mount is one that failed.\n */\nconst imageEl = useTemplateRef<HTMLImageElement>('image')\nonMounted(() => {\n const img = imageEl.value\n if (img?.complete && img.naturalWidth === 0) failed.value = true\n})\n\n// @a11y\n/*\n * The name bound on the root: a consumer `aria-labelledby` removes it, a consumer `aria-label`\n * replaces it, and otherwise it is `alt`, then `name`. A picture on show carries that name as\n * its own `alt`, so the root then names itself only with what the consumer wrote.\n */\nconst ariaLabel = useAriaLabel(() => (showImage.value ? undefined : (props.alt ?? props.name)))\nconst named = computed(() => ariaLabel.value !== undefined || attrs['aria-labelledby'] != null)\n\n// @core\nconst initials = computed(() => {\n if (!props.name) return ''\n /* Whole characters, not UTF-16 halves: `part[0]` of \"😀\" is a lone surrogate, drawn as a\n replacement box. And `toUpperCase` rather than its locale-aware sibling, whose answer\n depends on the runtime's locale, which the server and the browser need not share. */\n return props.name\n .split(/\\s+/)\n .filter(Boolean)\n .slice(0, 2)\n .map((part) => [...part][0]?.toUpperCase() ?? '')\n .join('')\n})\n\n// @core\n/*\n * Only the hue is inline (a unitless scalar); the CSS composes background/text with L/C fixed\n * per theme (light/dark adaptation without depending on contrast-color). A colour computed\n * outside the tokens, a deliberate exception.\n */\nconst hue = computed(() => {\n if (!props.name) return null\n let hash = 0\n for (let i = 0; i < props.name.length; i++) {\n hash = (hash * 31 + props.name.charCodeAt(i)) | 0\n }\n return Math.abs(hash) % 360\n})\nconst isAuto = computed(() => props.color === undefined && hue.value !== null)\n\n// @a11y\n// A static avatar with no picture is an image named by `alt`/ `name`. Anything else keeps the\n// role that arrived in the attributes; `link` on an inert link, a consumer's own otherwise.\nconst role = computed(() =>\n !isInteractive.value && !showImage.value && named.value\n ? 'img'\n : (passedAttrs.value.role as string | undefined),\n)\n\n// @devwarn\n// A button or a link named by nothing: no `name`, no `alt`, no `aria-*` and no slot text. A\n// picture alone does not count, its `alt` coming from the same two props.\nif (isDev) {\n const slots = useSlots()\n onMounted(() => {\n if (isInteractive.value && !named.value && !props.alt && !props.name && !slots.default) {\n console.warn(\n '[VAvatar] a clickable or linked avatar needs an accessible name: set `name`, `alt` or `aria-label`.',\n )\n }\n })\n}\n\nconst rootStyle = computed<StyleValue>(() => [\n customColorStyle(props.color) ??\n (isAuto.value ? { '--avatar-hue': String(hue.value) } : undefined),\n attrs.style as StyleValue,\n])\n</script>\n\n<template>\n <component\n :is=\"tag\"\n :aria-disabled=\"isInertLink ? 'true' : undefined\"\n v-bind=\"passedAttrs\"\n class=\"v-avatar v-control\"\n :style=\"rootStyle\"\n :data-size=\"resolvedSize\"\n :data-compact=\"resolvedCompact ? '' : undefined\"\n :data-custom=\"color !== undefined ? '' : undefined\"\n :data-auto=\"isAuto ? '' : undefined\"\n :href=\"linkHref\"\n :type=\"tag === 'button' ? 'button' : undefined\"\n :disabled=\"tag === 'button' ? disabled : undefined\"\n :role=\"role\"\n :aria-label=\"ariaLabel\"\n >\n <img\n v-if=\"showImage\"\n ref=\"image\"\n class=\"v-avatar-image\"\n :src=\"src\"\n :alt=\"alt ?? name ?? ''\"\n @error=\"failed = true\"\n />\n <VIcon v-else-if=\"icon\" v-bind=\"iconProps(icon)\" class=\"v-avatar-icon\" />\n <slot v-else>\n <span class=\"v-avatar-initials\" aria-hidden=\"true\">{{ initials }}</span>\n </slot>\n </component>\n</template>\n\n<style>\n@layer vectis.components {\n .v-avatar {\n --avatar-bg: var(--vectis-color-surface-muted);\n --avatar-text: var(--vectis-color-text-muted);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n inline-size: var(--control-height);\n block-size: var(--control-height);\n flex: none;\n overflow: hidden;\n padding: 0;\n border: none;\n background: var(--avatar-bg);\n color: var(--avatar-text);\n border-radius: var(--vectis-radius-pill);\n font-family: var(--vectis-text-family);\n font-size: var(--control-font-size);\n font-weight: var(--vectis-font-weight-semibold);\n line-height: var(--vectis-text-control-leading);\n text-decoration: none;\n user-select: none;\n /*\n * The `transparent` fallback is what lets a lone avatar render ringless, and it is also\n * what makes a divergence silent: rename it on one side and the discs in a group simply\n * stop being separated, with no error and nothing missing from the box.\n */\n box-shadow: 0 0 0 var(--vectis-control-size-avatar-ring) var(--avatar-ring-color, transparent);\n transition:\n background-color var(--vectis-duration-fast) var(--vectis-ease-default),\n box-shadow var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n\n /*\n * The lightness/chroma pairs are set on the THEME scopes and inherited, rather than written\n * in a `[data-theme='dark'] .v-avatar` rule: a descendant selector matches ANY dark ancestor,\n * so a light subtree nested in a dark page kept the dark discs. An inherited value is\n * resolved by the NEAREST scope, which is exactly how the semantic tokens behave.\n */\n :root,\n [data-theme='light'] {\n --avatar-auto-bg-lc: 0.9 0.06;\n --avatar-auto-text-lc: 0.42 0.13;\n }\n\n [data-theme='dark'] {\n --avatar-auto-bg-lc: 0.42 0.09;\n --avatar-auto-text-lc: 0.92 0.05;\n }\n\n .v-avatar[data-auto] {\n --avatar-bg: oklch(var(--avatar-auto-bg-lc) var(--avatar-hue));\n --avatar-text: oklch(var(--avatar-auto-text-lc) var(--avatar-hue));\n }\n\n /* Custom colour (--custom-color inline): wins, with a fixed white text (contrast\n is the consumer's responsibility). */\n .v-avatar[data-custom] {\n --avatar-bg: var(--custom-color);\n --avatar-text: var(--vectis-color-text-on-accent);\n }\n\n .v-avatar-image {\n inline-size: 100%;\n block-size: 100%;\n object-fit: cover;\n }\n\n .v-avatar-icon {\n --vectis-icon-size: calc(var(--control-height) * 0.55);\n }\n\n :is(a, button).v-avatar {\n cursor: pointer;\n }\n\n :is(a, button).v-avatar:hover:not([aria-disabled='true'], :disabled) {\n background: color-mix(in oklab, var(--avatar-bg), var(--vectis-color-text) 10%);\n }\n\n :is(a, button).v-avatar:focus-visible {\n outline: var(--vectis-focus-ring-width) solid var(--vectis-focus-ring-color);\n outline-offset: var(--vectis-focus-ring-offset);\n }\n\n .v-avatar:is(:disabled, [aria-disabled='true']) {\n cursor: not-allowed;\n background: var(--vectis-color-surface-muted);\n color: var(--vectis-color-text-subtle);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-avatar {\n transition: none;\n }\n }\n\n /* The outline gives each disc its circle back; the focus ring, at (0,2,0), still wins over it. */\n @media (forced-colors: active) {\n .v-avatar {\n outline: var(--vectis-control-border-width) solid CanvasText;\n outline-offset: calc(-1 * var(--vectis-control-border-width));\n }\n }\n}\n</style>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VAvatar.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/VAvatar/VAvatar.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Resolve image, icon and initials in priority order. JavaScript handles failed images, inert\n * links and merging private colour variables with consumer styles.\n */\n\nimport { computed, inject, onMounted, ref, useAttrs, useSlots, useTemplateRef, watch } from 'vue'\nimport type { StyleValue } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport type { IconSource } from '../VIcon/types'\nimport { AVATAR_DEFAULT_SIZE, avatarGroupKey } from './context'\n\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useInertLink } from '../../composables/useInertLink'\nimport { customColorStyle } from '../../utils/css'\nimport { isDev } from '../../utils/env'\n\n/** The diameter of the disc, from the control size scale. */\nexport type AvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'\n\ninterface AvatarProps {\n /**\n * The picture to show. It is what the avatar prefers above everything else, and an image\n * that fails to load hands over to the icon or the initials rather than leaving a gap.\n */\n src?: string\n /**\n * The icon to show when there is no picture. It comes before the initials, so an avatar\n * given both an icon and a name shows the icon.\n */\n icon?: IconSource\n /** The person's full name. */\n name?: string\n /**\n * The accessible name, when it should not simply be `name`: an avatar standing for a team\n * rather than a person, say. It wins over `name`, and a consumer `aria-label` wins over it.\n */\n alt?: string\n /**\n * A colour of your own, as a hex value, a CSS colour name or an `oklch()`. It REPLACES the\n * hue otherwise derived from `name`, and the text on it is always white, so a light colour\n * is the consumer's own risk.\n */\n color?: string\n /**\n * The diameter of the disc, from the size scale shared by every control. Leaving it out\n * inside a VAvatarGroup takes the group's size, which is the point of not defaulting it\n * here; on its own it is `md`.\n */\n size?: AvatarSize\n /** Takes 4px off the diameter, as it does on every other control. */\n compact?: boolean\n /**\n * Turns the avatar into an `<a>` pointing at this address. A disabled link becomes inert:\n * the address is dropped, so it can be neither focused nor followed.\n */\n href?: string\n /**\n * Turns the avatar into a `<button>`. It is ignored as soon as `href` makes it a link.\n * A VTooltip wrapping the avatar reaches this button through fallthrough.\n */\n clickable?: boolean\n /**\n * Makes an interactive avatar unusable: it stops responding, leaves the tab order and greys\n * out. It says nothing on a plain avatar, which was never interactive to begin with.\n */\n disabled?: boolean\n}\n\nconst props = withDefaults(defineProps<AvatarProps>(), {\n src: undefined,\n icon: undefined,\n name: undefined,\n alt: undefined,\n color: undefined,\n size: undefined,\n compact: false,\n href: undefined,\n clickable: false,\n disabled: false,\n})\n\ndefineSlots<{\n /** Fallback content (replaces the initials), e.g. VAvatarGroup's \"+X\". */\n default?(): unknown\n}>()\n\ndefineOptions({ inheritAttrs: false })\n\nconst attrs = useAttrs()\nconst group = inject(avatarGroupKey, null)\n\n// The size is the avatar's own answer first, then the group's; the density is cumulative,\n// the two terms written out in context.ts.\nconst resolvedSize = computed<AvatarSize>(() => props.size ?? group?.size ?? AVATAR_DEFAULT_SIZE)\nconst resolvedCompact = computed(() => props.compact || Boolean(group?.compact))\n\n// Fallthrough without `style`, which rootStyle merges with the component's own; the click\n// handler is also dropped on an inert link.\nconst {\n isLink,\n isInertLink,\n linkHref,\n attrs: passedAttrs,\n} = useInertLink({\n href: () => props.href,\n inert: () => props.disabled,\n attrs: () => Object.fromEntries(Object.entries(attrs).filter(([key]) => key !== 'style')),\n})\n\nconst isInteractive = computed(() => isLink.value || props.clickable)\nconst tag = computed(() => (isLink.value ? 'a' : props.clickable ? 'button' : 'span'))\n\n// @core\n// The image failed to load: the initials take over, so an avatar is never an empty box.\nconst failed = ref(false)\nwatch(\n () => props.src,\n () => {\n failed.value = false\n },\n)\nconst showImage = computed(() => Boolean(props.src) && !failed.value)\n\n/*\n * On a server-rendered page the browser may give up on the picture before hydration attaches\n * `@error`, and that event is never sent again: the disc would stay an empty circle. A picture\n * already settled with no pixels at mount is one that failed.\n */\nconst imageEl = useTemplateRef<HTMLImageElement>('image')\nonMounted(() => {\n const img = imageEl.value\n if (img?.complete && img.naturalWidth === 0) failed.value = true\n})\n\n// @a11y\n/*\n * The name bound on the root: a consumer `aria-labelledby` removes it, a consumer `aria-label`\n * replaces it, and otherwise it is `alt`, then `name`. A picture on show carries that name as\n * its own `alt`, so the root then names itself only with what the consumer wrote.\n */\nconst ariaLabel = useAriaLabel(() => (showImage.value ? undefined : (props.alt ?? props.name)))\nconst named = computed(() => ariaLabel.value !== undefined || attrs['aria-labelledby'] != null)\n\n// @core\nconst initials = computed(() => {\n if (!props.name) return ''\n /* Whole characters, not UTF-16 halves: `part[0]` of \"😀\" is a lone surrogate, drawn as a\n replacement box. And `toUpperCase` rather than its locale-aware sibling, whose answer\n depends on the runtime's locale, which the server and the browser need not share. */\n return props.name\n .split(/\\s+/)\n .filter(Boolean)\n .slice(0, 2)\n .map((part) => [...part][0]?.toUpperCase() ?? '')\n .join('')\n})\n\n// @core\n/*\n * Only the hue is inline (a unitless scalar); the CSS composes background/text with L/C fixed\n * per theme (light/dark adaptation without depending on contrast-color). A colour computed\n * outside the tokens, a deliberate exception.\n */\nconst hue = computed(() => {\n if (!props.name) return null\n let hash = 0\n for (let i = 0; i < props.name.length; i++) {\n hash = (hash * 31 + props.name.charCodeAt(i)) | 0\n }\n return Math.abs(hash) % 360\n})\nconst isAuto = computed(() => props.color === undefined && hue.value !== null)\n\n// @a11y\n// A static avatar with no picture is an image named by `alt`/ `name`. Anything else keeps the\n// role that arrived in the attributes; `link` on an inert link, a consumer's own otherwise.\nconst role = computed(() =>\n !isInteractive.value && !showImage.value && named.value\n ? 'img'\n : (passedAttrs.value.role as string | undefined),\n)\n\n// @devwarn\n// A button or a link named by nothing: no `name`, no `alt`, no `aria-*` and no slot text. A\n// picture alone does not count, its `alt` coming from the same two props.\nif (isDev) {\n const slots = useSlots()\n onMounted(() => {\n if (isInteractive.value && !named.value && !props.alt && !props.name && !slots.default) {\n console.warn(\n '[VAvatar] a clickable or linked avatar needs an accessible name: set `name`, `alt` or `aria-label`.',\n )\n }\n })\n}\n\nconst rootStyle = computed<StyleValue>(() => [\n customColorStyle(props.color) ??\n (isAuto.value ? { '--avatar-hue': String(hue.value) } : undefined),\n attrs.style as StyleValue,\n])\n</script>\n\n<template>\n <component\n :is=\"tag\"\n :aria-disabled=\"isInertLink ? 'true' : undefined\"\n v-bind=\"passedAttrs\"\n class=\"v-avatar v-control\"\n :style=\"rootStyle\"\n :data-size=\"resolvedSize\"\n :data-compact=\"resolvedCompact ? '' : undefined\"\n :data-custom=\"color !== undefined ? '' : undefined\"\n :data-auto=\"isAuto ? '' : undefined\"\n :href=\"linkHref\"\n :type=\"tag === 'button' ? 'button' : undefined\"\n :disabled=\"tag === 'button' ? disabled : undefined\"\n :role=\"role\"\n :aria-label=\"ariaLabel\"\n >\n <img\n v-if=\"showImage\"\n ref=\"image\"\n class=\"v-avatar-image\"\n :src=\"src\"\n :alt=\"alt ?? name ?? ''\"\n @error=\"failed = true\"\n />\n <VIcon v-else-if=\"icon\" v-bind=\"iconProps(icon)\" class=\"v-avatar-icon\" />\n <slot v-else>\n <span class=\"v-avatar-initials\" aria-hidden=\"true\">{{ initials }}</span>\n </slot>\n </component>\n</template>\n\n<style>\n@layer vectis.components {\n .v-avatar {\n --avatar-bg: var(--vectis-color-surface-muted);\n --avatar-text: var(--vectis-color-text-muted);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n inline-size: var(--control-height);\n block-size: var(--control-height);\n flex: none;\n overflow: hidden;\n padding: 0;\n border: none;\n background: var(--avatar-bg);\n color: var(--avatar-text);\n border-radius: var(--vectis-radius-pill);\n font-family: var(--vectis-text-family);\n font-size: var(--control-font-size);\n font-weight: var(--vectis-font-weight-semibold);\n line-height: var(--vectis-text-control-leading);\n text-decoration: none;\n user-select: none;\n /*\n * The `transparent` fallback is what lets a lone avatar render ringless, and it is also\n * what makes a divergence silent: rename it on one side and the discs in a group simply\n * stop being separated, with no error and nothing missing from the box.\n */\n box-shadow: 0 0 0 var(--vectis-control-size-avatar-ring) var(--avatar-ring-color, transparent);\n transition:\n background-color var(--vectis-duration-fast) var(--vectis-ease-default),\n box-shadow var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n\n /*\n * The lightness/chroma pairs are set on the THEME scopes and inherited, rather than written\n * in a `[data-theme='dark'] .v-avatar` rule: a descendant selector matches ANY dark ancestor,\n * so a light subtree nested in a dark page kept the dark discs. An inherited value is\n * resolved by the NEAREST scope, which is exactly how the semantic tokens behave.\n */\n :root,\n [data-theme='light'] {\n --avatar-auto-bg-lc: 0.9 0.06;\n --avatar-auto-text-lc: 0.42 0.13;\n }\n\n [data-theme='dark'] {\n --avatar-auto-bg-lc: 0.42 0.09;\n --avatar-auto-text-lc: 0.92 0.05;\n }\n\n .v-avatar[data-auto] {\n --avatar-bg: oklch(var(--avatar-auto-bg-lc) var(--avatar-hue));\n --avatar-text: oklch(var(--avatar-auto-text-lc) var(--avatar-hue));\n }\n\n /* Custom colour (--custom-color inline): wins, with a fixed white text (contrast\n is the consumer's responsibility). */\n .v-avatar[data-custom] {\n --avatar-bg: var(--custom-color);\n --avatar-text: var(--vectis-color-text-on-accent);\n }\n\n .v-avatar-image {\n inline-size: 100%;\n block-size: 100%;\n object-fit: cover;\n }\n\n .v-avatar-icon {\n --vectis-icon-size: calc(var(--control-height) * 0.55);\n }\n\n :is(a, button).v-avatar {\n cursor: pointer;\n }\n\n :is(a, button).v-avatar:hover:not([aria-disabled='true'], :disabled) {\n background: color-mix(in oklab, var(--avatar-bg), var(--vectis-color-text) 10%);\n }\n\n :is(a, button).v-avatar:focus-visible {\n outline: var(--vectis-focus-ring-width) solid var(--vectis-focus-ring-color);\n outline-offset: var(--vectis-focus-ring-offset);\n }\n\n .v-avatar:is(:disabled, [aria-disabled='true']) {\n cursor: not-allowed;\n background: var(--vectis-color-surface-muted);\n color: var(--vectis-color-text-subtle);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-avatar {\n transition: none;\n }\n }\n\n /* The outline gives each disc its circle back; the focus ring, at (0,2,0), still wins over it. */\n @media (forced-colors: active) {\n .v-avatar {\n outline: var(--vectis-control-border-width) solid CanvasText;\n outline-offset: calc(-1 * var(--vectis-control-border-width));\n }\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuEA,IAAM,IAAQ,GAoBR,IAAQ,EAAS,GACjB,IAAQ,EAAO,GAAgB,IAAI,GAInC,IAAe,QAA2B,EAAM,QAAQ,GAAO,QAAA,IAA2B,GAC1F,IAAkB,QAAe,EAAM,WAAW,EAAQ,GAAO,OAAQ,GAIzE,EACJ,WACA,gBACA,aACA,OAAO,MACL,EAAa;GACf,YAAY,EAAM;GAClB,aAAa,EAAM;GACnB,aAAa,OAAO,YAAY,OAAO,QAAQ,CAAK,CAAC,CAAC,QAAQ,CAAC,OAAS,MAAQ,OAAO,CAAC;EAC1F,CAAC,GAEK,IAAgB,QAAe,EAAO,SAAS,EAAM,SAAS,GAC9D,IAAM,QAAgB,EAAO,QAAQ,MAAM,EAAM,YAAY,WAAW,MAAO,GAI/E,IAAS,EAAI,EAAK;EACxB,QACQ,EAAM,WACN;GACJ,EAAO,QAAQ;EACjB,CACF;EACA,IAAM,IAAY,QAAe,EAAQ,EAAM,OAAQ,CAAC,EAAO,KAAK,GAO9D,IAAU,EAAiC,OAAO;EACxD,QAAgB;GACd,IAAM,IAAM,EAAQ;GACpB,AAAI,GAAK,YAAY,EAAI,iBAAiB,MAAG,EAAO,QAAQ;EAC9D,CAAC;EAQD,IAAM,IAAY,QAAoB,EAAU,QAAQ,KAAA,IAAa,EAAM,OAAO,EAAM,IAAM,GACxF,IAAQ,QAAe,EAAU,UAAU,KAAA,KAAa,EAAM,sBAAsB,IAAI,GAGxF,IAAW,QACV,EAAM,OAIJ,EAAM,KACV,MAAM,KAAK,CAAA,CACX,OAAO,OAAO,CAAA,CACd,MAAM,GAAG,CAAC,CAAA,CACV,KAAK,MAAS,CAAC,GAAG,CAAI,CAAC,CAAC,EAAE,EAAE,YAAY,KAAK,EAAE,CAAA,CAC/C,KAAK,EAAE,IATc,EAUzB,GAQK,IAAM,QAAe;GACzB,IAAI,CAAC,EAAM,MAAM,OAAO;GACxB,IAAI,IAAO;GACX,KAAK,IAAI,IAAI,GAAG,IAAI,EAAM,KAAK,QAAQ,KACrC,IAAQ,IAAO,KAAK,EAAM,KAAK,WAAW,CAAC,IAAK;GAElD,OAAO,KAAK,IAAI,CAAI,IAAI;EAC1B,CAAC,GACK,IAAS,QAAe,EAAM,UAAU,KAAA,KAAa,EAAI,UAAU,IAAI,GAKvE,IAAO,QACX,CAAC,EAAc,SAAS,CAAC,EAAU,SAAS,EAAM,QAC9C,QACC,EAAY,MAAM,IACzB;EAKA,IAAI,GAAO;GACT,IAAM,IAAQ,EAAS;GACvB,QAAgB;IACd,AAAI,EAAc,SAAS,CAAC,EAAM,SAAS,CAAC,EAAM,OAAO,CAAC,EAAM,QAAQ,CAAC,EAAM,WAC7E,QAAQ,KACN,qGACF;GAEJ,CAAC;EACH;EAEA,IAAM,IAAY,QAA2B,CAC3C,EAAiB,EAAM,KAAK,MACzB,EAAO,QAAQ,EAAE,gBAAgB,OAAO,EAAI,KAAK,EAAE,IAAI,KAAA,IAC1D,EAAM,KACR,CAAC;yBAIC,EA4BY,EA3BL,EAAA,KAAG,GADV,EA4BY,EA1BT,iBAAe,EAAA,CAAA,IAAW,SAAY,KAAA,EAAA,GAC/B,EAAA,CAAA,GAAW;GACnB,OAAM;GACL,OAAO,EAAA;GACP,aAAW,EAAA;GACX,gBAAc,EAAA,QAAe,KAAQ,KAAA;GACrC,eAAa,EAAA,UAAU,KAAA,IAAiB,KAAA,IAAR;GAChC,aAAW,EAAA,QAAM,KAAQ,KAAA;GACzB,MAAM,EAAA,CAAA;GACN,MAAM,EAAA,UAAG,WAAA,WAA2B,KAAA;GACpC,UAAU,EAAA,UAAG,WAAgB,EAAA,WAAW,KAAA;GACxC,MAAM,EAAA;GACN,cAAY,EAAA,CAAA;;oBASX,CANM,EAAA,SAAA,EAAA,GADR,EAOE,OAAA;;IALA,KAAI;IACJ,OAAM;IACL,KAAK,EAAA;IACL,KAAK,EAAA,OAAO,EAAA,QAAI;IAChB,SAAK,AAAA,EAAA,QAAA,MAAE,EAAA,QAAM;sBAEE,EAAA,QAAA,EAAA,GAAlB,EAAyE,GAAzE,EAAyE,EAAA,KAAA,EAAA,GAAzC,EAAA,CAAA,CAAS,CAAC,EAAA,IAAI,GAAA,EAAG,OAAM,gBAAe,CAAA,GAAA,MAAA,EAAA,KACtE,EAEO,EAAA,QAAA,WAAA,CAAA,SAAA,CADL,EAAwE,QAAxE,GAAwE,EAAlB,EAAA,KAAQ,GAAA,CAAA,CAAA,GAAA,KAAA,GAAA,CAAA,CAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"VAvatar.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","_resolveDynamicComponent","_mergeProps","_unref","_withCtx","_createElementBlock","VIcon","_renderSlot","_createElementVNode","_toDisplayString","VIcon_default","_hoisted_1","_hoisted_2","VAvatar_vue_vue_type_script_setup_true_lang_default","props","__props","attrs","useAttrs","group","inject","avatarGroupKey","resolvedSize","computed","resolvedCompact","passedAttrs","useInertLink","key","isInteractive","isLink","tag","failed","ref","showImage","imageEl","useTemplateRef","img","ariaLabel","useAriaLabel","named","initials","part","hue","hash","i","isAuto","role","isDev","slots","useSlots","rootStyle","customColorStyle","openBlock","createBlock","resolveDynamicComponent","mergeProps","unref","isInertLink","linkHref","withCtx","createElementBlock","_cache","iconProps","renderSlot","_ctx","createElementVNode","toDisplayString"],"sources":["../../../src/components/VAvatar/VAvatar.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Resolve image, icon and initials in priority order. JavaScript handles failed images, inert\n * links and merging private colour variables with consumer styles.\n */\n\nimport { computed, inject, onMounted, ref, useAttrs, useSlots, useTemplateRef, watch } from 'vue'\nimport type { StyleValue } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport type { IconSource } from '../VIcon/types'\nimport { AVATAR_DEFAULT_SIZE, avatarGroupKey } from './context'\n\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useInertLink } from '../../composables/useInertLink'\nimport { customColorStyle } from '../../utils/css'\nimport { isDev } from '../../utils/env'\n\n/** The diameter of the disc, from the control size scale. */\nexport type AvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'\n\ninterface AvatarProps {\n /**\n * The picture to show. It is what the avatar prefers above everything else, and an image\n * that fails to load hands over to the icon or the initials rather than leaving a gap.\n */\n src?: string\n /**\n * The icon to show when there is no picture. It comes before the initials, so an avatar\n * given both an icon and a name shows the icon.\n */\n icon?: IconSource\n /** The person's full name. */\n name?: string\n /**\n * The accessible name, when it should not simply be `name`: an avatar standing for a team\n * rather than a person, say. It wins over `name`, and a consumer `aria-label` wins over it.\n */\n alt?: string\n /**\n * A colour of your own, as a hex value, a CSS colour name or an `oklch()`. It REPLACES the\n * hue otherwise derived from `name`, and the text on it is always white, so a light colour\n * is the consumer's own risk.\n */\n color?: string\n /**\n * The diameter of the disc, from the size scale shared by every control. Leaving it out\n * inside a VAvatarGroup takes the group's size, which is the point of not defaulting it\n * here; on its own it is `md`.\n */\n size?: AvatarSize\n /** Takes 4px off the diameter, as it does on every other control. */\n compact?: boolean\n /**\n * Turns the avatar into an `<a>` pointing at this address. A disabled link becomes inert:\n * the address is dropped, so it can be neither focused nor followed.\n */\n href?: string\n /**\n * Turns the avatar into a `<button>`. It is ignored as soon as `href` makes it a link.\n * A VTooltip wrapping the avatar reaches this button through fallthrough.\n */\n clickable?: boolean\n /**\n * Makes an interactive avatar unusable: it stops responding, leaves the tab order and greys\n * out. It says nothing on a plain avatar, which was never interactive to begin with.\n */\n disabled?: boolean\n}\n\nconst props = withDefaults(defineProps<AvatarProps>(), {\n src: undefined,\n icon: undefined,\n name: undefined,\n alt: undefined,\n color: undefined,\n size: undefined,\n compact: false,\n href: undefined,\n clickable: false,\n disabled: false,\n})\n\ndefineSlots<{\n /** Fallback content (replaces the initials), e.g. VAvatarGroup's \"+X\". */\n default?(): unknown\n}>()\n\ndefineOptions({ inheritAttrs: false })\n\nconst attrs = useAttrs()\nconst group = inject(avatarGroupKey, null)\n\n// The size is the avatar's own answer first, then the group's; the density is cumulative,\n// the two terms written out in context.ts.\nconst resolvedSize = computed<AvatarSize>(() => props.size ?? group?.size ?? AVATAR_DEFAULT_SIZE)\nconst resolvedCompact = computed(() => props.compact || Boolean(group?.compact))\n\n// Fallthrough without `style`, which rootStyle merges with the component's own; the click\n// handler is also dropped on an inert link.\nconst {\n isLink,\n isInertLink,\n linkHref,\n attrs: passedAttrs,\n} = useInertLink({\n href: () => props.href,\n inert: () => props.disabled,\n attrs: () => Object.fromEntries(Object.entries(attrs).filter(([key]) => key !== 'style')),\n})\n\nconst isInteractive = computed(() => isLink.value || props.clickable)\nconst tag = computed(() => (isLink.value ? 'a' : props.clickable ? 'button' : 'span'))\n\n// @core\n// The image failed to load: the initials take over, so an avatar is never an empty box.\nconst failed = ref(false)\nwatch(\n () => props.src,\n () => {\n failed.value = false\n },\n)\nconst showImage = computed(() => Boolean(props.src) && !failed.value)\n\n/*\n * On a server-rendered page the browser may give up on the picture before hydration attaches\n * `@error`, and that event is never sent again: the disc would stay an empty circle. A picture\n * already settled with no pixels at mount is one that failed.\n */\nconst imageEl = useTemplateRef<HTMLImageElement>('image')\nonMounted(() => {\n const img = imageEl.value\n if (img?.complete && img.naturalWidth === 0) failed.value = true\n})\n\n// @a11y\n/*\n * The name bound on the root: a consumer `aria-labelledby` removes it, a consumer `aria-label`\n * replaces it, and otherwise it is `alt`, then `name`. A picture on show carries that name as\n * its own `alt`, so the root then names itself only with what the consumer wrote.\n */\nconst ariaLabel = useAriaLabel(() => (showImage.value ? undefined : (props.alt ?? props.name)))\nconst named = computed(() => ariaLabel.value !== undefined || attrs['aria-labelledby'] != null)\n\n// @core\nconst initials = computed(() => {\n if (!props.name) return ''\n /* Whole characters, not UTF-16 halves: `part[0]` of \"😀\" is a lone surrogate, drawn as a\n replacement box. And `toUpperCase` rather than its locale-aware sibling, whose answer\n depends on the runtime's locale, which the server and the browser need not share. */\n return props.name\n .split(/\\s+/)\n .filter(Boolean)\n .slice(0, 2)\n .map((part) => [...part][0]?.toUpperCase() ?? '')\n .join('')\n})\n\n// @core\n/*\n * Only the hue is inline (a unitless scalar); the CSS composes background/text with L/C fixed\n * per theme (light/dark adaptation without depending on contrast-color). A colour computed\n * outside the tokens, a deliberate exception.\n */\nconst hue = computed(() => {\n if (!props.name) return null\n let hash = 0\n for (let i = 0; i < props.name.length; i++) {\n hash = (hash * 31 + props.name.charCodeAt(i)) | 0\n }\n return Math.abs(hash) % 360\n})\nconst isAuto = computed(() => props.color === undefined && hue.value !== null)\n\n// @a11y\n// A static avatar with no picture is an image named by `alt`/ `name`. Anything else keeps the\n// role that arrived in the attributes; `link` on an inert link, a consumer's own otherwise.\nconst role = computed(() =>\n !isInteractive.value && !showImage.value && named.value\n ? 'img'\n : (passedAttrs.value.role as string | undefined),\n)\n\n// @devwarn\n// A button or a link named by nothing: no `name`, no `alt`, no `aria-*` and no slot text. A\n// picture alone does not count, its `alt` coming from the same two props.\nif (isDev) {\n const slots = useSlots()\n onMounted(() => {\n if (isInteractive.value && !named.value && !props.alt && !props.name && !slots.default) {\n console.warn(\n '[VAvatar] a clickable or linked avatar needs an accessible name: set `name`, `alt` or `aria-label`.',\n )\n }\n })\n}\n\nconst rootStyle = computed<StyleValue>(() => [\n customColorStyle(props.color) ??\n (isAuto.value ? { '--avatar-hue': String(hue.value) } : undefined),\n attrs.style as StyleValue,\n])\n</script>\n\n<template>\n <component\n :is=\"tag\"\n :aria-disabled=\"isInertLink ? 'true' : undefined\"\n v-bind=\"passedAttrs\"\n class=\"v-avatar v-control\"\n :style=\"rootStyle\"\n :data-size=\"resolvedSize\"\n :data-compact=\"resolvedCompact ? '' : undefined\"\n :data-custom=\"color !== undefined ? '' : undefined\"\n :data-auto=\"isAuto ? '' : undefined\"\n :href=\"linkHref\"\n :type=\"tag === 'button' ? 'button' : undefined\"\n :disabled=\"tag === 'button' ? disabled : undefined\"\n :role=\"role\"\n :aria-label=\"ariaLabel\"\n >\n <img\n v-if=\"showImage\"\n ref=\"image\"\n class=\"v-avatar-image\"\n :src=\"src\"\n :alt=\"alt ?? name ?? ''\"\n @error=\"failed = true\"\n />\n <VIcon v-else-if=\"icon\" v-bind=\"iconProps(icon)\" class=\"v-avatar-icon\" />\n <slot v-else>\n <span class=\"v-avatar-initials\" aria-hidden=\"true\">{{ initials }}</span>\n </slot>\n </component>\n</template>\n\n<style>\n@layer vectis.components {\n .v-avatar {\n --avatar-bg: var(--vectis-color-surface-muted);\n --avatar-text: var(--vectis-color-text-muted);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n inline-size: var(--control-height);\n block-size: var(--control-height);\n flex: none;\n overflow: hidden;\n padding: 0;\n border: none;\n background: var(--avatar-bg);\n color: var(--avatar-text);\n border-radius: var(--vectis-radius-pill);\n font-family: var(--vectis-text-family);\n font-size: var(--control-font-size);\n font-weight: var(--vectis-font-weight-semibold);\n line-height: var(--vectis-text-control-leading);\n text-decoration: none;\n user-select: none;\n /*\n * The `transparent` fallback is what lets a lone avatar render ringless, and it is also\n * what makes a divergence silent: rename it on one side and the discs in a group simply\n * stop being separated, with no error and nothing missing from the box.\n */\n box-shadow: 0 0 0 var(--vectis-control-size-avatar-ring) var(--avatar-ring-color, transparent);\n transition:\n background-color var(--vectis-duration-fast) var(--vectis-ease-default),\n box-shadow var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n\n /*\n * The lightness/chroma pairs are set on the THEME scopes and inherited, rather than written\n * in a `[data-theme='dark'] .v-avatar` rule: a descendant selector matches ANY dark ancestor,\n * so a light subtree nested in a dark page kept the dark discs. An inherited value is\n * resolved by the NEAREST scope, which is exactly how the semantic tokens behave.\n */\n :root,\n [data-theme='light'] {\n --avatar-auto-bg-lc: 0.9 0.06;\n --avatar-auto-text-lc: 0.42 0.13;\n }\n\n [data-theme='dark'] {\n --avatar-auto-bg-lc: 0.42 0.09;\n --avatar-auto-text-lc: 0.92 0.05;\n }\n\n .v-avatar[data-auto] {\n --avatar-bg: oklch(var(--avatar-auto-bg-lc) var(--avatar-hue));\n --avatar-text: oklch(var(--avatar-auto-text-lc) var(--avatar-hue));\n }\n\n /* Custom colour (--custom-color inline): wins, with a fixed white text (contrast\n is the consumer's responsibility). */\n .v-avatar[data-custom] {\n --avatar-bg: var(--custom-color);\n --avatar-text: var(--vectis-color-text-on-accent);\n }\n\n .v-avatar-image {\n inline-size: 100%;\n block-size: 100%;\n object-fit: cover;\n }\n\n .v-avatar-icon {\n --vectis-icon-size: calc(var(--control-height) * 0.55);\n }\n\n :is(a, button).v-avatar {\n cursor: pointer;\n }\n\n :is(a, button).v-avatar:hover:not([aria-disabled='true'], :disabled) {\n background: color-mix(in oklab, var(--avatar-bg), var(--vectis-color-text) 10%);\n }\n\n :is(a, button).v-avatar:focus-visible {\n outline: var(--vectis-focus-ring-width) solid var(--vectis-focus-ring-color);\n outline-offset: var(--vectis-focus-ring-offset);\n }\n\n .v-avatar:is(:disabled, [aria-disabled='true']) {\n cursor: not-allowed;\n background: var(--vectis-color-surface-muted);\n color: var(--vectis-color-text-subtle);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-avatar {\n transition: none;\n }\n }\n\n /* The outline gives each disc its circle back; the focus ring, at (0,2,0), still wins over it. */\n @media (forced-colors: active) {\n .v-avatar {\n outline: var(--vectis-control-border-width) solid CanvasText;\n outline-offset: calc(-1 * var(--vectis-control-border-width));\n }\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuEA,IAAMe,IAAQC,GAoBRC,IAAQC,EAAS,GACjBC,IAAQC,EAAOC,GAAgB,IAAI,GAInCC,IAAeC,QAA2BR,EAAM,QAAQI,GAAO,QAAA,IAA2B,GAC1FK,IAAkBD,QAAeR,EAAM,WAAW,EAAQI,GAAO,OAAQ,GAIzE,EACJ,WACA,gBACA,aACA,OAAOM,MACLC,EAAa;GACf,YAAYX,EAAM;GAClB,aAAaA,EAAM;GACnB,aAAa,OAAO,YAAY,OAAO,QAAQE,CAAK,CAAC,CAAC,QAAQ,CAACU,OAASA,MAAQ,OAAO,CAAC;EAC1F,CAAC,GAEKC,IAAgBL,QAAeM,EAAO,SAASd,EAAM,SAAS,GAC9De,IAAMP,QAAgBM,EAAO,QAAQ,MAAMd,EAAM,YAAY,WAAW,MAAO,GAI/EgB,IAASC,EAAI,EAAK;EACxB,QACQjB,EAAM,WACN;GACJ,EAAO,QAAQ;EACjB,CACF;EACA,IAAMkB,IAAYV,QAAe,EAAQR,EAAM,OAAQ,CAACgB,EAAO,KAAK,GAO9DG,IAAUC,EAAiC,OAAO;EACxD,QAAgB;GACd,IAAMC,IAAMF,EAAQ;GACpB,AAAIE,GAAK,YAAYA,EAAI,iBAAiB,MAAG,EAAO,QAAQ;EAC9D,CAAC;EAQD,IAAMC,IAAYC,QAAoBL,EAAU,QAAQ,KAAA,IAAalB,EAAM,OAAOA,EAAM,IAAM,GACxFwB,IAAQhB,QAAec,EAAU,UAAU,KAAA,KAAapB,EAAM,sBAAsB,IAAI,GAGxFuB,IAAWjB,QACVR,EAAM,OAIJA,EAAM,KACV,MAAM,KAAK,CAAA,CACX,OAAO,OAAO,CAAA,CACd,MAAM,GAAG,CAAC,CAAA,CACV,KAAK,MAAS,CAAC,GAAG0B,CAAI,CAAC,CAAC,EAAE,EAAE,YAAY,KAAK,EAAE,CAAA,CAC/C,KAAK,EAAE,IATc,EAUzB,GAQKC,IAAMnB,QAAe;GACzB,IAAI,CAACR,EAAM,MAAM,OAAO;GACxB,IAAI4B,IAAO;GACX,KAAK,IAAIC,IAAI,GAAGA,IAAI7B,EAAM,KAAK,QAAQ,KACrC,IAAQ4B,IAAO,KAAK5B,EAAM,KAAK,WAAW6B,CAAC,IAAK;GAElD,OAAO,KAAK,IAAID,CAAI,IAAI;EAC1B,CAAC,GACKE,IAAStB,QAAeR,EAAM,UAAU,KAAA,KAAa2B,EAAI,UAAU,IAAI,GAKvEI,IAAOvB,QACX,CAACK,EAAc,SAAS,CAACK,EAAU,SAASM,EAAM,QAC9C,QACCd,EAAY,MAAM,IACzB;EAKA,IAAIsB,GAAO;GACT,IAAMC,IAAQC,EAAS;GACvB,QAAgB;IACd,AAAIrB,EAAc,SAAS,CAACW,EAAM,SAAS,CAACxB,EAAM,OAAO,CAACA,EAAM,QAAQ,CAACiC,EAAM,WAC7E,QAAQ,KACN,qGACF;GAEJ,CAAC;EACH;EAEA,IAAME,IAAY3B,QAA2B,CAC3C4B,EAAiBpC,EAAM,KAAK,MACzB8B,EAAO,QAAQ,EAAE,gBAAgB,OAAOH,EAAI,KAAK,EAAE,IAAI,KAAA,IAC1DzB,EAAM,KACR,CAAC;oBAICjB,EAAA,GAAAC,EA4BYC,EA3BL4B,EAAA,KAAG,GADV3B,EA4BY,EA1BT,iBAAeC,EAAAqD,CAAA,IAAW,SAAY,KAAA,EAC/B,GAAArD,EAAAqB,CAAA,GAAW;GACnB,OAAM;GACL,OAAOyB,EAAA;GACP,aAAW5B,EAAA;GACX,gBAAcE,EAAA,QAAe,KAAQ,KAAA;GACrC,eAAaR,EAAA,UAAU,KAAA,IAAiB,KAAA,IAAR;GAChC,aAAW6B,EAAA,QAAM,KAAQ,KAAA;GACzB,MAAMzC,EAAAsD,CAAA;GACN,MAAM5B,EAAA,UAAG,WAAA,WAA2B,KAAA;GACpC,UAAUA,EAAA,UAAG,WAAgBd,EAAA,WAAW,KAAA;GACxC,MAAM8B,EAAA;GACN,cAAY1C,EAAAiC,CAAA;;GAEb,SAAAhC,QAOE,CANM4B,EAAA,SADRjC,EAAA,GAAAM,EAOE,OAAA;;IALA,KAAI;IACJ,OAAM;IACL,KAAKU,EAAA;IACL,KAAKA,EAAA,OAAOA,EAAA,QAAI;IAChB,SAAK,AAAA6C,EAAA,QAAA,MAAE,EAAA,QAAM;GAEE,GAAA,MAAA,IAAAjD,CAAA,KAAAI,EAAA,QAAlBhB,EAAA,GAAAC,EAAyEM,GAAzEJ,EAAyE,EAAA,KAAA,EAAA,GAAzCC,EAAA0D,CAAA,CAAS,CAAC9C,EAAA,IAAI,GAAA,EAAG,OAAM,gBAAe,CAAA,GAAA,MAAA,EAAA,KACtER,EAEOwD,EAAA,QAAA,WAAA,CAAA,SAAA,CADLvD,EAAwE,QAAxEI,GAAwEH,EAAlB8B,EAAA,KAAQ,GAAA,CAAA,CAAA,GAAA,KAAA,GAAA,CAAA,CAAA,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VAvatarGroup.js","names":[],"sources":["../../../src/components/VAvatar/VAvatarGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @ssr @core\n/**\n * Count avatars through slot VNodes for SSR-consistent overflow; useSlotNodes keeps that count\n * reactive when the parent replaces its slot.\n */\n\nimport { computed, provide } from 'vue'\nimport type { StyleValue } from 'vue'\n\nimport VAvatar from './VAvatar.vue'\nimport type { AvatarSize } from './VAvatar.vue'\nimport { AVATAR_DEFAULT_SIZE, avatarGroupKey } from './context'\n\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useSlotNodes } from '../../composables/useSlotNodes'\n\n/** What the `#overflow` slot receives. */\nexport interface AvatarGroupOverflowSlotProps {\n /** How many avatars are hidden beyond `max`. */\n count: number\n}\n\ninterface AvatarGroupProps {\n /**\n * How many avatars to show before the remaining ones are summed up as a single\n * \"+X\" disc. Left out, or set to 0, every avatar is shown.\n */\n max?: number\n /**\n * The size given to the avatars inside the group. An avatar that sets a `size`\n * of its own keeps it.\n */\n size?: AvatarSize\n /**\n * Applies the reduced density to every avatar inside. Unlike `size` it is cumulative: an\n * avatar cannot opt back out of a compact group.\n */\n compact?: boolean\n /**\n * The colour of the ring drawn around each disc. It defaults to the page background, which\n * makes the ring read as a gap between two avatars.\n */\n ringColor?: string\n /**\n * The accessible name of the group, e.g. \"Project members\". A row of faces does not say on\n * its own who these people are. A consumer `aria-label` or `aria-labelledby` wins over it.\n */\n label?: string\n}\n\nconst props = withDefaults(defineProps<AvatarGroupProps>(), {\n max: undefined,\n size: undefined,\n compact: false,\n ringColor: undefined,\n label: undefined,\n})\n\nconst ariaLabel = useAriaLabel(() => props.label)\n\ndefineSlots<{\n /** The VAvatars to stack. */\n default?(): unknown\n /**\n * Replaces the \"+X\" disc that stands for the avatars beyond `max`. It receives\n * `count`, the number of avatars being hidden.\n */\n overflow?(props: AvatarGroupOverflowSlotProps): unknown\n}>()\n\nprovide(avatarGroupKey, {\n get size() {\n return props.size\n },\n get compact() {\n return props.compact\n },\n})\n\nconst items = useSlotNodes()\n// `max: 0` means \"no limit\", as documented, and so does a negative one: `slice(0, -1)` would\n// drop the last avatar and sum it into a \"+1\" disc.\nconst visibleItems = computed(() =>\n props.max !== undefined && props.max > 0 ? items.value.slice(0, props.max) : items.value,\n)\nconst overflowCount = computed(() => items.value.length - visibleItems.value.length)\n\n// A functional component is the only way to render VNodes that have already been\n// captured: <component :is> expects a component definition, not a vnode.\nconst VisibleAvatars = () => visibleItems.value\n\nconst rootStyle = computed<StyleValue>(() =>\n props.ringColor !== undefined ? { '--avatar-ring-color': props.ringColor } : undefined,\n)\n\n// The group carries v-control so that --control-height is defined at ITS level, which keeps the\n// overlap computable even when a child is wrapped; a VTooltip, for instance, inserts a <span>\n// between the group and the VAvatar. An avatar given a size of its own redefines\n// --control-height on itself, so its own overlap follows that size rather than the group's.\nconst resolvedGroupSize = computed<AvatarSize>(() => props.size ?? AVATAR_DEFAULT_SIZE)\n</script>\n\n<template>\n <div\n class=\"v-avatar-group v-control\"\n role=\"group\"\n :aria-label=\"ariaLabel\"\n :style=\"rootStyle\"\n :data-size=\"resolvedGroupSize\"\n :data-compact=\"compact ? '' : undefined\"\n >\n <component :is=\"VisibleAvatars\" />\n <slot v-if=\"overflowCount > 0\" name=\"overflow\" :count=\"overflowCount\">\n <VAvatar>+{{ overflowCount }}</VAvatar>\n </slot>\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n .v-avatar-group {\n /* The separation ring, declared here so that every child .v-avatar inherits it. */\n --avatar-ring-color: var(--vectis-color-surface);\n display: inline-flex;\n align-items: center;\n }\n\n /*\n * Take overlap height from the group so wrappers and differently sized avatars share one row\n * contract.\n */\n .v-avatar-group > * + * {\n margin-inline-start: calc(var(--control-height) * -0.3);\n }\n\n /* On hover, or as soon as something inside it takes focus, a disc rises above its\n neighbours so it is seen whole rather than clipped by the next one. */\n .v-avatar-group > *:hover,\n .v-avatar-group > *:focus-within {\n z-index: 1;\n }\n}\n</style>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"VAvatarGroup.js","names":["_sfc_main","VAvatarGroup_vue_vue_type_script_setup_true_lang_default","VAvatarGroup_default"],"sources":["../../../src/components/VAvatar/VAvatarGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @ssr @core\n/**\n * Count avatars through slot VNodes for SSR-consistent overflow; useSlotNodes keeps that count\n * reactive when the parent replaces its slot.\n */\n\nimport { computed, provide } from 'vue'\nimport type { StyleValue } from 'vue'\n\nimport VAvatar from './VAvatar.vue'\nimport type { AvatarSize } from './VAvatar.vue'\nimport { AVATAR_DEFAULT_SIZE, avatarGroupKey } from './context'\n\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useSlotNodes } from '../../composables/useSlotNodes'\n\n/** What the `#overflow` slot receives. */\nexport interface AvatarGroupOverflowSlotProps {\n /** How many avatars are hidden beyond `max`. */\n count: number\n}\n\ninterface AvatarGroupProps {\n /**\n * How many avatars to show before the remaining ones are summed up as a single\n * \"+X\" disc. Left out, or set to 0, every avatar is shown.\n */\n max?: number\n /**\n * The size given to the avatars inside the group. An avatar that sets a `size`\n * of its own keeps it.\n */\n size?: AvatarSize\n /**\n * Applies the reduced density to every avatar inside. Unlike `size` it is cumulative: an\n * avatar cannot opt back out of a compact group.\n */\n compact?: boolean\n /**\n * The colour of the ring drawn around each disc. It defaults to the page background, which\n * makes the ring read as a gap between two avatars.\n */\n ringColor?: string\n /**\n * The accessible name of the group, e.g. \"Project members\". A row of faces does not say on\n * its own who these people are. A consumer `aria-label` or `aria-labelledby` wins over it.\n */\n label?: string\n}\n\nconst props = withDefaults(defineProps<AvatarGroupProps>(), {\n max: undefined,\n size: undefined,\n compact: false,\n ringColor: undefined,\n label: undefined,\n})\n\nconst ariaLabel = useAriaLabel(() => props.label)\n\ndefineSlots<{\n /** The VAvatars to stack. */\n default?(): unknown\n /**\n * Replaces the \"+X\" disc that stands for the avatars beyond `max`. It receives\n * `count`, the number of avatars being hidden.\n */\n overflow?(props: AvatarGroupOverflowSlotProps): unknown\n}>()\n\nprovide(avatarGroupKey, {\n get size() {\n return props.size\n },\n get compact() {\n return props.compact\n },\n})\n\nconst items = useSlotNodes()\n// `max: 0` means \"no limit\", as documented, and so does a negative one: `slice(0, -1)` would\n// drop the last avatar and sum it into a \"+1\" disc.\nconst visibleItems = computed(() =>\n props.max !== undefined && props.max > 0 ? items.value.slice(0, props.max) : items.value,\n)\nconst overflowCount = computed(() => items.value.length - visibleItems.value.length)\n\n// A functional component is the only way to render VNodes that have already been\n// captured: <component :is> expects a component definition, not a vnode.\nconst VisibleAvatars = () => visibleItems.value\n\nconst rootStyle = computed<StyleValue>(() =>\n props.ringColor !== undefined ? { '--avatar-ring-color': props.ringColor } : undefined,\n)\n\n// The group carries v-control so that --control-height is defined at ITS level, which keeps the\n// overlap computable even when a child is wrapped; a VTooltip, for instance, inserts a <span>\n// between the group and the VAvatar. An avatar given a size of its own redefines\n// --control-height on itself, so its own overlap follows that size rather than the group's.\nconst resolvedGroupSize = computed<AvatarSize>(() => props.size ?? AVATAR_DEFAULT_SIZE)\n</script>\n\n<template>\n <div\n class=\"v-avatar-group v-control\"\n role=\"group\"\n :aria-label=\"ariaLabel\"\n :style=\"rootStyle\"\n :data-size=\"resolvedGroupSize\"\n :data-compact=\"compact ? '' : undefined\"\n >\n <component :is=\"VisibleAvatars\" />\n <slot v-if=\"overflowCount > 0\" name=\"overflow\" :count=\"overflowCount\">\n <VAvatar>+{{ overflowCount }}</VAvatar>\n </slot>\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n .v-avatar-group {\n /* The separation ring, declared here so that every child .v-avatar inherits it. */\n --avatar-ring-color: var(--vectis-color-surface);\n display: inline-flex;\n align-items: center;\n }\n\n /*\n * Take overlap height from the group so wrappers and differently sized avatars share one row\n * contract.\n */\n .v-avatar-group > * + * {\n margin-inline-start: calc(var(--control-height) * -0.3);\n }\n\n /* On hover, or as soon as something inside it takes focus, a disc rises above its\n neighbours so it is seen whole rather than clipped by the next one. */\n .v-avatar-group > *:hover,\n .v-avatar-group > *:focus-within {\n z-index: 1;\n }\n}\n</style>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VAvatarGroup.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/VAvatar/VAvatarGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @ssr @core\n/**\n * Count avatars through slot VNodes for SSR-consistent overflow; useSlotNodes keeps that count\n * reactive when the parent replaces its slot.\n */\n\nimport { computed, provide } from 'vue'\nimport type { StyleValue } from 'vue'\n\nimport VAvatar from './VAvatar.vue'\nimport type { AvatarSize } from './VAvatar.vue'\nimport { AVATAR_DEFAULT_SIZE, avatarGroupKey } from './context'\n\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useSlotNodes } from '../../composables/useSlotNodes'\n\n/** What the `#overflow` slot receives. */\nexport interface AvatarGroupOverflowSlotProps {\n /** How many avatars are hidden beyond `max`. */\n count: number\n}\n\ninterface AvatarGroupProps {\n /**\n * How many avatars to show before the remaining ones are summed up as a single\n * \"+X\" disc. Left out, or set to 0, every avatar is shown.\n */\n max?: number\n /**\n * The size given to the avatars inside the group. An avatar that sets a `size`\n * of its own keeps it.\n */\n size?: AvatarSize\n /**\n * Applies the reduced density to every avatar inside. Unlike `size` it is cumulative: an\n * avatar cannot opt back out of a compact group.\n */\n compact?: boolean\n /**\n * The colour of the ring drawn around each disc. It defaults to the page background, which\n * makes the ring read as a gap between two avatars.\n */\n ringColor?: string\n /**\n * The accessible name of the group, e.g. \"Project members\". A row of faces does not say on\n * its own who these people are. A consumer `aria-label` or `aria-labelledby` wins over it.\n */\n label?: string\n}\n\nconst props = withDefaults(defineProps<AvatarGroupProps>(), {\n max: undefined,\n size: undefined,\n compact: false,\n ringColor: undefined,\n label: undefined,\n})\n\nconst ariaLabel = useAriaLabel(() => props.label)\n\ndefineSlots<{\n /** The VAvatars to stack. */\n default?(): unknown\n /**\n * Replaces the \"+X\" disc that stands for the avatars beyond `max`. It receives\n * `count`, the number of avatars being hidden.\n */\n overflow?(props: AvatarGroupOverflowSlotProps): unknown\n}>()\n\nprovide(avatarGroupKey, {\n get size() {\n return props.size\n },\n get compact() {\n return props.compact\n },\n})\n\nconst items = useSlotNodes()\n// `max: 0` means \"no limit\", as documented, and so does a negative one: `slice(0, -1)` would\n// drop the last avatar and sum it into a \"+1\" disc.\nconst visibleItems = computed(() =>\n props.max !== undefined && props.max > 0 ? items.value.slice(0, props.max) : items.value,\n)\nconst overflowCount = computed(() => items.value.length - visibleItems.value.length)\n\n// A functional component is the only way to render VNodes that have already been\n// captured: <component :is> expects a component definition, not a vnode.\nconst VisibleAvatars = () => visibleItems.value\n\nconst rootStyle = computed<StyleValue>(() =>\n props.ringColor !== undefined ? { '--avatar-ring-color': props.ringColor } : undefined,\n)\n\n// The group carries v-control so that --control-height is defined at ITS level, which keeps the\n// overlap computable even when a child is wrapped; a VTooltip, for instance, inserts a <span>\n// between the group and the VAvatar. An avatar given a size of its own redefines\n// --control-height on itself, so its own overlap follows that size rather than the group's.\nconst resolvedGroupSize = computed<AvatarSize>(() => props.size ?? AVATAR_DEFAULT_SIZE)\n</script>\n\n<template>\n <div\n class=\"v-avatar-group v-control\"\n role=\"group\"\n :aria-label=\"ariaLabel\"\n :style=\"rootStyle\"\n :data-size=\"resolvedGroupSize\"\n :data-compact=\"compact ? '' : undefined\"\n >\n <component :is=\"VisibleAvatars\" />\n <slot v-if=\"overflowCount > 0\" name=\"overflow\" :count=\"overflowCount\">\n <VAvatar>+{{ overflowCount }}</VAvatar>\n </slot>\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n .v-avatar-group {\n /* The separation ring, declared here so that every child .v-avatar inherits it. */\n --avatar-ring-color: var(--vectis-color-surface);\n display: inline-flex;\n align-items: center;\n }\n\n /*\n * Take overlap height from the group so wrappers and differently sized avatars share one row\n * contract.\n */\n .v-avatar-group > * + * {\n margin-inline-start: calc(var(--control-height) * -0.3);\n }\n\n /* On hover, or as soon as something inside it takes focus, a disc rises above its\n neighbours so it is seen whole rather than clipped by the next one. */\n .v-avatar-group > *:hover,\n .v-avatar-group > *:focus-within {\n z-index: 1;\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;EAmDA,
|
|
1
|
+
{"version":3,"file":"VAvatarGroup.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createElementBlock","_unref","_normalizeStyle","_createBlock","_resolveDynamicComponent","_renderSlot","_createVNode","VAvatar","_withCtx","_createTextVNode","_toDisplayString","_createCommentVNode","VAvatar_default","_hoisted_1","VAvatarGroup_vue_vue_type_script_setup_true_lang_default","props","__props","ariaLabel","useAriaLabel","avatarGroupKey","items","useSlotNodes","visibleItems","computed","overflowCount","VisibleAvatars","rootStyle","resolvedGroupSize","openBlock","createElementBlock","unref","normalizeStyle","createBlock","resolveDynamicComponent","renderSlot","_ctx","createVNode","withCtx","createTextVNode","toDisplayString","createCommentVNode"],"sources":["../../../src/components/VAvatar/VAvatarGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @ssr @core\n/**\n * Count avatars through slot VNodes for SSR-consistent overflow; useSlotNodes keeps that count\n * reactive when the parent replaces its slot.\n */\n\nimport { computed, provide } from 'vue'\nimport type { StyleValue } from 'vue'\n\nimport VAvatar from './VAvatar.vue'\nimport type { AvatarSize } from './VAvatar.vue'\nimport { AVATAR_DEFAULT_SIZE, avatarGroupKey } from './context'\n\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useSlotNodes } from '../../composables/useSlotNodes'\n\n/** What the `#overflow` slot receives. */\nexport interface AvatarGroupOverflowSlotProps {\n /** How many avatars are hidden beyond `max`. */\n count: number\n}\n\ninterface AvatarGroupProps {\n /**\n * How many avatars to show before the remaining ones are summed up as a single\n * \"+X\" disc. Left out, or set to 0, every avatar is shown.\n */\n max?: number\n /**\n * The size given to the avatars inside the group. An avatar that sets a `size`\n * of its own keeps it.\n */\n size?: AvatarSize\n /**\n * Applies the reduced density to every avatar inside. Unlike `size` it is cumulative: an\n * avatar cannot opt back out of a compact group.\n */\n compact?: boolean\n /**\n * The colour of the ring drawn around each disc. It defaults to the page background, which\n * makes the ring read as a gap between two avatars.\n */\n ringColor?: string\n /**\n * The accessible name of the group, e.g. \"Project members\". A row of faces does not say on\n * its own who these people are. A consumer `aria-label` or `aria-labelledby` wins over it.\n */\n label?: string\n}\n\nconst props = withDefaults(defineProps<AvatarGroupProps>(), {\n max: undefined,\n size: undefined,\n compact: false,\n ringColor: undefined,\n label: undefined,\n})\n\nconst ariaLabel = useAriaLabel(() => props.label)\n\ndefineSlots<{\n /** The VAvatars to stack. */\n default?(): unknown\n /**\n * Replaces the \"+X\" disc that stands for the avatars beyond `max`. It receives\n * `count`, the number of avatars being hidden.\n */\n overflow?(props: AvatarGroupOverflowSlotProps): unknown\n}>()\n\nprovide(avatarGroupKey, {\n get size() {\n return props.size\n },\n get compact() {\n return props.compact\n },\n})\n\nconst items = useSlotNodes()\n// `max: 0` means \"no limit\", as documented, and so does a negative one: `slice(0, -1)` would\n// drop the last avatar and sum it into a \"+1\" disc.\nconst visibleItems = computed(() =>\n props.max !== undefined && props.max > 0 ? items.value.slice(0, props.max) : items.value,\n)\nconst overflowCount = computed(() => items.value.length - visibleItems.value.length)\n\n// A functional component is the only way to render VNodes that have already been\n// captured: <component :is> expects a component definition, not a vnode.\nconst VisibleAvatars = () => visibleItems.value\n\nconst rootStyle = computed<StyleValue>(() =>\n props.ringColor !== undefined ? { '--avatar-ring-color': props.ringColor } : undefined,\n)\n\n// The group carries v-control so that --control-height is defined at ITS level, which keeps the\n// overlap computable even when a child is wrapped; a VTooltip, for instance, inserts a <span>\n// between the group and the VAvatar. An avatar given a size of its own redefines\n// --control-height on itself, so its own overlap follows that size rather than the group's.\nconst resolvedGroupSize = computed<AvatarSize>(() => props.size ?? AVATAR_DEFAULT_SIZE)\n</script>\n\n<template>\n <div\n class=\"v-avatar-group v-control\"\n role=\"group\"\n :aria-label=\"ariaLabel\"\n :style=\"rootStyle\"\n :data-size=\"resolvedGroupSize\"\n :data-compact=\"compact ? '' : undefined\"\n >\n <component :is=\"VisibleAvatars\" />\n <slot v-if=\"overflowCount > 0\" name=\"overflow\" :count=\"overflowCount\">\n <VAvatar>+{{ overflowCount }}</VAvatar>\n </slot>\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n .v-avatar-group {\n /* The separation ring, declared here so that every child .v-avatar inherits it. */\n --avatar-ring-color: var(--vectis-color-surface);\n display: inline-flex;\n align-items: center;\n }\n\n /*\n * Take overlap height from the group so wrappers and differently sized avatars share one row\n * contract.\n */\n .v-avatar-group > * + * {\n margin-inline-start: calc(var(--control-height) * -0.3);\n }\n\n /* On hover, or as soon as something inside it takes focus, a disc rises above its\n neighbours so it is seen whole rather than clipped by the next one. */\n .v-avatar-group > *:hover,\n .v-avatar-group > *:focus-within {\n z-index: 1;\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;EAmDA,IAAMgB,IAAQC,GAQRC,IAAYC,QAAmBH,EAAM,KAAK;EAYhD,EAAQI,GAAgB;GACtB,IAAI,OAAO;IACT,OAAOJ,EAAM;GACf;GACA,IAAI,UAAU;IACZ,OAAOA,EAAM;GACf;EACF,CAAC;EAED,IAAMK,IAAQC,EAAa,GAGrBC,IAAeC,QACnBR,EAAM,QAAQ,KAAA,KAAaA,EAAM,MAAM,IAAIK,EAAM,MAAM,MAAM,GAAGL,EAAM,GAAG,IAAIK,EAAM,KACrF,GACMI,IAAgBD,QAAeH,EAAM,MAAM,SAASE,EAAa,MAAM,MAAM,GAI7EG,UAAuBH,EAAa,OAEpCI,IAAYH,QAChBR,EAAM,cAAc,KAAA,IAAyD,KAAA,IAA7C,EAAE,uBAAuBA,EAAM,UAAU,CAC3E,GAMMY,IAAoBJ,QAA2BR,EAAM,QAAA,IAA2B;oBAIpFhB,EAAA,GAAAC,EAYM,OAAA;GAXJ,OAAM;GACN,MAAK;GACJ,cAAYC,EAAAgB,CAAA;GACZ,OAAKf,EAAEwB,EAAA,KAAS;GAChB,aAAWC,EAAA;GACX,gBAAcX,EAAA,UAAO,KAAQ,KAAA;EAE9BjB,GAAAA,EAAAA,EAAA,GAAAI,EAAkCC,EAAlBqB,CAAc,CAAA,IAClBD,EAAA,QAAa,IAAzBnB,EAEO8B,EAAA,QAAA,YAAA,EAFyC,OAAOX,EAAA,MAAa,SAE7D,CADLlB,EAAuCC,GAAA,MAAA;GAA9B,SAAAC,QAAC,CAADC,EAAA,MAACC,EAAGc,EAAA,KAAa,GAAA,CAAA,CAAA,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","names":[],"sources":["../../../src/components/VAvatar/context.ts"],"sourcesContent":["/**\n * Explicit avatar size overrides the group fallback. Compact is cumulative, so a compact group\n * cannot have an expanded child.\n */\n\nimport type { InjectionKey } from 'vue'\n\nimport type { AvatarSize } from './VAvatar.vue'\n\nexport interface AvatarGroupContext {\n size?: AvatarSize\n compact?: boolean\n}\n\n/** The size of an avatar that neither names one nor sits in a group that does. */\nexport const AVATAR_DEFAULT_SIZE: AvatarSize = 'md'\n\nexport const avatarGroupKey: InjectionKey<AvatarGroupContext> = Symbol('v-avatar-group')\n"],"mappings":";AAiBA,
|
|
1
|
+
{"version":3,"file":"context.js","names":["avatarGroupKey"],"sources":["../../../src/components/VAvatar/context.ts"],"sourcesContent":["/**\n * Explicit avatar size overrides the group fallback. Compact is cumulative, so a compact group\n * cannot have an expanded child.\n */\n\nimport type { InjectionKey } from 'vue'\n\nimport type { AvatarSize } from './VAvatar.vue'\n\nexport interface AvatarGroupContext {\n size?: AvatarSize\n compact?: boolean\n}\n\n/** The size of an avatar that neither names one nor sits in a group that does. */\nexport const AVATAR_DEFAULT_SIZE: AvatarSize = 'md'\n\nexport const avatarGroupKey: InjectionKey<AvatarGroupContext> = Symbol('v-avatar-group')\n"],"mappings":";AAiBA,IAAaA,IAAmD,OAAO,gBAAgB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VBadge.js","names":[],"sources":["../../../src/components/VBadge/VBadge.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @core\n/**\n * Render the default slot once: inspect its VNodes to decide whether a noninteractive badge has\n * content.\n */\nimport { computed, h } from 'vue'\nimport type { FunctionalComponent } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport type { IconSource } from '../VIcon/types'\n\nimport { customColorStyle } from '../../utils/css'\n\n/** How strongly the badge is painted: the full colour, or a tint of it. */\nexport type BadgeVariant = 'solid' | 'soft'\n/** What the badge means, in colour. */\nexport type BadgeTone = 'neutral' | 'accent' | 'danger' | 'success' | 'warning'\n/** The corner an overlaid badge is pinned to. */\nexport type BadgeOverlayPosition = 'top' | 'bottom'\n\ninterface BadgeProps {\n /**\n * How strongly the badge is painted: filled with the full colour (`solid`, the default), or a\n * tinted background with the text in the colour (`soft`), for a count that should not draw\n * the eye.\n */\n variant?: BadgeVariant\n /**\n * The meaning the badge carries, expressed as a colour. A solid badge is filled\n * with it and its text adapts to stay readable; a soft one is tinted with it and\n * writes its text in it.\n */\n tone?: BadgeTone\n /**\n * A colour of your own (hex, CSS name or `oklch()`), which replaces the tone. On a solid\n * badge, browsers that support `contrast-color()` turn the text black or white by themselves;\n * everywhere else it falls back to white, so with a light colour the contrast is yours to\n * check.\n */\n color?: string\n /**\n * The number to display. Anything above 99 is shown as \"99+\", so that a busy\n * counter cannot stretch the pill indefinitely.\n */\n count?: number\n /**\n * A single icon shown instead of a number: an icon name, or an explicit render\n * (the VIcon contract). It takes precedence over `count`, and is ignored when the\n * badge is a `dot`.\n */\n icon?: IconSource\n /**\n * Reduces the badge to a 10px dot with no content, the discreet way to signal\n * that something is new without saying how much.\n */\n dot?: boolean\n /**\n * Pins the badge to a corner of the target element instead of placing it beside\n * it. It does nothing when the badge has no target.\n */\n overlay?: boolean\n /**\n * Which corner an `overlay` badge is pinned to: the top one by default, the bottom one for a\n * marker that belongs at the foot of its target, such as a presence dot under an avatar.\n */\n overlayPosition?: BadgeOverlayPosition\n /**\n * Draws a 2px ring around the badge, in the colour of the surface behind it, which detaches\n * it from a busy target such as a picture.\n */\n bordered?: boolean\n /** The colour of the ring drawn by `bordered`. */\n ringColor?: string\n}\n\nconst props = withDefaults(defineProps<BadgeProps>(), {\n variant: 'solid',\n tone: 'accent',\n color: undefined,\n count: undefined,\n icon: undefined,\n overlayPosition: 'top',\n ringColor: undefined,\n // Written out although Vue casts an absent boolean to `false` on its own: left out,\n // `vue-component-meta` reports no default at all and the docs table's cell goes blank.\n dot: false,\n overlay: false,\n bordered: false,\n})\n\nconst slots = defineSlots<{\n /** The element the badge belongs to. */\n default?(): unknown\n}>()\n\n// A function read by the template, never a `computed`: `slots` is not reactive, so a computed\n// would keep its first answer while a slot behind a `v-if` comes and goes.\nfunction hasTarget() {\n return slots.default !== undefined\n}\n\n/**\n * The counter as it is actually displayed: a whole number, zero or more, and anything past 99\n * becomes \"99+\".\n */\nconst displayCount = computed(() => {\n const count = props.count\n if (count === undefined || !Number.isFinite(count)) return undefined\n return count > 99 ? '99+' : Math.max(0, Math.trunc(count))\n})\n\n/*\n * The template has two roots; one wrapping a target, one standing alone; and both render the\n * same badge; a functional component is the one way to put the same markup in two places of a\n * template without writing it twice.\n */\nconst Pill: FunctionalComponent = () =>\n h(\n 'span',\n {\n class: 'v-badge v-tone v-variant',\n 'data-variant': props.variant,\n 'data-tone': props.tone,\n 'data-custom': props.color !== undefined ? '' : undefined,\n 'data-dot': props.dot ? '' : undefined,\n 'data-icon-only': !props.dot && props.icon ? '' : undefined,\n 'data-bordered': props.bordered ? '' : undefined,\n style: [\n customColorStyle(props.color),\n props.ringColor !== undefined ? { '--badge-ring-color': props.ringColor } : undefined,\n ],\n },\n props.dot\n ? undefined\n : props.icon\n ? [h(VIcon, iconProps(props.icon))]\n : displayCount.value === undefined\n ? undefined\n : String(displayCount.value),\n )\n// The empty list is not decoration. A functional component that declares no props lets only\n// `class`, `style` and listeners fall through, so a standalone badge, whose root this is, would\n// silently drop every other attribute a consumer set on VBadge (an `id`, a `data-*`).\nPill.props = []\n</script>\n\n<template>\n <span\n v-if=\"hasTarget()\"\n class=\"v-badge-host\"\n :data-overlay=\"overlay ? '' : undefined\"\n :data-overlay-position=\"overlayPosition\"\n >\n <slot />\n <Pill aria-hidden=\"true\" />\n </span>\n <Pill v-else />\n</template>\n\n<style>\n@layer vectis.components {\n .v-badge-host {\n position: relative;\n display: inline-flex;\n align-items: center;\n gap: var(--vectis-space-2);\n }\n\n /* The pill is painted by the shared `.v-variant` rules (styles/variants.css) over the\n tone table (`.v-tone`), both set in the template: `solid` is the tone's full colour,\n `soft` its tint with the text in the tone's own colour. A custom colour is the table's\n `[data-custom]` row, in styles/tones.css. */\n .v-badge {\n --vectis-icon-size: var(--vectis-icon-size-sm);\n --vectis-icon-opsz: 20;\n /* The colour of the `bordered` ring: a bet on the page background, the only one a\n component can make since CSS cannot read what its parent paints. The `ringColor`\n prop overrides it inline for a badge sitting on anything else. */\n --badge-ring-color: var(--vectis-color-surface);\n\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: var(--vectis-control-size-badge-h);\n /* A minimum width equal to the height, with a small padding on top, is what\n makes a one- or two-digit counter come out round rather than oval. */\n min-width: var(--vectis-control-size-badge-h);\n padding-inline: var(--vectis-space-1);\n border-radius: var(--vectis-radius-pill);\n font-family: var(--vectis-text-family);\n font-size: var(--vectis-text-caption-size);\n font-weight: var(--vectis-text-control-weight);\n line-height: var(--vectis-text-control-leading);\n }\n\n /*\n * The class is compounded to (0,3,0): `.v-variant[data-variant='solid']` sets `color` at\n * (0,2,0) from another sheet, and a tie would be settled by sheet order. The soft pill keeps\n * the tone's own text colour, which says the tone where black or white would not.\n */\n @supports (color: contrast-color(red)) {\n .v-badge.v-variant[data-variant='solid'] {\n color: contrast-color(var(--tone-bg-solid));\n }\n }\n\n /* A dot is always solid: with no content, a soft dot is a pale disc on the page, which a\n presence marker cannot afford. (0,3,0), above the soft variant's background. */\n .v-badge.v-variant[data-dot] {\n background: var(--tone-bg-solid);\n }\n\n .v-badge[data-icon-only] {\n padding: 0;\n }\n\n .v-badge[data-dot] {\n width: var(--vectis-control-size-badge-dot);\n height: var(--vectis-control-size-badge-dot);\n min-width: 0;\n padding: 0;\n }\n\n .v-badge[data-bordered] {\n box-shadow: 0 0 0 var(--vectis-control-size-badge-ring) var(--badge-ring-color);\n }\n\n /*\n * The tuck-in offset is a ratio of the badge's own size, so it stays proportionate across the\n * pill, the dot and the icon. Each half of it is held in its own variable: the corner and the\n * reading direction each flip ONE axis, and writing the whole `translate` again in each\n * branch would make the two multiply; four rules to keep in step by hand for two independent\n * decisions.\n */\n .v-badge-host[data-overlay] > .v-badge {\n --badge-overlay-x: 25%;\n --badge-overlay-y: -25%;\n\n position: absolute;\n inset-block: 0 auto;\n inset-inline-end: 0;\n translate: var(--badge-overlay-x) var(--badge-overlay-y);\n /*\n * Raise overlaid badges above later positioned siblings; tree order alone lets neighbouring\n * segments cover them.\n */\n z-index: 1;\n }\n\n .v-badge-host[data-overlay][data-overlay-position='bottom'] > .v-badge {\n --badge-overlay-y: 25%;\n\n inset-block: auto 0;\n }\n\n /*\n * In a right-to-left direction the logical corner moves to the left, so the horizontal half\n * of the translation has to flip with it; `translate` is a physical property and knows\n * nothing about direction.\n */\n .v-badge-host[data-overlay]:dir(rtl) > .v-badge {\n --badge-overlay-x: -25%;\n }\n\n /* Forced colours repaint the background as Canvas and drop the ring, a shadow: the pill\n loses its shape, and a dot, which has nothing else, disappears altogether. The pill\n gets an edge, and the dot is filled in the text colour. */\n @media (forced-colors: active) {\n .v-badge {\n outline: var(--vectis-control-border-width) solid CanvasText;\n outline-offset: calc(-1 * var(--vectis-control-border-width));\n }\n\n .v-badge.v-variant[data-dot] {\n forced-color-adjust: none;\n background: CanvasText;\n }\n }\n}\n</style>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"VBadge.js","names":["_sfc_main","VBadge_vue_vue_type_script_setup_true_lang_default","VBadge_default"],"sources":["../../../src/components/VBadge/VBadge.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @core\n/**\n * Render the default slot once: inspect its VNodes to decide whether a noninteractive badge has\n * content.\n */\nimport { computed, h } from 'vue'\nimport type { FunctionalComponent } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport type { IconSource } from '../VIcon/types'\n\nimport { customColorStyle } from '../../utils/css'\n\n/** How strongly the badge is painted: the full colour, or a tint of it. */\nexport type BadgeVariant = 'solid' | 'soft'\n/** What the badge means, in colour. */\nexport type BadgeTone = 'neutral' | 'accent' | 'danger' | 'success' | 'warning'\n/** The corner an overlaid badge is pinned to. */\nexport type BadgeOverlayPosition = 'top' | 'bottom'\n\ninterface BadgeProps {\n /**\n * How strongly the badge is painted: filled with the full colour (`solid`, the default), or a\n * tinted background with the text in the colour (`soft`), for a count that should not draw\n * the eye.\n */\n variant?: BadgeVariant\n /**\n * The meaning the badge carries, expressed as a colour. A solid badge is filled\n * with it and its text adapts to stay readable; a soft one is tinted with it and\n * writes its text in it.\n */\n tone?: BadgeTone\n /**\n * A colour of your own (hex, CSS name or `oklch()`), which replaces the tone. On a solid\n * badge, browsers that support `contrast-color()` turn the text black or white by themselves;\n * everywhere else it falls back to white, so with a light colour the contrast is yours to\n * check.\n */\n color?: string\n /**\n * The number to display. Anything above 99 is shown as \"99+\", so that a busy\n * counter cannot stretch the pill indefinitely.\n */\n count?: number\n /**\n * A single icon shown instead of a number: an icon name, or an explicit render\n * (the VIcon contract). It takes precedence over `count`, and is ignored when the\n * badge is a `dot`.\n */\n icon?: IconSource\n /**\n * Reduces the badge to a 10px dot with no content, the discreet way to signal\n * that something is new without saying how much.\n */\n dot?: boolean\n /**\n * Pins the badge to a corner of the target element instead of placing it beside\n * it. It does nothing when the badge has no target.\n */\n overlay?: boolean\n /**\n * Which corner an `overlay` badge is pinned to: the top one by default, the bottom one for a\n * marker that belongs at the foot of its target, such as a presence dot under an avatar.\n */\n overlayPosition?: BadgeOverlayPosition\n /**\n * Draws a 2px ring around the badge, in the colour of the surface behind it, which detaches\n * it from a busy target such as a picture.\n */\n bordered?: boolean\n /** The colour of the ring drawn by `bordered`. */\n ringColor?: string\n}\n\nconst props = withDefaults(defineProps<BadgeProps>(), {\n variant: 'solid',\n tone: 'accent',\n color: undefined,\n count: undefined,\n icon: undefined,\n overlayPosition: 'top',\n ringColor: undefined,\n // Written out although Vue casts an absent boolean to `false` on its own: left out,\n // `vue-component-meta` reports no default at all and the docs table's cell goes blank.\n dot: false,\n overlay: false,\n bordered: false,\n})\n\nconst slots = defineSlots<{\n /** The element the badge belongs to. */\n default?(): unknown\n}>()\n\n// A function read by the template, never a `computed`: `slots` is not reactive, so a computed\n// would keep its first answer while a slot behind a `v-if` comes and goes.\nfunction hasTarget() {\n return slots.default !== undefined\n}\n\n/**\n * The counter as it is actually displayed: a whole number, zero or more, and anything past 99\n * becomes \"99+\".\n */\nconst displayCount = computed(() => {\n const count = props.count\n if (count === undefined || !Number.isFinite(count)) return undefined\n return count > 99 ? '99+' : Math.max(0, Math.trunc(count))\n})\n\n/*\n * The template has two roots; one wrapping a target, one standing alone; and both render the\n * same badge; a functional component is the one way to put the same markup in two places of a\n * template without writing it twice.\n */\nconst Pill: FunctionalComponent = () =>\n h(\n 'span',\n {\n class: 'v-badge v-tone v-variant',\n 'data-variant': props.variant,\n 'data-tone': props.tone,\n 'data-custom': props.color !== undefined ? '' : undefined,\n 'data-dot': props.dot ? '' : undefined,\n 'data-icon-only': !props.dot && props.icon ? '' : undefined,\n 'data-bordered': props.bordered ? '' : undefined,\n style: [\n customColorStyle(props.color),\n props.ringColor !== undefined ? { '--badge-ring-color': props.ringColor } : undefined,\n ],\n },\n props.dot\n ? undefined\n : props.icon\n ? [h(VIcon, iconProps(props.icon))]\n : displayCount.value === undefined\n ? undefined\n : String(displayCount.value),\n )\n// The empty list is not decoration. A functional component that declares no props lets only\n// `class`, `style` and listeners fall through, so a standalone badge, whose root this is, would\n// silently drop every other attribute a consumer set on VBadge (an `id`, a `data-*`).\nPill.props = []\n</script>\n\n<template>\n <span\n v-if=\"hasTarget()\"\n class=\"v-badge-host\"\n :data-overlay=\"overlay ? '' : undefined\"\n :data-overlay-position=\"overlayPosition\"\n >\n <slot />\n <Pill aria-hidden=\"true\" />\n </span>\n <Pill v-else />\n</template>\n\n<style>\n@layer vectis.components {\n .v-badge-host {\n position: relative;\n display: inline-flex;\n align-items: center;\n gap: var(--vectis-space-2);\n }\n\n /* The pill is painted by the shared `.v-variant` rules (styles/variants.css) over the\n tone table (`.v-tone`), both set in the template: `solid` is the tone's full colour,\n `soft` its tint with the text in the tone's own colour. A custom colour is the table's\n `[data-custom]` row, in styles/tones.css. */\n .v-badge {\n --vectis-icon-size: var(--vectis-icon-size-sm);\n --vectis-icon-opsz: 20;\n /* The colour of the `bordered` ring: a bet on the page background, the only one a\n component can make since CSS cannot read what its parent paints. The `ringColor`\n prop overrides it inline for a badge sitting on anything else. */\n --badge-ring-color: var(--vectis-color-surface);\n\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: var(--vectis-control-size-badge-h);\n /* A minimum width equal to the height, with a small padding on top, is what\n makes a one- or two-digit counter come out round rather than oval. */\n min-width: var(--vectis-control-size-badge-h);\n padding-inline: var(--vectis-space-1);\n border-radius: var(--vectis-radius-pill);\n font-family: var(--vectis-text-family);\n font-size: var(--vectis-text-caption-size);\n font-weight: var(--vectis-text-control-weight);\n line-height: var(--vectis-text-control-leading);\n }\n\n /*\n * The class is compounded to (0,3,0): `.v-variant[data-variant='solid']` sets `color` at\n * (0,2,0) from another sheet, and a tie would be settled by sheet order. The soft pill keeps\n * the tone's own text colour, which says the tone where black or white would not.\n */\n @supports (color: contrast-color(red)) {\n .v-badge.v-variant[data-variant='solid'] {\n color: contrast-color(var(--tone-bg-solid));\n }\n }\n\n /* A dot is always solid: with no content, a soft dot is a pale disc on the page, which a\n presence marker cannot afford. (0,3,0), above the soft variant's background. */\n .v-badge.v-variant[data-dot] {\n background: var(--tone-bg-solid);\n }\n\n .v-badge[data-icon-only] {\n padding: 0;\n }\n\n .v-badge[data-dot] {\n width: var(--vectis-control-size-badge-dot);\n height: var(--vectis-control-size-badge-dot);\n min-width: 0;\n padding: 0;\n }\n\n .v-badge[data-bordered] {\n box-shadow: 0 0 0 var(--vectis-control-size-badge-ring) var(--badge-ring-color);\n }\n\n /*\n * The tuck-in offset is a ratio of the badge's own size, so it stays proportionate across the\n * pill, the dot and the icon. Each half of it is held in its own variable: the corner and the\n * reading direction each flip ONE axis, and writing the whole `translate` again in each\n * branch would make the two multiply; four rules to keep in step by hand for two independent\n * decisions.\n */\n .v-badge-host[data-overlay] > .v-badge {\n --badge-overlay-x: 25%;\n --badge-overlay-y: -25%;\n\n position: absolute;\n inset-block: 0 auto;\n inset-inline-end: 0;\n translate: var(--badge-overlay-x) var(--badge-overlay-y);\n /*\n * Raise overlaid badges above later positioned siblings; tree order alone lets neighbouring\n * segments cover them.\n */\n z-index: 1;\n }\n\n .v-badge-host[data-overlay][data-overlay-position='bottom'] > .v-badge {\n --badge-overlay-y: 25%;\n\n inset-block: auto 0;\n }\n\n /*\n * In a right-to-left direction the logical corner moves to the left, so the horizontal half\n * of the translation has to flip with it; `translate` is a physical property and knows\n * nothing about direction.\n */\n .v-badge-host[data-overlay]:dir(rtl) > .v-badge {\n --badge-overlay-x: -25%;\n }\n\n /* Forced colours repaint the background as Canvas and drop the ring, a shadow: the pill\n loses its shape, and a dot, which has nothing else, disappears altogether. The pill\n gets an edge, and the dot is filled in the text colour. */\n @media (forced-colors: active) {\n .v-badge {\n outline: var(--vectis-control-border-width) solid CanvasText;\n outline-offset: calc(-1 * var(--vectis-control-border-width));\n }\n\n .v-badge.v-variant[data-dot] {\n forced-color-adjust: none;\n background: CanvasText;\n }\n }\n}\n</style>\n"],"mappings":""}
|
|
@@ -33,7 +33,7 @@ var f = ["data-overlay", "data-overlay-position"], p = /*@__PURE__*/ s({
|
|
|
33
33
|
}
|
|
34
34
|
let g = r(() => {
|
|
35
35
|
let e = p.count;
|
|
36
|
-
if (
|
|
36
|
+
if (e !== void 0 && Number.isFinite(e)) return e > 99 ? "99+" : Math.max(0, Math.trunc(e));
|
|
37
37
|
}), _ = () => c("span", {
|
|
38
38
|
class: "v-badge v-tone v-variant",
|
|
39
39
|
"data-variant": p.variant,
|