vectis-ui 0.14.0 → 0.16.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.css +1 -1
- package/dist/components/VAccordion/VAccordion.d.ts +0 -6
- package/dist/components/VAccordion/VAccordion.js.map +1 -1
- package/dist/components/VAccordion/VAccordion.vue_vue_type_script_setup_true_lang.js +3 -8
- 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.d.ts +0 -3
- package/dist/components/VAvatar/VAvatar.js.map +1 -1
- package/dist/components/VAvatar/VAvatar.vue_vue_type_script_setup_true_lang.js +21 -27
- package/dist/components/VAvatar/VAvatar.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VAvatar/VAvatarGroup.d.ts +0 -6
- package/dist/components/VAvatar/VAvatarGroup.js.map +1 -1
- package/dist/components/VAvatar/VAvatarGroup.vue_vue_type_script_setup_true_lang.js +5 -19
- package/dist/components/VAvatar/VAvatarGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VAvatar/context.d.ts +0 -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.d.ts +0 -6
- package/dist/components/VButton/VButton.js.map +1 -1
- package/dist/components/VButton/VButton.vue_vue_type_script_setup_true_lang.js +11 -17
- package/dist/components/VButton/VButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VButton/VButtonGroup.d.ts +0 -6
- package/dist/components/VButton/VButtonGroup.js.map +1 -1
- package/dist/components/VButton/VButtonGroup.vue_vue_type_script_setup_true_lang.js +0 -7
- package/dist/components/VButton/VButtonGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VButton/context.d.ts +0 -2
- 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.d.ts +0 -3
- package/dist/components/VChip/VChip.js.map +1 -1
- package/dist/components/VChip/VChip.vue_vue_type_script_setup_true_lang.js +0 -6
- package/dist/components/VChip/VChip.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VColorInput/VColorInput.d.ts +0 -3
- package/dist/components/VColorInput/VColorInput.js.map +1 -1
- package/dist/components/VColorInput/VColorInput.vue_vue_type_script_setup_true_lang.js +3 -9
- package/dist/components/VColorInput/VColorInput.vue_vue_type_script_setup_true_lang.js.map +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.d.ts +0 -3
- package/dist/components/VCombobox/VCombobox.js.map +1 -1
- package/dist/components/VCombobox/VCombobox.vue_vue_type_script_setup_true_lang.js +100 -119
- package/dist/components/VCombobox/VCombobox.vue_vue_type_script_setup_true_lang.js.map +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.d.ts +0 -3
- package/dist/components/VContextMenu/VContextMenu.js.map +1 -1
- package/dist/components/VContextMenu/VContextMenu.vue_vue_type_script_setup_true_lang.js +3 -11
- package/dist/components/VContextMenu/VContextMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VDataTable/VDataTable.css +1 -1
- package/dist/components/VDataTable/VDataTable.d.ts +0 -2
- package/dist/components/VDataTable/VDataTable.js.map +1 -1
- package/dist/components/VDataTable/VDataTable.vue_vue_type_script_setup_true_lang.js +69 -88
- package/dist/components/VDataTable/VDataTable.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VDateInput/VDateInput.d.ts +0 -3
- package/dist/components/VDateInput/VDateInput.js.map +1 -1
- package/dist/components/VDateInput/VDateInput.vue_vue_type_script_setup_true_lang.js +5 -10
- 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.d.ts +0 -5
- package/dist/components/VFileInput/VFileInput.js.map +1 -1
- package/dist/components/VFileInput/VFileInput.vue_vue_type_script_setup_true_lang.js +54 -65
- 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.d.ts +0 -3
- package/dist/components/VHotkeys/VHotkeys.js.map +1 -1
- package/dist/components/VHotkeys/VHotkeys.vue_vue_type_script_setup_true_lang.js +0 -6
- 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.d.ts +0 -3
- package/dist/components/VIconButton/VIconButton.js.map +1 -1
- package/dist/components/VIconButton/VIconButton.vue_vue_type_script_setup_true_lang.js +0 -6
- package/dist/components/VIconButton/VIconButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VInput/VInput.css +1 -1
- package/dist/components/VInput/VInput.d.ts +0 -3
- package/dist/components/VInput/VInput.js.map +1 -1
- package/dist/components/VInput/VInput.vue_vue_type_script_setup_true_lang.js +2 -8
- package/dist/components/VInput/VInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VInput/VInputGroup.d.ts +0 -3
- package/dist/components/VInput/VInputGroup.js.map +1 -1
- package/dist/components/VInput/VInputGroup.vue_vue_type_script_setup_true_lang.js +0 -7
- package/dist/components/VInput/VInputGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VInput/context.d.ts +0 -2
- package/dist/components/VInput/context.js.map +1 -1
- package/dist/components/VInputOTP/VInputOTP.d.ts +0 -3
- package/dist/components/VInputOTP/VInputOTP.js.map +1 -1
- package/dist/components/VInputOTP/VInputOTP.vue_vue_type_script_setup_true_lang.js +2 -14
- 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.d.ts +0 -3
- package/dist/components/VListbox/VListboxPanel.js.map +1 -1
- package/dist/components/VListbox/VListboxPanel.vue_vue_type_script_setup_true_lang.js +0 -6
- 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 +4 -14
- package/dist/components/VListbox/VListboxValues.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VMenu/VMenu.d.ts +0 -3
- package/dist/components/VMenu/VMenu.js.map +1 -1
- package/dist/components/VMenu/VMenu.vue_vue_type_script_setup_true_lang.js +0 -6
- 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.d.ts +0 -3
- package/dist/components/VMenu/VMenuPanel.js.map +1 -1
- package/dist/components/VMenu/VMenuPanel.vue_vue_type_script_setup_true_lang.js +9 -16
- 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.d.ts +0 -3
- package/dist/components/VNumberInput/VNumberInput.js.map +1 -1
- package/dist/components/VNumberInput/VNumberInput.vue_vue_type_script_setup_true_lang.js +85 -90
- package/dist/components/VNumberInput/VNumberInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VNumberInput/number.js.map +1 -1
- package/dist/components/VPagination/VPagination.d.ts +0 -3
- package/dist/components/VPagination/VPagination.js.map +1 -1
- package/dist/components/VPagination/VPagination.vue_vue_type_script_setup_true_lang.js +0 -6
- 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.d.ts +0 -3
- package/dist/components/VSelect/VSelect.js.map +1 -1
- package/dist/components/VSelect/VSelect.vue_vue_type_script_setup_true_lang.js +80 -90
- 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.d.ts +0 -6
- package/dist/components/VSideNavigation/VSideNavigation.js.map +1 -1
- package/dist/components/VSideNavigation/VSideNavigation.vue_vue_type_script_setup_true_lang.js +2 -11
- 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.d.ts +0 -3
- package/dist/components/VSkeletonLoader/VSkeletonLoader.js.map +1 -1
- package/dist/components/VSkeletonLoader/VSkeletonLoader.vue_vue_type_script_setup_true_lang.js +0 -6
- 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 +107 -112
- 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.d.ts +0 -3
- package/dist/components/VSplitButton/VSplitButton.js.map +1 -1
- package/dist/components/VSplitButton/VSplitButton.vue_vue_type_script_setup_true_lang.js +0 -6
- 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 +0 -2
- 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.css +1 -1
- package/dist/components/VTabs/VTabs.d.ts +0 -3
- package/dist/components/VTabs/VTabs.js.map +1 -1
- package/dist/components/VTabs/VTabs.vue_vue_type_script_setup_true_lang.js +2 -15
- package/dist/components/VTabs/VTabs.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTabs/context.d.ts +0 -2
- package/dist/components/VTabs/context.js.map +1 -1
- package/dist/components/VTextarea/VTextarea.d.ts +0 -6
- package/dist/components/VTextarea/VTextarea.js.map +1 -1
- package/dist/components/VTextarea/VTextarea.vue_vue_type_script_setup_true_lang.js +0 -6
- package/dist/components/VTextarea/VTextarea.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTimeInput/VTimeInput.d.ts +0 -3
- package/dist/components/VTimeInput/VTimeInput.js.map +1 -1
- package/dist/components/VTimeInput/VTimeInput.vue_vue_type_script_setup_true_lang.js +197 -204
- 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 +9 -9
- 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.d.ts +0 -3
- package/dist/components/VToggle/VToggle.js.map +1 -1
- package/dist/components/VToggle/VToggle.vue_vue_type_script_setup_true_lang.js +1 -13
- 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 +1 -5
- 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.d.ts +1 -5
- package/dist/composables/useControlShape.js +0 -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.map +1 -1
- package/dist/composables/useIconClickHandlers.js.map +1 -1
- package/dist/composables/useInertLink.js.map +1 -1
- package/dist/composables/useInfiniteScroll.js +2 -2
- package/dist/composables/useInfiniteScroll.js.map +1 -1
- package/dist/composables/useListbox.d.ts +0 -1
- package/dist/composables/useListbox.js +4 -10
- 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.js.map +1 -1
- 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.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/tokens/css.js.map +1 -1
- package/dist/tokens/index.d.ts +3 -0
- package/dist/tokens/index.js.map +1 -1
- package/dist/tokens/primitives.js.map +1 -1
- package/dist/tokens/semantic.d.ts +3 -0
- package/dist/tokens/semantic.js +6 -5
- 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/tokens.json +12 -5
- package/dist/types.d.ts +0 -2
- 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.d.ts +4 -6
- package/dist/utils/chip.js +8 -5
- 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.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
|
@@ -15,7 +15,6 @@ import { computed as f, createBlock as p, createCommentVNode as m, createElement
|
|
|
15
15
|
//#region src/components/VInput/VInput.vue?vue&type=script&setup=true&lang.ts
|
|
16
16
|
var M = [
|
|
17
17
|
"data-size",
|
|
18
|
-
"data-compact",
|
|
19
18
|
"data-disabled",
|
|
20
19
|
"data-readonly"
|
|
21
20
|
], N = ["aria-label", "disabled"], P = [
|
|
@@ -28,10 +27,6 @@ var M = [
|
|
|
28
27
|
__name: "VInput",
|
|
29
28
|
props: /*@__PURE__*/ x({
|
|
30
29
|
size: { default: "md" },
|
|
31
|
-
compact: {
|
|
32
|
-
type: Boolean,
|
|
33
|
-
default: !1
|
|
34
|
-
},
|
|
35
30
|
type: { default: "text" },
|
|
36
31
|
invalid: {
|
|
37
32
|
type: Boolean,
|
|
@@ -98,7 +93,7 @@ var M = [
|
|
|
98
93
|
"clear"
|
|
99
94
|
], ["update:modelValue"]),
|
|
100
95
|
setup(v, { expose: x, emit: R }) {
|
|
101
|
-
let z = v, B = R, V = O(v, "modelValue"), H = f(() => String(V.value ?? "")), { rootClass: ae, rootStyle: U, forwardedAttrs: W } = o(),
|
|
96
|
+
let z = v, B = R, V = O(v, "modelValue"), H = f(() => String(V.value ?? "")), { rootClass: ae, rootStyle: U, forwardedAttrs: W } = o(), G = b(d, null), { size: K, disabled: q } = i(z, G), J = e(), oe = f(() => z.clearLabel ?? J.value.common.clear), Y = D(), { hasIconStartHandler: se, hasIconEndHandler: ce } = te({
|
|
102
97
|
name: "VInput",
|
|
103
98
|
iconStartLabel: z.iconStartLabel,
|
|
104
99
|
iconEndLabel: z.iconEndLabel
|
|
@@ -150,8 +145,7 @@ var M = [
|
|
|
150
145
|
}), ne({
|
|
151
146
|
default: A(({ fieldProps: o }) => [g("div", {
|
|
152
147
|
class: "v-input-field v-control",
|
|
153
|
-
"data-size": E(
|
|
154
|
-
"data-compact": E(K) ? "" : void 0,
|
|
148
|
+
"data-size": E(K),
|
|
155
149
|
"data-disabled": E(q) ? "" : void 0,
|
|
156
150
|
"data-readonly": v.readonly ? "" : void 0
|
|
157
151
|
}, [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VInput.vue_vue_type_script_setup_true_lang.js","names":["$slots"],"sources":["../../../src/components/VInput/VInput.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @core\n/**\n * Native input owns typing and validity. JavaScript bridges the model and restores focus after\n * the clear button disappears.\n */\nimport { computed, inject, ref, useId } from 'vue'\n\nimport VField from '../VField/VField.vue'\nimport type { FieldControlProps, FieldLabelPosition } from '../VField/VField.vue'\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconName, iconProps } from '../VIcon/iconProps'\nimport { close as closeIcon } from '../VIcon/icons/close'\nimport type { IconSource } from '../VIcon/types'\nimport VSpinner from '../VSpinner/VSpinner.vue'\n\nimport { useIconClickHandlers } from '../../composables/useIconClickHandlers'\nimport { useClearable } from '../../composables/useClearable'\nimport { useControlShape } from '../../composables/useControlShape'\nimport { useRootAttrs } from '../../composables/useRootAttrs'\nimport { useTextLimit } from '../../composables/useTextLimit'\nimport { useMessages } from '../../i18n/state'\nimport { joinIds } from '../../utils/ids'\n\nimport { inputGroupKey } from './context'\n\n/** The height of the field: 32, 40 or 48 pixels. */\nexport type InputSize = 'sm' | 'md' | 'lg'\n\n/** The native type of the input, which also decides the keyboard a phone offers. */\nexport type InputType = 'text' | 'email' | 'number' | 'password' | 'search' | 'tel' | 'url'\n\n/**\n * What the `#control` slot hands over, to bind on the element replacing the input: its id, which\n * the label points at, the class the field's states are drawn from, the references to the hint\n * and the error, and the attributes set on the field other than `class` and `style`. `required`\n * is left out: the replacing element states it in its own way.\n */\nexport type InputControlProps = {\n id: string\n class: string\n disabled: boolean\n 'aria-invalid'?: 'true'\n 'aria-describedby'?: string\n} & Record<string, unknown>\n\ninterface InputProps {\n /** The height of the field: 32, 40 or 48 pixels. */\n size?: InputSize\n /** Takes 4px off the height, leaving the padding, the text and the icons as they are. */\n compact?: boolean\n /**\n * The native type of the input, which is also what tells a phone which keyboard to\n * offer: a numeric pad for `number`, an @ key for `email`.\n */\n type?: InputType\n /** Marks the field as invalid whatever the browser thinks. */\n invalid?: boolean\n /** Makes the field unusable, greyed out through the colour tokens. */\n disabled?: boolean\n /**\n * Shows the value without allowing it to be changed. The field can still be\n * focused and copied from, and it hides the clear button, unless `clearVisible`\n * answers that question explicitly.\n */\n readonly?: boolean\n /**\n * Refuses the keyboard without drawing the field as read-only: the native attribute is set,\n * but the field keeps its ordinary look and its clear cross.\n */\n noTyping?: boolean\n /** The label, tied to the field so that clicking it focuses the field. */\n label?: string\n /**\n * A line of help under the field. It is tied to the input for assistive\n * technology, so it is read out along with the label.\n */\n hint?: string\n /**\n * A message saying what is wrong with the value, shown in place of the hint so that the field\n * does not grow. It marks the field invalid, is read along with it, and is announced when it\n * appears or changes.\n */\n error?: string\n /** Marks the field as required: an asterisk follows the label, and the input is `required`. */\n required?: boolean\n /** Hides the label visually. It still names the field for assistive technology. */\n hideLabel?: boolean\n /**\n * Where the label sits: above the field (`top`, the default), or at its start, in a column of\n * its own, moving back above when there is not room for both.\n */\n labelPosition?: FieldLabelPosition\n /**\n * An icon inside the field, at the start. It is decorative by default and becomes a real\n * button as soon as a `@click:icon-start` listener is attached, in which case it needs\n * `iconStartLabel`.\n */\n iconStart?: IconSource\n /**\n * The same at the end of the field. The `#end` slot replaces it, and the loading\n * spinner takes its place while it turns.\n */\n iconEnd?: IconSource\n /** What the start icon does, in words, once it is clickable. */\n iconStartLabel?: string\n /** What the end icon does, in words, once it is clickable. */\n iconEndLabel?: string\n /** Shows a spinner at the end of the field, in place of the end icon or slot. */\n loading?: boolean\n /**\n * What screen readers announce while the spinner turns. It falls back to the\n * design system dictionary.\n */\n loadingText?: string\n /**\n * Offers a cross that empties the field. It appears when there is something to\n * clear and the field can be edited.\n */\n clearable?: boolean\n /**\n * Decides whether the cross is shown, instead of letting the field work it out\n * from its own content (a read-only field included).\n *\n * It exists for the components built on top of this one, where what there is to\n * clear is not the text: VCombobox holds its selection as chips beside the field,\n * and a read-only date or time picker changes its value through a panel rather\n * than by typing.\n */\n clearVisible?: boolean\n /** What the clear button does, in words. It falls back to the design system dictionary. */\n clearLabel?: string\n /**\n * The maximum number of characters. By default this is the browser's own limit,\n * which simply refuses anything beyond it.\n */\n maxlength?: number\n /**\n * Turns that limit into a soft one: the reader may type past it, and the field goes into\n * error instead of silently refusing the keystrokes.\n */\n softLimit?: boolean\n /**\n * Shows how much has been typed, at the end of the field: \"12/80\" against a limit,\n * or just \"12\" without one.\n */\n counter?: boolean\n}\n\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<InputProps>(), {\n size: 'md',\n compact: false,\n type: 'text',\n invalid: false,\n disabled: false,\n readonly: false,\n label: undefined,\n hint: undefined,\n error: undefined,\n required: false,\n hideLabel: false,\n labelPosition: 'top',\n iconStart: undefined,\n iconEnd: undefined,\n iconStartLabel: undefined,\n iconEndLabel: undefined,\n loading: false,\n loadingText: undefined,\n clearable: false,\n clearVisible: undefined,\n clearLabel: undefined,\n maxlength: undefined,\n softLimit: false,\n noTyping: false,\n counter: false,\n})\n\nconst emit = defineEmits<{\n /** The start icon was clicked. Attaching this listener is what makes it a button. */\n 'click:icon-start': [event: MouseEvent]\n /** The end icon was clicked. Attaching this listener is what makes it a button. */\n 'click:icon-end': [event: MouseEvent]\n /** The clear button was pressed. The field has already been emptied. */\n clear: []\n}>()\n\ndefineSlots<{\n /**\n * Content at the start of the field, rendered after `iconStart` rather than in its place,\n * which lets a field composed on top of this one put the chips standing for its values here\n * beside an icon it still wants drawn.\n */\n start?(): unknown\n /**\n * Controls of your own inside the field, placed before the field's own: the clear cross and\n * the end icon.\n */\n 'value-end'?(): unknown\n /**\n * Replaces the input with another control, for a field composed on top of this one: VSelect\n * puts its button here. Bind `controlProps` on it; the field then draws its focus, invalid and\n * disabled states from that control. The model, the limit and the counter apply to the input\n * alone.\n */\n control?(props: { controlProps: InputControlProps }): unknown\n /**\n * Content at the end of the field, which replaces `iconEnd`. It is hidden while\n * the field is loading, the spinner taking that place.\n */\n end?(): unknown\n /**\n * Content at the end of the hint's line, under the field. Bind `id` on it: it joins the\n * field's description, after the error and the hint.\n */\n meta?(props: { id: string }): unknown\n}>()\n\n/** The value, typed as text or a number rather than text alone. */\nconst model = defineModel<string | number>({ default: '' })\n\n/**\n * The value seen as text. Every measurement of its length; the counter, the soft limit, whether\n * the clear cross has anything to clear; goes through this, since a number has no length of its\n * own.\n */\nconst modelText = computed(() => String(model.value ?? ''))\n\nconst { rootClass, rootStyle, forwardedAttrs: restAttrs } = useRootAttrs()\n\n// `disabled` is the one read as an or, the two answers being cumulative (VInput/context.ts).\nconst group = inject(inputGroupKey, null)\nconst {\n size: resolvedSize,\n compact: resolvedCompact,\n disabled: resolvedDisabled,\n} = useControlShape(props, group)\n\n// The prop keeps priority; what it falls back to is the dictionary, so the default\n// wording follows the language the design system is set to.\nconst m = useMessages()\nconst resolvedClearLabel = computed(() => props.clearLabel ?? m.value.common.clear)\n\nconst counterId = useId()\n\nconst { hasIconStartHandler, hasIconEndHandler } = useIconClickHandlers({\n name: 'VInput',\n iconStartLabel: props.iconStartLabel,\n iconEndLabel: props.iconEndLabel,\n})\n\nconst controlEl = ref<HTMLInputElement | null>(null)\n\nconst { showClear, onClear } = useClearable({\n clearable: () => props.clearable,\n clearVisible: () => props.clearVisible,\n disabled: () => resolvedDisabled.value,\n readonly: () => props.readonly,\n text: () => modelText.value,\n controlEl,\n onCleared: () => {\n model.value = ''\n emit('clear')\n },\n})\n\n// The counter and the soft limit both measure `modelText` rather than the model\n// itself, a number having no length.\nconst { counterText, over } = useTextLimit({\n el: controlEl,\n text: () => modelText.value,\n maxlength: () => props.maxlength,\n softLimit: () => props.softLimit,\n})\n\n/**\n * The attributes of the input, built on VField's: the consumer's attributes win over the\n * `invalid` prop, and the counter inside the field joins the description last.\n */\nfunction inputAttrs(fieldProps: FieldControlProps): FieldControlProps {\n return {\n 'aria-invalid': props.invalid ? 'true' : undefined,\n ...fieldProps,\n 'aria-describedby': joinIds(fieldProps['aria-describedby'], props.counter && counterId),\n }\n}\n\nfunction controlProps(fieldProps: FieldControlProps): InputControlProps {\n const bound = inputAttrs(fieldProps)\n delete bound.required\n return { ...bound, class: 'v-input-control', disabled: resolvedDisabled.value }\n}\n\n// The real input sits inside the wrapper, out of reach of whoever renders this component. These\n// three are how the components built on it get there; VCombobox refocuses the field and selects\n// its text this way.\ndefineExpose({\n /** Moves the focus to the real input. */\n focus: (options?: FocusOptions) => controlEl.value?.focus(options),\n /** Selects everything in the field, as VCombobox does when it reopens its panel. */\n select: () => controlEl.value?.select(),\n /** The real `<input>`, for what neither of the two above covers. */\n el: controlEl,\n})\n</script>\n\n<template>\n <VField\n v-bind=\"restAttrs\"\n class=\"v-input\"\n :class=\"rootClass\"\n :style=\"rootStyle\"\n :label=\"label\"\n :hint=\"hint\"\n :error=\"error\"\n :required=\"required\"\n :disabled=\"resolvedDisabled\"\n :hide-label=\"hideLabel\"\n :label-position=\"labelPosition\"\n >\n <template #default=\"{ fieldProps }\">\n <div\n class=\"v-input-field v-control\"\n :data-size=\"resolvedSize\"\n :data-compact=\"resolvedCompact ? '' : undefined\"\n :data-disabled=\"resolvedDisabled ? '' : undefined\"\n :data-readonly=\"readonly ? '' : undefined\"\n >\n <!--\n The start icon is rendered before the slot, where the end icon is the slot's own\n fallback. That asymmetry is what the composed fields need: VCombobox and VFileInput fill\n `#start` with the chips standing for their values, which is OTHER content in the same\n zone rather than another way of drawing the icon.\n -->\n <button\n v-if=\"iconStart && hasIconStartHandler\"\n type=\"button\"\n class=\"v-input-action v-field-action v-input-icon-start\"\n :aria-label=\"iconStartLabel ?? iconName(iconStart)\"\n :disabled=\"resolvedDisabled\"\n @click=\"emit('click:icon-start', $event)\"\n >\n <VIcon v-bind=\"iconProps(iconStart)\" />\n </button>\n <VIcon v-else-if=\"iconStart\" v-bind=\"iconProps(iconStart)\" class=\"v-input-icon-start\" />\n <slot name=\"start\" />\n\n <slot name=\"control\" :control-props=\"controlProps(fieldProps)\">\n <!-- The label's `for` matches the id inside fieldProps, which the rule cannot follow. -->\n <!-- eslint-disable-next-line vuejs-accessibility/form-control-has-label -->\n <input\n ref=\"controlEl\"\n v-model=\"model\"\n v-bind=\"inputAttrs(fieldProps)\"\n class=\"v-input-control\"\n :type=\"type\"\n :maxlength=\"softLimit ? undefined : maxlength\"\n :disabled=\"resolvedDisabled\"\n :readonly=\"readonly || noTyping || undefined\"\n />\n </slot>\n\n <span\n v-if=\"counter\"\n :id=\"counterId\"\n class=\"v-input-counter v-field-counter\"\n :data-over=\"over ? '' : undefined\"\n >\n {{ counterText }}\n </span>\n\n <!-- Before the clear cross rather than after it, so that a consumer's control reads\n and tabs in the same order: what acts on the value sits next to the value, and\n the field's own controls stay together at the end. -->\n <slot name=\"value-end\" />\n\n <button\n v-if=\"showClear\"\n type=\"button\"\n class=\"v-input-action v-field-action v-input-clear\"\n :aria-label=\"resolvedClearLabel\"\n @click=\"onClear\"\n >\n <VIcon :name=\"closeIcon\" />\n </button>\n\n <VSpinner v-if=\"loading\" :label=\"loadingText\" />\n <slot v-else name=\"end\">\n <button\n v-if=\"iconEnd && hasIconEndHandler\"\n type=\"button\"\n class=\"v-input-action v-field-action v-input-icon-end\"\n :aria-label=\"iconEndLabel ?? iconName(iconEnd)\"\n :disabled=\"resolvedDisabled\"\n @click=\"emit('click:icon-end', $event)\"\n >\n <VIcon v-bind=\"iconProps(iconEnd)\" />\n </button>\n <VIcon v-else-if=\"iconEnd\" v-bind=\"iconProps(iconEnd)\" class=\"v-input-icon-end\" />\n </slot>\n </div>\n </template>\n <template v-if=\"$slots.meta\" #meta=\"{ id }\"><slot :id=\"id\" name=\"meta\" /></template>\n </VField>\n</template>\n\n<style>\n@layer vectis.components {\n /* The root is a VField, which lays out the label, the hint and the error. */\n .v-input {\n width: 100%;\n }\n\n /*\n * This is the box that carries the border, the background and the focus ring, and the size and\n * state attributes. `--field-border-color` is the single source of truth for its colour, and the hover, error\n * and disabled states do nothing but redefine it.\n */\n .v-input-field {\n --field-border-color: var(--vectis-color-border-strong);\n\n display: flex;\n align-items: center;\n gap: var(--control-gap);\n height: var(--control-height);\n padding-inline: var(--control-padding-inline-field);\n background: var(--vectis-color-surface);\n color: var(--vectis-color-text);\n border: 1px solid var(--field-border-color);\n border-radius: var(--vectis-radius-interactive);\n font-size: var(--control-font-size);\n transition:\n border-color var(--vectis-duration-fast) var(--vectis-ease-default),\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 .v-input-control {\n flex: 1;\n min-width: 0;\n height: 100%;\n padding: 0;\n border: none;\n background: none;\n color: inherit;\n font: inherit;\n outline: none; /* The focus ring is drawn by the field around it, not here */\n }\n\n .v-input-control::placeholder {\n color: var(--vectis-color-text-subtle);\n }\n\n /* The browsers' own in-field controls are removed, because the design system draws\n its own: WebKit's search cross would sit beside the `clearable` one, the number\n spinners and Edge's password-reveal eye would clash with the icons. */\n .v-input-control::-webkit-search-cancel-button,\n .v-input-control::-webkit-search-decoration,\n .v-input-control::-webkit-search-results-button,\n .v-input-control::-webkit-search-results-decoration,\n .v-input-control::-webkit-inner-spin-button,\n .v-input-control::-webkit-outer-spin-button {\n -webkit-appearance: none;\n appearance: none;\n }\n\n .v-input-control[type='number'] {\n appearance: textfield;\n }\n\n .v-input-control::-ms-reveal {\n display: none;\n }\n\n /*\n * Its colour cannot be changed, but matching the field's radius at least stops it from\n * showing square corners inside a rounded box.\n */\n .v-input-control:-webkit-autofill {\n border-radius: var(--vectis-radius-interactive);\n }\n\n /*\n * This block must stay first in the sequence of states: read-only, then hover, focus, invalid\n * and disabled. The read-only, focus, invalid and disabled selectors all weigh (0,3,0),\n * `:has()` taking the specificity of what it contains, so nothing but the source order\n * arbitrates between them.\n */\n .v-input .v-input-field[data-readonly] {\n --field-border-color: var(--vectis-color-border);\n\n background: var(--vectis-color-surface-sunken);\n }\n\n .v-input-field:hover:not(:has(.v-input-control:focus)):not(\n :has(\n .v-input-control:disabled,\n .v-input-control:user-invalid,\n .v-input-control[aria-invalid='true']\n )\n ) {\n --field-border-color: color-mix(\n in oklab,\n var(--vectis-color-border-strong),\n var(--vectis-color-text) 15%\n );\n }\n\n /*\n * The selector watches the control's focus and not `:focus-within`, so that when one of the\n * field's own buttons; the cross, a clickable icon; takes keyboard focus, only that button's\n * outline lights up: two indicators at once would be unreadable. And it is `:focus` rather\n * than `:focus-visible`, because a text field shows its focus even when it was reached with\n * the mouse.\n */\n .v-input-field:has(.v-input-control:focus) {\n --field-border-color: var(--vectis-color-accent);\n\n box-shadow: 0 0 0 1px var(--field-border-color);\n outline: var(--vectis-focus-ring-width) solid transparent;\n }\n\n /*\n * Only the colour variable is changed, which is why the border and the focus ring both turn\n * red without either being restated.\n */\n .v-input-field:has(.v-input-control:user-invalid),\n .v-input-field:has(.v-input-control[aria-invalid='true']) {\n --field-border-color: var(--vectis-color-danger);\n }\n\n /* Inside the box it must not shrink, or a long value would squeeze its figures. */\n .v-input-counter {\n flex: none;\n }\n\n /* A decorative icon is drawn in a muted grey, so it stays quieter than the text\n being typed beside it. */\n .v-input-field > .v-icon {\n color: var(--vectis-color-text-muted);\n }\n\n .v-input-field > .v-spinner {\n font-size: var(--vectis-icon-size);\n }\n\n /*\n * A disabled field greys out through the colour tokens, the same ones VCheckbox and VRadio\n * use, and never through opacity. It comes last in the sequence of states, which at equal\n * specificity is what makes it win over all of them, the error included: a disabled field is\n * not submitted, so it has nothing to report.\n */\n .v-input .v-input-field[data-disabled] {\n --field-border-color: var(--vectis-color-border);\n\n background: var(--vectis-color-surface-muted);\n color: var(--vectis-color-text-muted);\n cursor: not-allowed;\n }\n\n .v-input-field[data-disabled] .v-input-counter {\n color: var(--vectis-color-text-subtle);\n }\n\n .v-input-field[data-disabled] .v-input-action,\n .v-input-field[data-disabled] > .v-icon {\n color: inherit;\n cursor: not-allowed;\n }\n\n .v-input-control:disabled {\n cursor: not-allowed;\n }\n\n /*\n * They live in this sheet because it is the one both are guaranteed to load, being built on\n * VInput; the core sheet would charge every consumer for them. `.v-input-end-pinned` lifts\n * the clear cross and whatever carries `.v-input-icon-end`; the end icon, or a composed\n * field's own chevron and spinner; out of the flow, so they stay pinned to the end of the\n * field and vertically centred whatever the chips do.\n */\n .v-input-end-pinned .v-input-field {\n position: relative;\n }\n\n .v-input-end-pinned .v-input-field:has(> :is(.v-input-clear, .v-input-icon-end, .v-spinner)) {\n padding-inline-end: calc(\n var(--control-padding-inline-field) + var(--vectis-icon-size) + var(--control-gap)\n );\n }\n\n .v-input-end-pinned\n .v-input-field:has(> .v-input-clear):has(> :is(.v-input-icon-end, .v-spinner)) {\n padding-inline-end: calc(\n var(--control-padding-inline-field) + 2 * var(--vectis-icon-size) + 2 * var(--control-gap)\n );\n }\n\n .v-input-end-pinned :is(.v-input-clear, .v-input-icon-end) {\n position: absolute;\n inset-inline-end: var(--control-padding-inline-field);\n top: 50%;\n translate: 0 -50%;\n }\n\n /*\n * This inset reads in glyphs and not in buttons. The cross is one of the field's buttons,\n * whose negative margin; half the difference between icon and button; already cancels its own\n * overhang, so an inset lands on the glyph's edge.\n */\n .v-input-end-pinned .v-input-clear:has(~ :is(.v-input-icon-end, .v-spinner)) {\n inset-inline-end: calc(\n var(--control-padding-inline-field) + var(--vectis-icon-size) + var(--control-gap)\n );\n }\n\n /*\n * The control rule must stay at (0,2,0). VCombobox folds its search input away with a (0,3,0)\n * rule that zeroes this height, and at equal weight the winner would be whichever of the two\n * sheets a bundler put last.\n */\n .v-input-chips .v-input-field {\n flex-wrap: wrap;\n height: auto;\n min-height: var(--control-height);\n padding-block: var(--vectis-space-1);\n }\n\n .v-input-chips .v-input-control {\n height: var(--chip-height);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-input-field {\n transition: none;\n }\n }\n}\n</style>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"VInput.vue_vue_type_script_setup_true_lang.js","names":["$slots","_useModel","_openBlock","_createBlock","VField","_mergeProps","_unref","_createSlots","_withCtx","_createElementVNode","_createElementBlock","_createVNode","VIcon","_normalizeProps","_guardReactiveProps","_createCommentVNode","_renderSlot","_withDirectives","_vModelDynamic","_toDisplayString","closeIcon","VSpinner","VIcon_default","VSpinner_default","VField_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","VInput_vue_vue_type_script_setup_true_lang_default","\"modelValue\"","\"modelModifiers\"","__expose","__emit","props","__props","emit","model","useModel","modelText","computed","restAttrs","useRootAttrs","group","inject","inputGroupKey","resolvedSize","resolvedDisabled","useControlShape","m","useMessages","resolvedClearLabel","counterId","useId","useIconClickHandlers","controlEl","ref","useClearable","useTextLimit","inputAttrs","fieldProps","joinIds","controlProps","bound","options","openBlock","createBlock","mergeProps","unref","rootClass","rootStyle","createSlots","withCtx","createElementVNode","hasIconStartHandler","createElementBlock","iconName","_cache","$event","createVNode","normalizeProps","guardReactiveProps","iconProps","createCommentVNode","renderSlot","_ctx","withDirectives","vModelDynamic","over","toDisplayString","counterText","showClear","args","onClear","close","hasIconEndHandler"],"sources":["../../../src/components/VInput/VInput.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @core\n/**\n * Native input owns typing and validity. JavaScript bridges the model and restores focus after\n * the clear button disappears.\n */\nimport { computed, inject, ref, useId } from 'vue'\n\nimport VField from '../VField/VField.vue'\nimport type { FieldControlProps, FieldLabelPosition } from '../VField/VField.vue'\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconName, iconProps } from '../VIcon/iconProps'\nimport { close as closeIcon } from '../VIcon/icons/close'\nimport type { IconSource } from '../VIcon/types'\nimport VSpinner from '../VSpinner/VSpinner.vue'\n\nimport { useIconClickHandlers } from '../../composables/useIconClickHandlers'\nimport { useClearable } from '../../composables/useClearable'\nimport { useControlShape } from '../../composables/useControlShape'\nimport { useRootAttrs } from '../../composables/useRootAttrs'\nimport { useTextLimit } from '../../composables/useTextLimit'\nimport { useMessages } from '../../i18n/state'\nimport { joinIds } from '../../utils/ids'\n\nimport { inputGroupKey } from './context'\n\n/** The height of the field: 32, 40 or 48 pixels. */\nexport type InputSize = 'sm' | 'md' | 'lg'\n\n/** The native type of the input, which also decides the keyboard a phone offers. */\nexport type InputType = 'text' | 'email' | 'number' | 'password' | 'search' | 'tel' | 'url'\n\n/**\n * What the `#control` slot hands over, to bind on the element replacing the input: its id, which\n * the label points at, the class the field's states are drawn from, the references to the hint\n * and the error, and the attributes set on the field other than `class` and `style`. `required`\n * is left out: the replacing element states it in its own way.\n */\nexport type InputControlProps = {\n id: string\n class: string\n disabled: boolean\n 'aria-invalid'?: 'true'\n 'aria-describedby'?: string\n} & Record<string, unknown>\n\ninterface InputProps {\n /** The height of the field: 32, 40 or 48 pixels. */\n size?: InputSize\n /**\n * The native type of the input, which is also what tells a phone which keyboard to\n * offer: a numeric pad for `number`, an @ key for `email`.\n */\n type?: InputType\n /** Marks the field as invalid whatever the browser thinks. */\n invalid?: boolean\n /** Makes the field unusable, greyed out through the colour tokens. */\n disabled?: boolean\n /**\n * Shows the value without allowing it to be changed. The field can still be\n * focused and copied from, and it hides the clear button, unless `clearVisible`\n * answers that question explicitly.\n */\n readonly?: boolean\n /**\n * Refuses the keyboard without drawing the field as read-only: the native attribute is set,\n * but the field keeps its ordinary look and its clear cross.\n */\n noTyping?: boolean\n /** The label, tied to the field so that clicking it focuses the field. */\n label?: string\n /**\n * A line of help under the field. It is tied to the input for assistive\n * technology, so it is read out along with the label.\n */\n hint?: string\n /**\n * A message saying what is wrong with the value, shown in place of the hint so that the field\n * does not grow. It marks the field invalid, is read along with it, and is announced when it\n * appears or changes.\n */\n error?: string\n /** Marks the field as required: an asterisk follows the label, and the input is `required`. */\n required?: boolean\n /** Hides the label visually. It still names the field for assistive technology. */\n hideLabel?: boolean\n /**\n * Where the label sits: above the field (`top`, the default), or at its start, in a column of\n * its own, moving back above when there is not room for both.\n */\n labelPosition?: FieldLabelPosition\n /**\n * An icon inside the field, at the start. It is decorative by default and becomes a real\n * button as soon as a `@click:icon-start` listener is attached, in which case it needs\n * `iconStartLabel`.\n */\n iconStart?: IconSource\n /**\n * The same at the end of the field. The `#end` slot replaces it, and the loading\n * spinner takes its place while it turns.\n */\n iconEnd?: IconSource\n /** What the start icon does, in words, once it is clickable. */\n iconStartLabel?: string\n /** What the end icon does, in words, once it is clickable. */\n iconEndLabel?: string\n /** Shows a spinner at the end of the field, in place of the end icon or slot. */\n loading?: boolean\n /**\n * What screen readers announce while the spinner turns. It falls back to the\n * design system dictionary.\n */\n loadingText?: string\n /**\n * Offers a cross that empties the field. It appears when there is something to\n * clear and the field can be edited.\n */\n clearable?: boolean\n /**\n * Decides whether the cross is shown, instead of letting the field work it out\n * from its own content (a read-only field included).\n *\n * It exists for the components built on top of this one, where what there is to\n * clear is not the text: VCombobox holds its selection as chips beside the field,\n * and a read-only date or time picker changes its value through a panel rather\n * than by typing.\n */\n clearVisible?: boolean\n /** What the clear button does, in words. It falls back to the design system dictionary. */\n clearLabel?: string\n /**\n * The maximum number of characters. By default this is the browser's own limit,\n * which simply refuses anything beyond it.\n */\n maxlength?: number\n /**\n * Turns that limit into a soft one: the reader may type past it, and the field goes into\n * error instead of silently refusing the keystrokes.\n */\n softLimit?: boolean\n /**\n * Shows how much has been typed, at the end of the field: \"12/80\" against a limit,\n * or just \"12\" without one.\n */\n counter?: boolean\n}\n\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<InputProps>(), {\n size: 'md',\n type: 'text',\n invalid: false,\n disabled: false,\n readonly: false,\n label: undefined,\n hint: undefined,\n error: undefined,\n required: false,\n hideLabel: false,\n labelPosition: 'top',\n iconStart: undefined,\n iconEnd: undefined,\n iconStartLabel: undefined,\n iconEndLabel: undefined,\n loading: false,\n loadingText: undefined,\n clearable: false,\n clearVisible: undefined,\n clearLabel: undefined,\n maxlength: undefined,\n softLimit: false,\n noTyping: false,\n counter: false,\n})\n\nconst emit = defineEmits<{\n /** The start icon was clicked. Attaching this listener is what makes it a button. */\n 'click:icon-start': [event: MouseEvent]\n /** The end icon was clicked. Attaching this listener is what makes it a button. */\n 'click:icon-end': [event: MouseEvent]\n /** The clear button was pressed. The field has already been emptied. */\n clear: []\n}>()\n\ndefineSlots<{\n /**\n * Content at the start of the field, rendered after `iconStart` rather than in its place,\n * which lets a field composed on top of this one put the chips standing for its values here\n * beside an icon it still wants drawn.\n */\n start?(): unknown\n /**\n * Controls of your own inside the field, placed before the field's own: the clear cross and\n * the end icon.\n */\n 'value-end'?(): unknown\n /**\n * Replaces the input with another control, for a field composed on top of this one: VSelect\n * puts its button here. Bind `controlProps` on it; the field then draws its focus, invalid and\n * disabled states from that control. The model, the limit and the counter apply to the input\n * alone.\n */\n control?(props: { controlProps: InputControlProps }): unknown\n /**\n * Content at the end of the field, which replaces `iconEnd`. It is hidden while\n * the field is loading, the spinner taking that place.\n */\n end?(): unknown\n /**\n * Content at the end of the hint's line, under the field. Bind `id` on it: it joins the\n * field's description, after the error and the hint.\n */\n meta?(props: { id: string }): unknown\n}>()\n\n/** The value, typed as text or a number rather than text alone. */\nconst model = defineModel<string | number>({ default: '' })\n\n/**\n * The value seen as text. Every measurement of its length; the counter, the soft limit, whether\n * the clear cross has anything to clear; goes through this, since a number has no length of its\n * own.\n */\nconst modelText = computed(() => String(model.value ?? ''))\n\nconst { rootClass, rootStyle, forwardedAttrs: restAttrs } = useRootAttrs()\n\n// `disabled` is the one read as an or, the two answers being cumulative (VInput/context.ts).\nconst group = inject(inputGroupKey, null)\nconst { size: resolvedSize, disabled: resolvedDisabled } = useControlShape(props, group)\n\n// The prop keeps priority; what it falls back to is the dictionary, so the default\n// wording follows the language the design system is set to.\nconst m = useMessages()\nconst resolvedClearLabel = computed(() => props.clearLabel ?? m.value.common.clear)\n\nconst counterId = useId()\n\nconst { hasIconStartHandler, hasIconEndHandler } = useIconClickHandlers({\n name: 'VInput',\n iconStartLabel: props.iconStartLabel,\n iconEndLabel: props.iconEndLabel,\n})\n\nconst controlEl = ref<HTMLInputElement | null>(null)\n\nconst { showClear, onClear } = useClearable({\n clearable: () => props.clearable,\n clearVisible: () => props.clearVisible,\n disabled: () => resolvedDisabled.value,\n readonly: () => props.readonly,\n text: () => modelText.value,\n controlEl,\n onCleared: () => {\n model.value = ''\n emit('clear')\n },\n})\n\n// The counter and the soft limit both measure `modelText` rather than the model\n// itself, a number having no length.\nconst { counterText, over } = useTextLimit({\n el: controlEl,\n text: () => modelText.value,\n maxlength: () => props.maxlength,\n softLimit: () => props.softLimit,\n})\n\n/**\n * The attributes of the input, built on VField's: the consumer's attributes win over the\n * `invalid` prop, and the counter inside the field joins the description last.\n */\nfunction inputAttrs(fieldProps: FieldControlProps): FieldControlProps {\n return {\n 'aria-invalid': props.invalid ? 'true' : undefined,\n ...fieldProps,\n 'aria-describedby': joinIds(fieldProps['aria-describedby'], props.counter && counterId),\n }\n}\n\nfunction controlProps(fieldProps: FieldControlProps): InputControlProps {\n const bound = inputAttrs(fieldProps)\n delete bound.required\n return { ...bound, class: 'v-input-control', disabled: resolvedDisabled.value }\n}\n\n// The real input sits inside the wrapper, out of reach of whoever renders this component. These\n// three are how the components built on it get there; VCombobox refocuses the field and selects\n// its text this way.\ndefineExpose({\n /** Moves the focus to the real input. */\n focus: (options?: FocusOptions) => controlEl.value?.focus(options),\n /** Selects everything in the field, as VCombobox does when it reopens its panel. */\n select: () => controlEl.value?.select(),\n /** The real `<input>`, for what neither of the two above covers. */\n el: controlEl,\n})\n</script>\n\n<template>\n <VField\n v-bind=\"restAttrs\"\n class=\"v-input\"\n :class=\"rootClass\"\n :style=\"rootStyle\"\n :label=\"label\"\n :hint=\"hint\"\n :error=\"error\"\n :required=\"required\"\n :disabled=\"resolvedDisabled\"\n :hide-label=\"hideLabel\"\n :label-position=\"labelPosition\"\n >\n <template #default=\"{ fieldProps }\">\n <div\n class=\"v-input-field v-control\"\n :data-size=\"resolvedSize\"\n :data-disabled=\"resolvedDisabled ? '' : undefined\"\n :data-readonly=\"readonly ? '' : undefined\"\n >\n <!--\n The start icon is rendered before the slot, where the end icon is the slot's own\n fallback. That asymmetry is what the composed fields need: VCombobox and VFileInput fill\n `#start` with the chips standing for their values, which is OTHER content in the same\n zone rather than another way of drawing the icon.\n -->\n <button\n v-if=\"iconStart && hasIconStartHandler\"\n type=\"button\"\n class=\"v-input-action v-field-action v-input-icon-start\"\n :aria-label=\"iconStartLabel ?? iconName(iconStart)\"\n :disabled=\"resolvedDisabled\"\n @click=\"emit('click:icon-start', $event)\"\n >\n <VIcon v-bind=\"iconProps(iconStart)\" />\n </button>\n <VIcon v-else-if=\"iconStart\" v-bind=\"iconProps(iconStart)\" class=\"v-input-icon-start\" />\n <slot name=\"start\" />\n\n <slot name=\"control\" :control-props=\"controlProps(fieldProps)\">\n <!-- The label's `for` matches the id inside fieldProps, which the rule cannot follow. -->\n <!-- eslint-disable-next-line vuejs-accessibility/form-control-has-label -->\n <input\n ref=\"controlEl\"\n v-model=\"model\"\n v-bind=\"inputAttrs(fieldProps)\"\n class=\"v-input-control\"\n :type=\"type\"\n :maxlength=\"softLimit ? undefined : maxlength\"\n :disabled=\"resolvedDisabled\"\n :readonly=\"readonly || noTyping || undefined\"\n />\n </slot>\n\n <span\n v-if=\"counter\"\n :id=\"counterId\"\n class=\"v-input-counter v-field-counter\"\n :data-over=\"over ? '' : undefined\"\n >\n {{ counterText }}\n </span>\n\n <!-- Before the clear cross rather than after it, so that a consumer's control reads\n and tabs in the same order: what acts on the value sits next to the value, and\n the field's own controls stay together at the end. -->\n <slot name=\"value-end\" />\n\n <button\n v-if=\"showClear\"\n type=\"button\"\n class=\"v-input-action v-field-action v-input-clear\"\n :aria-label=\"resolvedClearLabel\"\n @click=\"onClear\"\n >\n <VIcon :name=\"closeIcon\" />\n </button>\n\n <VSpinner v-if=\"loading\" :label=\"loadingText\" />\n <slot v-else name=\"end\">\n <button\n v-if=\"iconEnd && hasIconEndHandler\"\n type=\"button\"\n class=\"v-input-action v-field-action v-input-icon-end\"\n :aria-label=\"iconEndLabel ?? iconName(iconEnd)\"\n :disabled=\"resolvedDisabled\"\n @click=\"emit('click:icon-end', $event)\"\n >\n <VIcon v-bind=\"iconProps(iconEnd)\" />\n </button>\n <VIcon v-else-if=\"iconEnd\" v-bind=\"iconProps(iconEnd)\" class=\"v-input-icon-end\" />\n </slot>\n </div>\n </template>\n <template v-if=\"$slots.meta\" #meta=\"{ id }\"><slot :id=\"id\" name=\"meta\" /></template>\n </VField>\n</template>\n\n<style>\n@layer vectis.components {\n /* The root is a VField, which lays out the label, the hint and the error. */\n .v-input {\n width: 100%;\n }\n\n /*\n * This is the box that carries the border, the background and the focus ring, and the size and\n * state attributes. `--field-border-color` is the single source of truth for its colour, and the hover, error\n * and disabled states do nothing but redefine it.\n */\n .v-input-field {\n --field-border-color: var(--vectis-color-border-strong);\n\n display: flex;\n align-items: center;\n gap: var(--control-gap);\n height: var(--control-height);\n padding-inline: var(--control-padding-inline-field);\n background: var(--vectis-color-surface);\n color: var(--vectis-color-text);\n border: 1px solid var(--field-border-color);\n border-radius: var(--vectis-radius-interactive);\n font-size: var(--control-font-size);\n transition:\n border-color var(--vectis-duration-fast) var(--vectis-ease-default),\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 .v-input-control {\n flex: 1;\n min-width: 0;\n height: 100%;\n padding: 0;\n border: none;\n background: none;\n color: inherit;\n font: inherit;\n outline: none; /* The focus ring is drawn by the field around it, not here */\n }\n\n .v-input-control::placeholder {\n color: var(--vectis-color-text-subtle);\n }\n\n /* The browsers' own in-field controls are removed, because the design system draws\n its own: WebKit's search cross would sit beside the `clearable` one, the number\n spinners and Edge's password-reveal eye would clash with the icons. */\n .v-input-control::-webkit-search-cancel-button,\n .v-input-control::-webkit-search-decoration,\n .v-input-control::-webkit-search-results-button,\n .v-input-control::-webkit-search-results-decoration,\n .v-input-control::-webkit-inner-spin-button,\n .v-input-control::-webkit-outer-spin-button {\n -webkit-appearance: none;\n appearance: none;\n }\n\n .v-input-control[type='number'] {\n appearance: textfield;\n }\n\n .v-input-control::-ms-reveal {\n display: none;\n }\n\n /*\n * Its colour cannot be changed, but matching the field's radius at least stops it from\n * showing square corners inside a rounded box.\n */\n .v-input-control:-webkit-autofill {\n border-radius: var(--vectis-radius-interactive);\n }\n\n /*\n * This block must stay first in the sequence of states: read-only, then hover, focus, invalid\n * and disabled. The read-only, focus, invalid and disabled selectors all weigh (0,3,0),\n * `:has()` taking the specificity of what it contains, so nothing but the source order\n * arbitrates between them.\n */\n .v-input .v-input-field[data-readonly] {\n --field-border-color: var(--vectis-color-border);\n\n background: var(--vectis-color-surface-sunken);\n }\n\n .v-input-field:hover:not(:has(.v-input-control:focus)):not(\n :has(\n .v-input-control:disabled,\n .v-input-control:user-invalid,\n .v-input-control[aria-invalid='true']\n )\n ) {\n --field-border-color: color-mix(\n in oklab,\n var(--vectis-color-border-strong),\n var(--vectis-color-text) 15%\n );\n }\n\n /*\n * The selector watches the control's focus and not `:focus-within`, so that when one of the\n * field's own buttons; the cross, a clickable icon; takes keyboard focus, only that button's\n * outline lights up: two indicators at once would be unreadable. And it is `:focus` rather\n * than `:focus-visible`, because a text field shows its focus even when it was reached with\n * the mouse.\n */\n .v-input-field:has(.v-input-control:focus) {\n --field-border-color: var(--vectis-color-accent);\n\n box-shadow: 0 0 0 1px var(--field-border-color);\n outline: var(--vectis-focus-ring-width) solid transparent;\n }\n\n /*\n * Only the colour variable is changed, which is why the border and the focus ring both turn\n * red without either being restated.\n */\n .v-input-field:has(.v-input-control:user-invalid),\n .v-input-field:has(.v-input-control[aria-invalid='true']) {\n --field-border-color: var(--vectis-color-danger);\n }\n\n /* Inside the box it must not shrink, or a long value would squeeze its figures. */\n .v-input-counter {\n flex: none;\n }\n\n /* A decorative icon is drawn in a muted grey, so it stays quieter than the text\n being typed beside it. */\n .v-input-field > .v-icon {\n color: var(--vectis-color-text-muted);\n }\n\n .v-input-field > .v-spinner {\n font-size: var(--vectis-icon-size);\n }\n\n /*\n * A disabled field greys out through the colour tokens, the same ones VCheckbox and VRadio\n * use, and never through opacity. It comes last in the sequence of states, which at equal\n * specificity is what makes it win over all of them, the error included: a disabled field is\n * not submitted, so it has nothing to report.\n */\n .v-input .v-input-field[data-disabled] {\n --field-border-color: var(--vectis-color-border);\n\n background: var(--vectis-color-surface-muted);\n color: var(--vectis-color-text-muted);\n cursor: not-allowed;\n }\n\n .v-input-field[data-disabled] .v-input-counter {\n color: var(--vectis-color-text-subtle);\n }\n\n .v-input-field[data-disabled] .v-input-action,\n .v-input-field[data-disabled] > .v-icon {\n color: inherit;\n cursor: not-allowed;\n }\n\n .v-input-control:disabled {\n cursor: not-allowed;\n }\n\n /*\n * They live in this sheet because it is the one both are guaranteed to load, being built on\n * VInput; the core sheet would charge every consumer for them. `.v-input-end-pinned` lifts\n * the clear cross and whatever carries `.v-input-icon-end`; the end icon, or a composed\n * field's own chevron and spinner; out of the flow, so they stay pinned to the end of the\n * field and vertically centred whatever the chips do.\n */\n .v-input-end-pinned .v-input-field {\n position: relative;\n }\n\n .v-input-end-pinned .v-input-field:has(> :is(.v-input-clear, .v-input-icon-end, .v-spinner)) {\n padding-inline-end: calc(\n var(--control-padding-inline-field) + var(--vectis-icon-size) + var(--control-gap)\n );\n }\n\n .v-input-end-pinned\n .v-input-field:has(> .v-input-clear):has(> :is(.v-input-icon-end, .v-spinner)) {\n padding-inline-end: calc(\n var(--control-padding-inline-field) + 2 * var(--vectis-icon-size) + 2 * var(--control-gap)\n );\n }\n\n .v-input-end-pinned :is(.v-input-clear, .v-input-icon-end) {\n position: absolute;\n inset-inline-end: var(--control-padding-inline-field);\n top: 50%;\n translate: 0 -50%;\n }\n\n /*\n * This inset reads in glyphs and not in buttons. The cross is one of the field's buttons,\n * whose negative margin; half the difference between icon and button; already cancels its own\n * overhang, so an inset lands on the glyph's edge.\n */\n .v-input-end-pinned .v-input-clear:has(~ :is(.v-input-icon-end, .v-spinner)) {\n inset-inline-end: calc(\n var(--control-padding-inline-field) + var(--vectis-icon-size) + var(--control-gap)\n );\n }\n\n /*\n * The control rule must stay at (0,2,0). VCombobox folds its search input away with a (0,3,0)\n * rule that zeroes this height, and at equal weight the winner would be whichever of the two\n * sheets a bundler put last.\n */\n .v-input-chips .v-input-field {\n flex-wrap: wrap;\n height: auto;\n min-height: var(--control-height);\n padding-block: var(--vectis-space-1);\n }\n\n .v-input-chips .v-input-control {\n height: var(--chip-height);\n }\n\n /* (0,2,0) over the chip's own height, so a chip from the #chip slot fits as well. */\n .v-input-chips .v-chip {\n block-size: var(--chip-height);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-input-field {\n transition: none;\n }\n }\n}\n</style>\n"],"mappings":"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"}
|
|
@@ -33,8 +33,6 @@ interface InputGroupProps {
|
|
|
33
33
|
* two heights stops reading as one object. Left out, each segment keeps its own.
|
|
34
34
|
*/
|
|
35
35
|
size?: InputGroupSize;
|
|
36
|
-
/** Takes 4px off the height of every segment, the way `compact` does on a lone field. */
|
|
37
|
-
compact?: boolean;
|
|
38
36
|
/**
|
|
39
37
|
* Makes the whole row unusable. It adds to what each segment says rather than
|
|
40
38
|
* replacing it: a segment disabled on its own stays disabled under a row that says
|
|
@@ -50,7 +48,6 @@ declare const __VLS_base: import('vue').DefineComponent<InputGroupProps, {}, {},
|
|
|
50
48
|
label: string;
|
|
51
49
|
error: string;
|
|
52
50
|
size: InputGroupSize;
|
|
53
|
-
compact: boolean;
|
|
54
51
|
disabled: boolean;
|
|
55
52
|
required: boolean;
|
|
56
53
|
hint: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VInputGroup.js","names":[],"sources":["../../../src/components/VInput/VInputGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @a11y @core\n/**\n * Join functional field boxes rather than their label-and-hint wrappers. Context shares row\n * shape and disables descendants without changing their native controls.\n */\nimport { provide } from 'vue'\n\nimport VField from '../VField/VField.vue'\nimport type { FieldLabelPosition } from '../VField/VField.vue'\n\nimport { buttonGroupKey } from '../VButton/context'\n\nimport { useRootAttrs } from '../../composables/useRootAttrs'\n\nimport { inputGroupKey } from './context'\n\n/** The heights a joined row offers, matching the field scale: 32, 40 or 48 pixels. */\nexport type InputGroupSize = 'sm' | 'md' | 'lg'\n\ninterface InputGroupProps {\n /**\n * The label above the row, rendered once for all of its segments and used as the\n * group's accessible name. A segment carrying one of its own is pushed out of line,\n * so name each of them with `aria-label` instead.\n */\n label?: string\n /**\n * A line of help under the row, tied to the group so assistive technology reads it\n * out along with the label.\n */\n hint?: string\n /**\n * A message saying what is wrong with the row, shown in place of the hint and read along with\n * the group. It is announced when it appears or changes. Mark the segments at fault with\n * `invalid`.\n */\n error?: string\n /** Adds an asterisk after the label. Mark the segments themselves `required`. */\n required?: boolean\n /** Hides the label visually. It still names the group for assistive technology. */\n hideLabel?: boolean\n /**\n * Where the label sits: above the row (`top`, the default), or at its start, in a column of\n * its own, moving back above when there is not room for both.\n */\n labelPosition?: FieldLabelPosition\n /**\n * The height every segment takes, whatever it names for itself: a row of controls of\n * two heights stops reading as one object. Left out, each segment keeps its own.\n */\n size?: InputGroupSize\n /** Takes 4px off the height of every segment, the way `compact` does on a lone field. */\n compact?: boolean\n /**\n * Makes the whole row unusable. It adds to what each segment says rather than\n * replacing it: a segment disabled on its own stays disabled under a row that says\n * nothing.\n */\n disabled?: boolean\n}\n\ndefineOptions({ inheritAttrs: false })\n\n// Every one of the three below defaults to `undefined`, the booleans included. It is\n// `undefined`, and not `false`, that means \"the group has no opinion\", and that is what makes a\n// bare VInputGroup change nothing about what it contains.\nconst props = withDefaults(defineProps<InputGroupProps>(), {\n label: undefined,\n hint: undefined,\n error: undefined,\n required: false,\n hideLabel: false,\n labelPosition: 'top',\n size: undefined,\n compact: undefined,\n disabled: undefined,\n})\n\ndefineSlots<{\n /** The fields and buttons to join. Each one is a segment of the row. */\n default(): unknown\n}>()\n\n// The consumer's attributes name and describe the row, which VField's group mode hands over: a\n// consumer's `aria-labelledby` or `aria-label` wins over the visible label.\nconst { rootClass, rootStyle, forwardedAttrs } = useRootAttrs()\n\n// Getters, so the group's props stay reactive on the other side of the injection.\nconst rowContext = {\n get size() {\n return props.size\n },\n get compact() {\n return props.compact\n },\n get disabled() {\n return props.disabled\n },\n}\n\nprovide(inputGroupKey, rowContext)\n\n// The group provides VButtonGroup's context TOO, which makes a VButton or a VIconButton segment\n// follow the row's height without a new line in VButton: the arbitration there is already\n// `group?.x ?? props.x`, exactly this one. Variant, tone and elevation stay `undefined`; in a\n// row of fields those are the button's own decisions.\nprovide(buttonGroupKey, rowContext)\n</script>\n\n<template>\n <VField\n v-bind=\"forwardedAttrs\"\n class=\"v-input-group\"\n :class=\"rootClass\"\n :style=\"rootStyle\"\n :label=\"label\"\n :hint=\"hint\"\n :error=\"error\"\n :required=\"required\"\n :disabled=\"disabled\"\n :hide-label=\"hideLabel\"\n :label-position=\"labelPosition\"\n group\n >\n <!-- A label points at ONE control, and this names a row of them: the row takes it through\n aria-labelledby, the ARIA pattern for a composed field. -->\n <template #default=\"{ fieldProps }\">\n <div v-bind=\"fieldProps\" class=\"v-input-group-row\" role=\"group\">\n <slot />\n </div>\n </template>\n </VField>\n</template>\n\n<style>\n@layer vectis.components {\n /* The root is a VField, which lays out the label, the hint and the error. */\n .v-input-group {\n width: 100%;\n }\n\n /*\n * Do not put v-control on the row: rederiving its inherited height would reset compact\n * dimensions already applied by the fields.\n */\n .v-input-group-row {\n display: flex;\n /* Same height whatever a segment measures. This changes nothing in an ordinary row,\n where everything is --control-height, and it is what stops a segment that GROWS from\n leaving its neighbours hanging at the top. */\n align-items: stretch;\n }\n\n /*\n * The logic is written this way round because it is the one that enumerates nothing: a bare\n * VButton, or one under two companions, has no `.v-input-field`, so it never stretches\n * without our having to name it. The proportions belong to the consumer, an inline `flex` on\n * the segment (style=\"flex: 0 0 9rem\"). Every segment rule excludes `.v-overlay`: VMenu\n * renders its panel as a sibling of its trigger, and a panel must not pass for a segment.\n */\n .v-input-group-row > :not(:where(.v-overlay)) {\n flex: none;\n min-inline-size: 0;\n }\n\n /*\n * The field has to be the segment's own, never one inside a panel it opens: a VPopover\n * segment holding a VInput in its panel is a button, and stays its natural width.\n */\n .v-input-group-row > :not(:where(.v-overlay)):has(.v-input-field:not(:where(.v-overlay *))) {\n flex: 1 1 0;\n }\n\n /*\n * Without this rule the paint order would depend on which components the row happens to hold.\n * A combobox's field is already `position: relative` (VInput's `.v-input-end-pinned`, which\n * lifts its chevron and its cross out of the flow) where a bare `.v-input-field` is not, and\n * a positioned element paints after every in-flow block whatever the document order.\n */\n .v-input-group-row > .v-button,\n .v-input-group-row\n > :not(:where(.v-overlay, .v-button-group))\n :is(.v-input-field, .v-button):not(:where(.v-overlay *, .v-button-group *)) {\n position: relative;\n }\n\n /*\n * VButton's base is `border: 1px solid transparent`, so a row of solid buttons has no line to\n * inherit and the seam is the only separation possible. A field carries a real opaque border,\n * and melting it with its neighbour's PRODUCES the line; a seam here would double it, and in\n * VButtonGroup's `--vectis-color-border` it would come out LIGHTER than the row's own\n * outline.\n */\n .v-input-group-row > .v-button:not(:first-child),\n .v-input-group-row\n > :not(:where(.v-overlay, .v-button-group)):has(\n :is(.v-input-field, .v-button):not(:where(.v-overlay *, .v-button-group *))\n ):not(:first-child) {\n margin-inline-start: -1px;\n }\n\n /* Only the two outer corners of the row stay rounded. Logical properties throughout, so a\n right-to-left row rounds its other end with no second rule, and the pull above is\n `margin-inline-start`. */\n .v-input-group-row > .v-button:not(:first-child),\n .v-input-group-row\n > :not(:where(.v-overlay, .v-button-group)):not(:first-child)\n :is(.v-input-field, .v-button):not(:where(.v-overlay *, .v-button-group *)) {\n border-start-start-radius: 0;\n border-end-start-radius: 0;\n }\n\n /*\n * The last segment reads `:has(~ :not(.v-overlay))` and not `:not(:last-child)`, and that is\n * VMenu's doing: it renders its panel as a SIBLING of its trigger, so a menu closing a row\n * would leave its trigger without `:last-child` and the row would lose its outer corner with\n * nothing in the DOM to say why. Asking whether a real SEGMENT follows weighs exactly what\n * the test it replaces weighed.\n */\n .v-input-group-row > .v-button:has(~ :not(.v-overlay)),\n .v-input-group-row\n > :not(:where(.v-overlay, .v-button-group)):has(~ :not(.v-overlay))\n :is(.v-input-field, .v-button):not(:where(.v-overlay *, .v-button-group *)) {\n border-start-end-radius: 0;\n border-end-end-radius: 0;\n }\n\n /*\n * This rule must stay ABOVE the focus rule. A field both invalid and focused matches the two,\n * they weigh the same (0,4,0), and nothing but the source order arbitrates between them; it\n * is the accent ring the reader has to see.\n */\n .v-input-group-row\n > :not(:where(.v-overlay, .v-button-group))\n .v-input-field:is(\n :has(.v-input-control:user-invalid),\n :has(.v-input-control[aria-invalid='true'])\n ) {\n z-index: 1;\n }\n\n /*\n * The field draws its focus as its own 1px border PLUS a 1px shadow just outside the border\n * box, and that shadow falls into the neighbour the pull brought over it: without this rule\n * the accent edge disappears from one side of every segment but the last. Two tests, because\n * the two kinds of segment mark focus differently.\n */\n .v-input-group-row\n > :not(:where(.v-overlay, .v-button-group))\n .v-input-field:has(.v-input-control:focus),\n .v-input-group-row > .v-button:focus-visible,\n .v-input-group-row\n > :not(:where(.v-overlay, .v-button-group))\n .v-button:focus-visible:not(:where(.v-overlay *, .v-button-group *)) {\n z-index: 2;\n }\n}\n</style>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"VInputGroup.js","names":["_sfc_main","VInputGroup_vue_vue_type_script_setup_true_lang_default","VInputGroup_default"],"sources":["../../../src/components/VInput/VInputGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @a11y @core\n/**\n * Join functional field boxes rather than their label-and-hint wrappers. Context shares row\n * shape and disables descendants without changing their native controls.\n */\nimport { provide } from 'vue'\n\nimport VField from '../VField/VField.vue'\nimport type { FieldLabelPosition } from '../VField/VField.vue'\n\nimport { buttonGroupKey } from '../VButton/context'\n\nimport { useRootAttrs } from '../../composables/useRootAttrs'\n\nimport { inputGroupKey } from './context'\n\n/** The heights a joined row offers, matching the field scale: 32, 40 or 48 pixels. */\nexport type InputGroupSize = 'sm' | 'md' | 'lg'\n\ninterface InputGroupProps {\n /**\n * The label above the row, rendered once for all of its segments and used as the\n * group's accessible name. A segment carrying one of its own is pushed out of line,\n * so name each of them with `aria-label` instead.\n */\n label?: string\n /**\n * A line of help under the row, tied to the group so assistive technology reads it\n * out along with the label.\n */\n hint?: string\n /**\n * A message saying what is wrong with the row, shown in place of the hint and read along with\n * the group. It is announced when it appears or changes. Mark the segments at fault with\n * `invalid`.\n */\n error?: string\n /** Adds an asterisk after the label. Mark the segments themselves `required`. */\n required?: boolean\n /** Hides the label visually. It still names the group for assistive technology. */\n hideLabel?: boolean\n /**\n * Where the label sits: above the row (`top`, the default), or at its start, in a column of\n * its own, moving back above when there is not room for both.\n */\n labelPosition?: FieldLabelPosition\n /**\n * The height every segment takes, whatever it names for itself: a row of controls of\n * two heights stops reading as one object. Left out, each segment keeps its own.\n */\n size?: InputGroupSize\n /**\n * Makes the whole row unusable. It adds to what each segment says rather than\n * replacing it: a segment disabled on its own stays disabled under a row that says\n * nothing.\n */\n disabled?: boolean\n}\n\ndefineOptions({ inheritAttrs: false })\n\n// Every one of the three below defaults to `undefined`, the booleans included. It is\n// `undefined`, and not `false`, that means \"the group has no opinion\", and that is what makes a\n// bare VInputGroup change nothing about what it contains.\nconst props = withDefaults(defineProps<InputGroupProps>(), {\n label: undefined,\n hint: undefined,\n error: undefined,\n required: false,\n hideLabel: false,\n labelPosition: 'top',\n size: undefined,\n disabled: undefined,\n})\n\ndefineSlots<{\n /** The fields and buttons to join. Each one is a segment of the row. */\n default(): unknown\n}>()\n\n// The consumer's attributes name and describe the row, which VField's group mode hands over: a\n// consumer's `aria-labelledby` or `aria-label` wins over the visible label.\nconst { rootClass, rootStyle, forwardedAttrs } = useRootAttrs()\n\n// Getters, so the group's props stay reactive on the other side of the injection.\nconst rowContext = {\n get size() {\n return props.size\n },\n get disabled() {\n return props.disabled\n },\n}\n\nprovide(inputGroupKey, rowContext)\n\n// The group provides VButtonGroup's context TOO, which makes a VButton or a VIconButton segment\n// follow the row's height without a new line in VButton: the arbitration there is already\n// `group?.x ?? props.x`, exactly this one. Variant, tone and elevation stay `undefined`; in a\n// row of fields those are the button's own decisions.\nprovide(buttonGroupKey, rowContext)\n</script>\n\n<template>\n <VField\n v-bind=\"forwardedAttrs\"\n class=\"v-input-group\"\n :class=\"rootClass\"\n :style=\"rootStyle\"\n :label=\"label\"\n :hint=\"hint\"\n :error=\"error\"\n :required=\"required\"\n :disabled=\"disabled\"\n :hide-label=\"hideLabel\"\n :label-position=\"labelPosition\"\n group\n >\n <!-- A label points at ONE control, and this names a row of them: the row takes it through\n aria-labelledby, the ARIA pattern for a composed field. -->\n <template #default=\"{ fieldProps }\">\n <div v-bind=\"fieldProps\" class=\"v-input-group-row\" role=\"group\">\n <slot />\n </div>\n </template>\n </VField>\n</template>\n\n<style>\n@layer vectis.components {\n /* The root is a VField, which lays out the label, the hint and the error. */\n .v-input-group {\n width: 100%;\n }\n\n /*\n * Do not put v-control on the row: it has no size of its own, and each field derives its\n * height itself.\n */\n .v-input-group-row {\n display: flex;\n /* Same height whatever a segment measures. This changes nothing in an ordinary row,\n where everything is --control-height, and it is what stops a segment that GROWS from\n leaving its neighbours hanging at the top. */\n align-items: stretch;\n }\n\n /*\n * The logic is written this way round because it is the one that enumerates nothing: a bare\n * VButton, or one under two companions, has no `.v-input-field`, so it never stretches\n * without our having to name it. The proportions belong to the consumer, an inline `flex` on\n * the segment (style=\"flex: 0 0 9rem\"). Every segment rule excludes `.v-overlay`: VMenu\n * renders its panel as a sibling of its trigger, and a panel must not pass for a segment.\n */\n .v-input-group-row > :not(:where(.v-overlay)) {\n flex: none;\n min-inline-size: 0;\n }\n\n /*\n * The field has to be the segment's own, never one inside a panel it opens: a VPopover\n * segment holding a VInput in its panel is a button, and stays its natural width.\n */\n .v-input-group-row > :not(:where(.v-overlay)):has(.v-input-field:not(:where(.v-overlay *))) {\n flex: 1 1 0;\n }\n\n /*\n * Without this rule the paint order would depend on which components the row happens to hold.\n * A combobox's field is already `position: relative` (VInput's `.v-input-end-pinned`, which\n * lifts its chevron and its cross out of the flow) where a bare `.v-input-field` is not, and\n * a positioned element paints after every in-flow block whatever the document order.\n */\n .v-input-group-row > .v-button,\n .v-input-group-row\n > :not(:where(.v-overlay, .v-button-group))\n :is(.v-input-field, .v-button):not(:where(.v-overlay *, .v-button-group *)) {\n position: relative;\n }\n\n /*\n * VButton's base is `border: 1px solid transparent`, so a row of solid buttons has no line to\n * inherit and the seam is the only separation possible. A field carries a real opaque border,\n * and melting it with its neighbour's PRODUCES the line; a seam here would double it, and in\n * VButtonGroup's `--vectis-color-border` it would come out LIGHTER than the row's own\n * outline.\n */\n .v-input-group-row > .v-button:not(:first-child),\n .v-input-group-row\n > :not(:where(.v-overlay, .v-button-group)):has(\n :is(.v-input-field, .v-button):not(:where(.v-overlay *, .v-button-group *))\n ):not(:first-child) {\n margin-inline-start: -1px;\n }\n\n /* Only the two outer corners of the row stay rounded. Logical properties throughout, so a\n right-to-left row rounds its other end with no second rule, and the pull above is\n `margin-inline-start`. */\n .v-input-group-row > .v-button:not(:first-child),\n .v-input-group-row\n > :not(:where(.v-overlay, .v-button-group)):not(:first-child)\n :is(.v-input-field, .v-button):not(:where(.v-overlay *, .v-button-group *)) {\n border-start-start-radius: 0;\n border-end-start-radius: 0;\n }\n\n /*\n * The last segment reads `:has(~ :not(.v-overlay))` and not `:not(:last-child)`, and that is\n * VMenu's doing: it renders its panel as a SIBLING of its trigger, so a menu closing a row\n * would leave its trigger without `:last-child` and the row would lose its outer corner with\n * nothing in the DOM to say why. Asking whether a real SEGMENT follows weighs exactly what\n * the test it replaces weighed.\n */\n .v-input-group-row > .v-button:has(~ :not(.v-overlay)),\n .v-input-group-row\n > :not(:where(.v-overlay, .v-button-group)):has(~ :not(.v-overlay))\n :is(.v-input-field, .v-button):not(:where(.v-overlay *, .v-button-group *)) {\n border-start-end-radius: 0;\n border-end-end-radius: 0;\n }\n\n /*\n * This rule must stay ABOVE the focus rule. A field both invalid and focused matches the two,\n * they weigh the same (0,4,0), and nothing but the source order arbitrates between them; it\n * is the accent ring the reader has to see.\n */\n .v-input-group-row\n > :not(:where(.v-overlay, .v-button-group))\n .v-input-field:is(\n :has(.v-input-control:user-invalid),\n :has(.v-input-control[aria-invalid='true'])\n ) {\n z-index: 1;\n }\n\n /*\n * The field draws its focus as its own 1px border PLUS a 1px shadow just outside the border\n * box, and that shadow falls into the neighbour the pull brought over it: without this rule\n * the accent edge disappears from one side of every segment but the last. Two tests, because\n * the two kinds of segment mark focus differently.\n */\n .v-input-group-row\n > :not(:where(.v-overlay, .v-button-group))\n .v-input-field:has(.v-input-control:focus),\n .v-input-group-row > .v-button:focus-visible,\n .v-input-group-row\n > :not(:where(.v-overlay, .v-button-group))\n .v-button:focus-visible:not(:where(.v-overlay *, .v-button-group *)) {\n z-index: 2;\n }\n}\n</style>\n"],"mappings":""}
|
|
@@ -21,10 +21,6 @@ var p = /*@__PURE__*/ o({
|
|
|
21
21
|
},
|
|
22
22
|
labelPosition: { default: "top" },
|
|
23
23
|
size: { default: void 0 },
|
|
24
|
-
compact: {
|
|
25
|
-
type: Boolean,
|
|
26
|
-
default: void 0
|
|
27
|
-
},
|
|
28
24
|
disabled: {
|
|
29
25
|
type: Boolean,
|
|
30
26
|
default: void 0
|
|
@@ -35,9 +31,6 @@ var p = /*@__PURE__*/ o({
|
|
|
35
31
|
get size() {
|
|
36
32
|
return p.size;
|
|
37
33
|
},
|
|
38
|
-
get compact() {
|
|
39
|
-
return p.compact;
|
|
40
|
-
},
|
|
41
34
|
get disabled() {
|
|
42
35
|
return p.disabled;
|
|
43
36
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VInputGroup.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/VInput/VInputGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @a11y @core\n/**\n * Join functional field boxes rather than their label-and-hint wrappers. Context shares row\n * shape and disables descendants without changing their native controls.\n */\nimport { provide } from 'vue'\n\nimport VField from '../VField/VField.vue'\nimport type { FieldLabelPosition } from '../VField/VField.vue'\n\nimport { buttonGroupKey } from '../VButton/context'\n\nimport { useRootAttrs } from '../../composables/useRootAttrs'\n\nimport { inputGroupKey } from './context'\n\n/** The heights a joined row offers, matching the field scale: 32, 40 or 48 pixels. */\nexport type InputGroupSize = 'sm' | 'md' | 'lg'\n\ninterface InputGroupProps {\n /**\n * The label above the row, rendered once for all of its segments and used as the\n * group's accessible name. A segment carrying one of its own is pushed out of line,\n * so name each of them with `aria-label` instead.\n */\n label?: string\n /**\n * A line of help under the row, tied to the group so assistive technology reads it\n * out along with the label.\n */\n hint?: string\n /**\n * A message saying what is wrong with the row, shown in place of the hint and read along with\n * the group. It is announced when it appears or changes. Mark the segments at fault with\n * `invalid`.\n */\n error?: string\n /** Adds an asterisk after the label. Mark the segments themselves `required`. */\n required?: boolean\n /** Hides the label visually. It still names the group for assistive technology. */\n hideLabel?: boolean\n /**\n * Where the label sits: above the row (`top`, the default), or at its start, in a column of\n * its own, moving back above when there is not room for both.\n */\n labelPosition?: FieldLabelPosition\n /**\n * The height every segment takes, whatever it names for itself: a row of controls of\n * two heights stops reading as one object. Left out, each segment keeps its own.\n */\n size?: InputGroupSize\n /** Takes 4px off the height of every segment, the way `compact` does on a lone field. */\n compact?: boolean\n /**\n * Makes the whole row unusable. It adds to what each segment says rather than\n * replacing it: a segment disabled on its own stays disabled under a row that says\n * nothing.\n */\n disabled?: boolean\n}\n\ndefineOptions({ inheritAttrs: false })\n\n// Every one of the three below defaults to `undefined`, the booleans included. It is\n// `undefined`, and not `false`, that means \"the group has no opinion\", and that is what makes a\n// bare VInputGroup change nothing about what it contains.\nconst props = withDefaults(defineProps<InputGroupProps>(), {\n label: undefined,\n hint: undefined,\n error: undefined,\n required: false,\n hideLabel: false,\n labelPosition: 'top',\n size: undefined,\n compact: undefined,\n disabled: undefined,\n})\n\ndefineSlots<{\n /** The fields and buttons to join. Each one is a segment of the row. */\n default(): unknown\n}>()\n\n// The consumer's attributes name and describe the row, which VField's group mode hands over: a\n// consumer's `aria-labelledby` or `aria-label` wins over the visible label.\nconst { rootClass, rootStyle, forwardedAttrs } = useRootAttrs()\n\n// Getters, so the group's props stay reactive on the other side of the injection.\nconst rowContext = {\n get size() {\n return props.size\n },\n get compact() {\n return props.compact\n },\n get disabled() {\n return props.disabled\n },\n}\n\nprovide(inputGroupKey, rowContext)\n\n// The group provides VButtonGroup's context TOO, which makes a VButton or a VIconButton segment\n// follow the row's height without a new line in VButton: the arbitration there is already\n// `group?.x ?? props.x`, exactly this one. Variant, tone and elevation stay `undefined`; in a\n// row of fields those are the button's own decisions.\nprovide(buttonGroupKey, rowContext)\n</script>\n\n<template>\n <VField\n v-bind=\"forwardedAttrs\"\n class=\"v-input-group\"\n :class=\"rootClass\"\n :style=\"rootStyle\"\n :label=\"label\"\n :hint=\"hint\"\n :error=\"error\"\n :required=\"required\"\n :disabled=\"disabled\"\n :hide-label=\"hideLabel\"\n :label-position=\"labelPosition\"\n group\n >\n <!-- A label points at ONE control, and this names a row of them: the row takes it through\n aria-labelledby, the ARIA pattern for a composed field. -->\n <template #default=\"{ fieldProps }\">\n <div v-bind=\"fieldProps\" class=\"v-input-group-row\" role=\"group\">\n <slot />\n </div>\n </template>\n </VField>\n</template>\n\n<style>\n@layer vectis.components {\n /* The root is a VField, which lays out the label, the hint and the error. */\n .v-input-group {\n width: 100%;\n }\n\n /*\n * Do not put v-control on the row: rederiving its inherited height would reset compact\n * dimensions already applied by the fields.\n */\n .v-input-group-row {\n display: flex;\n /* Same height whatever a segment measures. This changes nothing in an ordinary row,\n where everything is --control-height, and it is what stops a segment that GROWS from\n leaving its neighbours hanging at the top. */\n align-items: stretch;\n }\n\n /*\n * The logic is written this way round because it is the one that enumerates nothing: a bare\n * VButton, or one under two companions, has no `.v-input-field`, so it never stretches\n * without our having to name it. The proportions belong to the consumer, an inline `flex` on\n * the segment (style=\"flex: 0 0 9rem\"). Every segment rule excludes `.v-overlay`: VMenu\n * renders its panel as a sibling of its trigger, and a panel must not pass for a segment.\n */\n .v-input-group-row > :not(:where(.v-overlay)) {\n flex: none;\n min-inline-size: 0;\n }\n\n /*\n * The field has to be the segment's own, never one inside a panel it opens: a VPopover\n * segment holding a VInput in its panel is a button, and stays its natural width.\n */\n .v-input-group-row > :not(:where(.v-overlay)):has(.v-input-field:not(:where(.v-overlay *))) {\n flex: 1 1 0;\n }\n\n /*\n * Without this rule the paint order would depend on which components the row happens to hold.\n * A combobox's field is already `position: relative` (VInput's `.v-input-end-pinned`, which\n * lifts its chevron and its cross out of the flow) where a bare `.v-input-field` is not, and\n * a positioned element paints after every in-flow block whatever the document order.\n */\n .v-input-group-row > .v-button,\n .v-input-group-row\n > :not(:where(.v-overlay, .v-button-group))\n :is(.v-input-field, .v-button):not(:where(.v-overlay *, .v-button-group *)) {\n position: relative;\n }\n\n /*\n * VButton's base is `border: 1px solid transparent`, so a row of solid buttons has no line to\n * inherit and the seam is the only separation possible. A field carries a real opaque border,\n * and melting it with its neighbour's PRODUCES the line; a seam here would double it, and in\n * VButtonGroup's `--vectis-color-border` it would come out LIGHTER than the row's own\n * outline.\n */\n .v-input-group-row > .v-button:not(:first-child),\n .v-input-group-row\n > :not(:where(.v-overlay, .v-button-group)):has(\n :is(.v-input-field, .v-button):not(:where(.v-overlay *, .v-button-group *))\n ):not(:first-child) {\n margin-inline-start: -1px;\n }\n\n /* Only the two outer corners of the row stay rounded. Logical properties throughout, so a\n right-to-left row rounds its other end with no second rule, and the pull above is\n `margin-inline-start`. */\n .v-input-group-row > .v-button:not(:first-child),\n .v-input-group-row\n > :not(:where(.v-overlay, .v-button-group)):not(:first-child)\n :is(.v-input-field, .v-button):not(:where(.v-overlay *, .v-button-group *)) {\n border-start-start-radius: 0;\n border-end-start-radius: 0;\n }\n\n /*\n * The last segment reads `:has(~ :not(.v-overlay))` and not `:not(:last-child)`, and that is\n * VMenu's doing: it renders its panel as a SIBLING of its trigger, so a menu closing a row\n * would leave its trigger without `:last-child` and the row would lose its outer corner with\n * nothing in the DOM to say why. Asking whether a real SEGMENT follows weighs exactly what\n * the test it replaces weighed.\n */\n .v-input-group-row > .v-button:has(~ :not(.v-overlay)),\n .v-input-group-row\n > :not(:where(.v-overlay, .v-button-group)):has(~ :not(.v-overlay))\n :is(.v-input-field, .v-button):not(:where(.v-overlay *, .v-button-group *)) {\n border-start-end-radius: 0;\n border-end-end-radius: 0;\n }\n\n /*\n * This rule must stay ABOVE the focus rule. A field both invalid and focused matches the two,\n * they weigh the same (0,4,0), and nothing but the source order arbitrates between them; it\n * is the accent ring the reader has to see.\n */\n .v-input-group-row\n > :not(:where(.v-overlay, .v-button-group))\n .v-input-field:is(\n :has(.v-input-control:user-invalid),\n :has(.v-input-control[aria-invalid='true'])\n ) {\n z-index: 1;\n }\n\n /*\n * The field draws its focus as its own 1px border PLUS a 1px shadow just outside the border\n * box, and that shadow falls into the neighbour the pull brought over it: without this rule\n * the accent edge disappears from one side of every segment but the last. Two tests, because\n * the two kinds of segment mark focus differently.\n */\n .v-input-group-row\n > :not(:where(.v-overlay, .v-button-group))\n .v-input-field:has(.v-input-control:focus),\n .v-input-group-row > .v-button:focus-visible,\n .v-input-group-row\n > :not(:where(.v-overlay, .v-button-group))\n .v-button:focus-visible:not(:where(.v-overlay *, .v-button-group *)) {\n z-index: 2;\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmEA,IAAM,IAAQ,GAmBR,EAAE,cAAW,cAAW,sBAAmB,EAAa,GAGxD,IAAa;GACjB,IAAI,OAAO;IACT,OAAO,EAAM;GACf;GACA,IAAI,UAAU;IACZ,OAAO,EAAM;GACf;GACA,IAAI,WAAW;IACb,OAAO,EAAM;GACf;EACF;SAEA,EAAQ,GAAe,CAAU,GAMjC,EAAQ,GAAgB,CAAU,mBAIhC,EAqBS,GArBT,EACU,EAoBD,CAAA,GApBe;GACtB,OAAK,CAAC,iBACE,EAAA,CAAA,CAAS;GAChB,OAAO,EAAA,CAAA;GACP,OAAO,EAAA;GACP,MAAM,EAAA;GACN,OAAO,EAAA;GACP,UAAU,EAAA;GACV,UAAU,EAAA;GACV,cAAY,EAAA;GACZ,kBAAgB,EAAA;GACjB,OAAA;;GAIW,SAAO,GAGV,EAHc,oBAAU,CAC9B,EAEM,OAFN,EAAa,GAAU;IAAE,OAAM;IAAoB,MAAK;QACtD,EAAQ,EAAA,QAAA,SAAA,CAAA,GAAA,EAAA,CAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"VInputGroup.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","VField","_mergeProps","_unref","_withCtx","_createElementVNode","_renderSlot","VField_default","VInputGroup_vue_vue_type_script_setup_true_lang_default","props","__props","useRootAttrs","rowContext","provide","inputGroupKey","buttonGroupKey","openBlock","createBlock","mergeProps","unref","forwardedAttrs","rootClass","rootStyle","withCtx","createElementVNode","fieldProps","renderSlot","_ctx"],"sources":["../../../src/components/VInput/VInputGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @a11y @core\n/**\n * Join functional field boxes rather than their label-and-hint wrappers. Context shares row\n * shape and disables descendants without changing their native controls.\n */\nimport { provide } from 'vue'\n\nimport VField from '../VField/VField.vue'\nimport type { FieldLabelPosition } from '../VField/VField.vue'\n\nimport { buttonGroupKey } from '../VButton/context'\n\nimport { useRootAttrs } from '../../composables/useRootAttrs'\n\nimport { inputGroupKey } from './context'\n\n/** The heights a joined row offers, matching the field scale: 32, 40 or 48 pixels. */\nexport type InputGroupSize = 'sm' | 'md' | 'lg'\n\ninterface InputGroupProps {\n /**\n * The label above the row, rendered once for all of its segments and used as the\n * group's accessible name. A segment carrying one of its own is pushed out of line,\n * so name each of them with `aria-label` instead.\n */\n label?: string\n /**\n * A line of help under the row, tied to the group so assistive technology reads it\n * out along with the label.\n */\n hint?: string\n /**\n * A message saying what is wrong with the row, shown in place of the hint and read along with\n * the group. It is announced when it appears or changes. Mark the segments at fault with\n * `invalid`.\n */\n error?: string\n /** Adds an asterisk after the label. Mark the segments themselves `required`. */\n required?: boolean\n /** Hides the label visually. It still names the group for assistive technology. */\n hideLabel?: boolean\n /**\n * Where the label sits: above the row (`top`, the default), or at its start, in a column of\n * its own, moving back above when there is not room for both.\n */\n labelPosition?: FieldLabelPosition\n /**\n * The height every segment takes, whatever it names for itself: a row of controls of\n * two heights stops reading as one object. Left out, each segment keeps its own.\n */\n size?: InputGroupSize\n /**\n * Makes the whole row unusable. It adds to what each segment says rather than\n * replacing it: a segment disabled on its own stays disabled under a row that says\n * nothing.\n */\n disabled?: boolean\n}\n\ndefineOptions({ inheritAttrs: false })\n\n// Every one of the three below defaults to `undefined`, the booleans included. It is\n// `undefined`, and not `false`, that means \"the group has no opinion\", and that is what makes a\n// bare VInputGroup change nothing about what it contains.\nconst props = withDefaults(defineProps<InputGroupProps>(), {\n label: undefined,\n hint: undefined,\n error: undefined,\n required: false,\n hideLabel: false,\n labelPosition: 'top',\n size: undefined,\n disabled: undefined,\n})\n\ndefineSlots<{\n /** The fields and buttons to join. Each one is a segment of the row. */\n default(): unknown\n}>()\n\n// The consumer's attributes name and describe the row, which VField's group mode hands over: a\n// consumer's `aria-labelledby` or `aria-label` wins over the visible label.\nconst { rootClass, rootStyle, forwardedAttrs } = useRootAttrs()\n\n// Getters, so the group's props stay reactive on the other side of the injection.\nconst rowContext = {\n get size() {\n return props.size\n },\n get disabled() {\n return props.disabled\n },\n}\n\nprovide(inputGroupKey, rowContext)\n\n// The group provides VButtonGroup's context TOO, which makes a VButton or a VIconButton segment\n// follow the row's height without a new line in VButton: the arbitration there is already\n// `group?.x ?? props.x`, exactly this one. Variant, tone and elevation stay `undefined`; in a\n// row of fields those are the button's own decisions.\nprovide(buttonGroupKey, rowContext)\n</script>\n\n<template>\n <VField\n v-bind=\"forwardedAttrs\"\n class=\"v-input-group\"\n :class=\"rootClass\"\n :style=\"rootStyle\"\n :label=\"label\"\n :hint=\"hint\"\n :error=\"error\"\n :required=\"required\"\n :disabled=\"disabled\"\n :hide-label=\"hideLabel\"\n :label-position=\"labelPosition\"\n group\n >\n <!-- A label points at ONE control, and this names a row of them: the row takes it through\n aria-labelledby, the ARIA pattern for a composed field. -->\n <template #default=\"{ fieldProps }\">\n <div v-bind=\"fieldProps\" class=\"v-input-group-row\" role=\"group\">\n <slot />\n </div>\n </template>\n </VField>\n</template>\n\n<style>\n@layer vectis.components {\n /* The root is a VField, which lays out the label, the hint and the error. */\n .v-input-group {\n width: 100%;\n }\n\n /*\n * Do not put v-control on the row: it has no size of its own, and each field derives its\n * height itself.\n */\n .v-input-group-row {\n display: flex;\n /* Same height whatever a segment measures. This changes nothing in an ordinary row,\n where everything is --control-height, and it is what stops a segment that GROWS from\n leaving its neighbours hanging at the top. */\n align-items: stretch;\n }\n\n /*\n * The logic is written this way round because it is the one that enumerates nothing: a bare\n * VButton, or one under two companions, has no `.v-input-field`, so it never stretches\n * without our having to name it. The proportions belong to the consumer, an inline `flex` on\n * the segment (style=\"flex: 0 0 9rem\"). Every segment rule excludes `.v-overlay`: VMenu\n * renders its panel as a sibling of its trigger, and a panel must not pass for a segment.\n */\n .v-input-group-row > :not(:where(.v-overlay)) {\n flex: none;\n min-inline-size: 0;\n }\n\n /*\n * The field has to be the segment's own, never one inside a panel it opens: a VPopover\n * segment holding a VInput in its panel is a button, and stays its natural width.\n */\n .v-input-group-row > :not(:where(.v-overlay)):has(.v-input-field:not(:where(.v-overlay *))) {\n flex: 1 1 0;\n }\n\n /*\n * Without this rule the paint order would depend on which components the row happens to hold.\n * A combobox's field is already `position: relative` (VInput's `.v-input-end-pinned`, which\n * lifts its chevron and its cross out of the flow) where a bare `.v-input-field` is not, and\n * a positioned element paints after every in-flow block whatever the document order.\n */\n .v-input-group-row > .v-button,\n .v-input-group-row\n > :not(:where(.v-overlay, .v-button-group))\n :is(.v-input-field, .v-button):not(:where(.v-overlay *, .v-button-group *)) {\n position: relative;\n }\n\n /*\n * VButton's base is `border: 1px solid transparent`, so a row of solid buttons has no line to\n * inherit and the seam is the only separation possible. A field carries a real opaque border,\n * and melting it with its neighbour's PRODUCES the line; a seam here would double it, and in\n * VButtonGroup's `--vectis-color-border` it would come out LIGHTER than the row's own\n * outline.\n */\n .v-input-group-row > .v-button:not(:first-child),\n .v-input-group-row\n > :not(:where(.v-overlay, .v-button-group)):has(\n :is(.v-input-field, .v-button):not(:where(.v-overlay *, .v-button-group *))\n ):not(:first-child) {\n margin-inline-start: -1px;\n }\n\n /* Only the two outer corners of the row stay rounded. Logical properties throughout, so a\n right-to-left row rounds its other end with no second rule, and the pull above is\n `margin-inline-start`. */\n .v-input-group-row > .v-button:not(:first-child),\n .v-input-group-row\n > :not(:where(.v-overlay, .v-button-group)):not(:first-child)\n :is(.v-input-field, .v-button):not(:where(.v-overlay *, .v-button-group *)) {\n border-start-start-radius: 0;\n border-end-start-radius: 0;\n }\n\n /*\n * The last segment reads `:has(~ :not(.v-overlay))` and not `:not(:last-child)`, and that is\n * VMenu's doing: it renders its panel as a SIBLING of its trigger, so a menu closing a row\n * would leave its trigger without `:last-child` and the row would lose its outer corner with\n * nothing in the DOM to say why. Asking whether a real SEGMENT follows weighs exactly what\n * the test it replaces weighed.\n */\n .v-input-group-row > .v-button:has(~ :not(.v-overlay)),\n .v-input-group-row\n > :not(:where(.v-overlay, .v-button-group)):has(~ :not(.v-overlay))\n :is(.v-input-field, .v-button):not(:where(.v-overlay *, .v-button-group *)) {\n border-start-end-radius: 0;\n border-end-end-radius: 0;\n }\n\n /*\n * This rule must stay ABOVE the focus rule. A field both invalid and focused matches the two,\n * they weigh the same (0,4,0), and nothing but the source order arbitrates between them; it\n * is the accent ring the reader has to see.\n */\n .v-input-group-row\n > :not(:where(.v-overlay, .v-button-group))\n .v-input-field:is(\n :has(.v-input-control:user-invalid),\n :has(.v-input-control[aria-invalid='true'])\n ) {\n z-index: 1;\n }\n\n /*\n * The field draws its focus as its own 1px border PLUS a 1px shadow just outside the border\n * box, and that shadow falls into the neighbour the pull brought over it: without this rule\n * the accent edge disappears from one side of every segment but the last. Two tests, because\n * the two kinds of segment mark focus differently.\n */\n .v-input-group-row\n > :not(:where(.v-overlay, .v-button-group))\n .v-input-field:has(.v-input-control:focus),\n .v-input-group-row > .v-button:focus-visible,\n .v-input-group-row\n > :not(:where(.v-overlay, .v-button-group))\n .v-button:focus-visible:not(:where(.v-overlay *, .v-button-group *)) {\n z-index: 2;\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiEA,IAAMU,IAAQC,GAkBR,EAAE,cAAW,cAAW,sBAAmBC,EAAa,GAGxDC,IAAa;GACjB,IAAI,OAAO;IACT,OAAOH,EAAM;GACf;GACA,IAAI,WAAW;IACb,OAAOA,EAAM;GACf;EACF;SAEAI,EAAQC,GAAeF,CAAU,GAMjCC,EAAQE,GAAgBH,CAAU,cAIhCb,EAAA,GAAAC,EAqBSC,GArBTC,EACUC,EAoBDiB,CAAA,GApBe;GACtB,OAAK,CAAC,iBACEjB,EAAAkB,CAAA,CAAS;GAChB,OAAOlB,EAAAmB,CAAA;GACP,OAAOZ,EAAA;GACP,MAAMA,EAAA;GACN,OAAOA,EAAA;GACP,UAAUA,EAAA;GACV,UAAUA,EAAA;GACV,cAAYA,EAAA;GACZ,kBAAgBA,EAAA;GACjB,OAAA;;GAIW,SAAON,GAGV,EAHc,oBAAU,CAC9BC,EAEM,OAFNH,EAAauB,GAAU;IAAE,OAAM;IAAoB,MAAK;GACtDnB,CAAAA,GAAAA,CAAAA,EAAQqB,EAAA,QAAA,SAAA,CAAA,GAAA,EAAA,CAAA,CAAA"}
|
|
@@ -3,8 +3,6 @@ import { InputGroupSize } from './VInputGroup.js';
|
|
|
3
3
|
export interface InputGroupContext {
|
|
4
4
|
/** The height of the segments. */
|
|
5
5
|
readonly size?: InputGroupSize;
|
|
6
|
-
/** The reduced density. */
|
|
7
|
-
readonly compact?: boolean;
|
|
8
6
|
/** Whether the whole row is unusable, which no segment can refuse. */
|
|
9
7
|
readonly disabled?: boolean;
|
|
10
8
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","names":[],"sources":["../../../src/components/VInput/context.ts"],"sourcesContent":["/**\n * Limit inherited context to fields so nested panel buttons do not take the surrounding row's\n * dimensions.\n */\n\nimport type { InjectionKey } from 'vue'\n\nimport type { InputGroupSize } from './VInputGroup.vue'\n\nexport interface InputGroupContext {\n /** The height of the segments. */\n readonly size?: InputGroupSize\n /**
|
|
1
|
+
{"version":3,"file":"context.js","names":["inputGroupKey"],"sources":["../../../src/components/VInput/context.ts"],"sourcesContent":["/**\n * Limit inherited context to fields so nested panel buttons do not take the surrounding row's\n * dimensions.\n */\n\nimport type { InjectionKey } from 'vue'\n\nimport type { InputGroupSize } from './VInputGroup.vue'\n\nexport interface InputGroupContext {\n /** The height of the segments. */\n readonly size?: InputGroupSize\n /** Whether the whole row is unusable, which no segment can refuse. */\n readonly disabled?: boolean\n}\n\nexport const inputGroupKey: InjectionKey<InputGroupContext> = Symbol('v-input-group')\n"],"mappings":";AAgBA,IAAaA,IAAiD,OAAO,eAAe"}
|
|
@@ -22,8 +22,6 @@ interface InputOTPProps {
|
|
|
22
22
|
separatorIcon?: IconSource;
|
|
23
23
|
/** The size of the boxes: 32, 40 or 48 pixels. */
|
|
24
24
|
size?: InputOTPSize;
|
|
25
|
-
/** Takes 4px off the boxes, leaving the text and the icons as they are. */
|
|
26
|
-
compact?: boolean;
|
|
27
25
|
/** Makes every box unusable, greyed out through the colour tokens. */
|
|
28
26
|
disabled?: boolean;
|
|
29
27
|
/**
|
|
@@ -92,7 +90,6 @@ declare const __VLS_export: import('vue').DefineComponent<__VLS_PublicProps, {
|
|
|
92
90
|
size: InputOTPSize;
|
|
93
91
|
length: number;
|
|
94
92
|
pattern: string;
|
|
95
|
-
compact: boolean;
|
|
96
93
|
disabled: boolean;
|
|
97
94
|
required: boolean;
|
|
98
95
|
invalid: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VInputOTP.js","names":[],"sources":["../../../src/components/VInputOTP/VInputOTP.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @keyboard @core\n/**\n * Coordinate character inputs because HTML has no segmented code field. JavaScript filters\n * values, distributes paste and moves focus; pattern literals stay outside the model.\n */\n\nimport { computed, ref, useAttrs, watch } from 'vue'\nimport VField from '../VField/VField.vue'\nimport type { FieldLabelPosition } from '../VField/VField.vue'\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport type { IconSource } from '../VIcon/types'\n\nimport { partitionAttrs } from '../../utils/attrs'\nimport { isDev } from '../../utils/env'\n\nimport { useMessages } from '../../i18n/state'\n\n/** The height of the boxes: 32, 40 or 48 pixels. */\nexport type InputOTPSize = 'sm' | 'md' | 'lg'\n\n/** Which characters the code is made of. */\nexport type InputOTPFormat = 'numeric' | 'alpha' | 'alphanumeric'\n\ninterface InputOTPProps {\n /** How many boxes the code has. It is ignored as soon as a `pattern` is given. */\n length?: number\n /**\n * Which characters the code is made of. It filters what can be typed or pasted, and\n * decides which keyboard a phone offers.\n */\n format?: InputOTPFormat\n /**\n * The shape of the code: each `#` is a box to fill, and every other character is a separator\n * shown between the boxes without ever being part of the value, as in `'GT-###'` or\n * `'###.###.###'`.\n */\n pattern?: string\n /** An icon drawn in place of every separator of the pattern. */\n separatorIcon?: IconSource\n /** The size of the boxes: 32, 40 or 48 pixels. */\n size?: InputOTPSize\n /** Takes 4px off the boxes, leaving the text and the icons as they are. */\n compact?: boolean\n /** Makes every box unusable, greyed out through the colour tokens. */\n disabled?: boolean\n /**\n * Shows the code without letting it be changed. The boxes keep their focus and the code can\n * still be selected and copied, which separates it from `disabled`.\n */\n readonly?: boolean\n /** Marks the code as wrong, which colours the boxes and tells assistive technology so. */\n invalid?: boolean\n /**\n * The label above the boxes, which names the row. Without it, the row is named by its\n * `aria-label` or by the design system dictionary.\n */\n label?: string\n /**\n * A line of help under the boxes: where the code was sent, how long it lasts. It is\n * tied to the row for assistive technology, so it is read out along with the label.\n */\n hint?: string\n /**\n * A message saying what is wrong with the value, shown in place of the hint so that the field\n * does not grow. It marks the field invalid, is read along with it, and is announced when it\n * appears or changes.\n */\n error?: string\n /**\n * Marks the code as required: an asterisk follows the label, and the hidden input a form reads\n * is `required`.\n */\n required?: boolean\n /** Hides the label visually. It still names the row for assistive technology. */\n hideLabel?: boolean\n /**\n * Where the label sits: above the boxes (`top`, the default), or at their start, in a column\n * of its own, moving back above when there is not room for both.\n */\n labelPosition?: FieldLabelPosition\n}\n\nconst props = withDefaults(defineProps<InputOTPProps>(), {\n length: 6,\n format: 'numeric',\n pattern: undefined,\n separatorIcon: undefined,\n size: 'md',\n compact: false,\n disabled: false,\n readonly: false,\n invalid: false,\n label: undefined,\n hint: undefined,\n error: undefined,\n required: false,\n hideLabel: false,\n labelPosition: 'top',\n})\n\nconst m = useMessages()\n\n// @a11y\n/*\n * `aria-describedby` is a list, and the hint is appended to whatever the consumer already\n * pointed at instead of replacing it; left to the fallthrough, their value would land last and\n * take the hint out of the announcement with nothing to show for it.\n */\ndefineOptions({ inheritAttrs: false })\n\nconst attrs = useAttrs()\n\n// What the FORM reads goes on the hidden native input, and everything else on the group:\n// on the group a `name` submits nothing and `required` validates nothing, silently.\nconst NATIVE_ONLY = ['name', 'form']\nconst split = computed(() => partitionAttrs(attrs, NATIVE_ONLY))\nconst groupAttrs = computed(() => split.value.rest)\nconst nativeAttrs = computed(() => split.value.picked)\n// @a11y\n// The row has no visible label to be named by when a consumer gives none or names it\n// themselves (VField's group mode): the dictionary names it then.\nfunction rowLabel(fieldProps: Record<string, unknown>): string | undefined {\n if (fieldProps['aria-labelledby']) return undefined\n return (fieldProps['aria-label'] as string | undefined) ?? m.value.inputOTP.label\n}\n\nconst isInvalid = computed(() => props.invalid || !!props.error)\n\n/**\n * The code as one string, without the separators: a `GT-###` template still yields three\n * characters. It is empty to begin with, and shorter than the full length while it is being\n * typed.\n */\nconst model = defineModel<string>({ default: '' })\n\nconst emit = defineEmits<{\n /**\n * Emitted the moment the code BECOMES complete, carrying it. Retyping a character of a\n * complete code with the same one does not emit it again.\n */\n complete: [code: string]\n}>()\n\ntype Cell = { type: 'slot'; slotIndex: number } | { type: 'literal'; char: string }\n\nconst cells = computed<Cell[]>(() => {\n if (props.pattern?.includes('#')) {\n let slotIndex = 0\n return [...props.pattern].map((char): Cell =>\n char === '#' ? { type: 'slot', slotIndex: slotIndex++ } : { type: 'literal', char },\n )\n }\n return Array.from({ length: props.length }, (_, i) => ({ type: 'slot', slotIndex: i }))\n})\nconst slotCount = computed(() => cells.value.filter((cell) => cell.type === 'slot').length)\n\n// @devwarn\nif (isDev) {\n if (props.pattern && !props.pattern.includes('#'))\n console.warn(\"[VInputOTP] pattern without '#' — falling back to `length`.\")\n}\n\nconst filters: Record<InputOTPFormat, RegExp> = {\n numeric: /[^0-9]/g,\n alpha: /[^A-Z]/g,\n alphanumeric: /[^A-Z0-9]/g,\n}\n\n/**\n * Keeps only what the format allows. Outside a numeric code the text is put in\n * capitals first, so that the value has a single canonical form whichever case the\n * reader typed or pasted.\n */\nfunction sanitize(text: string) {\n const upper = props.format === 'numeric' ? text : text.toUpperCase()\n return upper.replace(filters[props.format], '')\n}\n\nconst rootEl = ref<HTMLElement | null>(null)\nconst digits = ref<string[]>([])\n\n// @keyboard\n// Read the rendered order on demand; changing a pattern can move or replace its input cells.\nfunction inputAt(slot: number) {\n return rootEl.value?.querySelectorAll<HTMLInputElement>('.v-input-otp-input')[slot]\n}\n\nfunction syncFromModel(value: string) {\n // A value longer than the row is simply shown cut short, and one holding characters the\n // format refuses is shown filtered; but the model is not rewritten to match: writing back\n // here would feed the watcher below and the two would keep correcting each other.\n const clean = sanitize(value)\n digits.value = Array.from({ length: slotCount.value }, (_, i) => clean[i] ?? '')\n}\nsyncFromModel(model.value)\nwatch([model, slotCount], ([value, count]) => {\n if (value !== digits.value.join('') || digits.value.length !== count) syncFromModel(value)\n})\n\n/** The first empty box, or -1 once the code is complete. Every box before it is filled. */\nconst firstEmpty = () => digits.value.findIndex((d) => !d)\n\n/** The furthest box the focus may reach: the first empty one, or the last of a full code. */\nfunction reachable() {\n const empty = firstEmpty()\n return empty === -1 ? slotCount.value - 1 : empty\n}\n\n/** Takes a character out and moves the following ones back, so no gap is left behind. */\nfunction removeAt(slot: number) {\n digits.value.splice(slot, 1)\n digits.value.push('')\n}\n\nfunction focusBox(slot: number) {\n const el = inputAt(slot)\n el?.focus()\n // Selected, so the next keystroke REPLACES the character: a box that already has the\n // focus receives no focus event to select it.\n el?.select()\n}\n\nfunction commit() {\n const code = digits.value.join('')\n const previous = model.value\n model.value = code\n // Only when the code CHANGES into a full one: retyping a character of a complete code\n // must not submit it a second time for a consumer listening to `complete`.\n if (code.length === slotCount.value && code !== previous) emit('complete', code)\n}\n\n// @core\n/**\n * Spreads a run of characters across the boxes, starting from the one that received them. It\n * returns the last box it filled, so the caller knows where to put the focus, and `null` when\n * nothing in the text was usable.\n */\nfunction distribute(raw: string, startSlot: number): number | null {\n const allCells = cells.value\n let start = allCells.findIndex((cell) => cell.type === 'slot' && cell.slotIndex === startSlot)\n const chars = [...raw]\n // Never for ONE character: a `G` typed into the first box of `GT-###` is the code's first\n // character, not the separator, and swallowing it would make such a code impossible to type.\n if (chars.length > 1) while (start > 0 && allCells[start - 1]?.type === 'literal') start--\n let charIndex = 0\n let lastFilled: number | null = null\n for (const cell of allCells.slice(start)) {\n if (charIndex >= chars.length) break\n if (cell.type === 'literal') {\n if (chars[charIndex]?.toUpperCase() === cell.char.toUpperCase()) charIndex++\n continue\n }\n let char = ''\n while (charIndex < chars.length && !char) {\n char = sanitize(chars[charIndex] ?? '')\n charIndex++\n }\n if (!char) break\n digits.value[cell.slotIndex] = char\n lastFilled = cell.slotIndex\n }\n return lastFilled\n}\n\n// @keyboard @core\n// Separate inputs into something that types like one field; spreading the characters is the\n// core behaviour underneath it.\nfunction onInput(slotIndex: number, event: Event) {\n const el = event.target as HTMLInputElement\n const empty = firstEmpty()\n const filled = empty === -1 || slotIndex < empty\n\n // A filled box whose character was not selected receives the new one NEXT to it. What\n // was inserted is what lies just before the caret, and it is what counts.\n const previous = digits.value[slotIndex] ?? ''\n let raw = el.value\n const inserted = raw.length - previous.length\n if (previous && inserted > 0 && el.selectionStart !== null) {\n raw = raw.slice(Math.max(0, el.selectionStart - inserted), el.selectionStart)\n }\n\n // The same path serves a single keystroke and a pasted code: both are spread from this box\n // onwards; or from the first empty box, when this one lies past it.\n const lastFilled = distribute(raw, filled ? slotIndex : empty)\n if (lastFilled === null) {\n // Either the box was emptied, or nothing typed was valid for this format. A filled box\n // loses its character and the ones after it close the gap.\n if (filled) removeAt(slotIndex)\n el.value = digits.value[slotIndex] ?? ''\n commit()\n return\n }\n // Written by hand: when the characters went to another box, this one's value is still\n // '' in the render, and the patch would leave the typed character on screen.\n el.value = digits.value[slotIndex] ?? ''\n focusBox(Math.min(lastFilled + 1, slotCount.value - 1))\n commit()\n}\n\n// @keyboard\n// Sends the focus there instead: a pointer landing on box 5 of a two-character code types into\n// box 3.\nfunction onFocus(slotIndex: number, event: FocusEvent) {\n const empty = firstEmpty()\n if (empty !== -1 && slotIndex > empty) inputAt(empty)?.focus()\n else (event.target as HTMLInputElement).select()\n}\n\n// @keyboard\nfunction onKeydown(slotIndex: number, event: KeyboardEvent) {\n const last = reachable()\n let target: number | null = null\n switch (event.key) {\n case 'Backspace':\n // A read-only box refuses its own edits natively, but this erases ANOTHER box, which\n // nothing native guards.\n if (props.readonly || props.disabled || digits.value[slotIndex] || slotIndex === 0) return\n removeAt(slotIndex - 1)\n commit()\n target = slotIndex - 1\n break\n case 'ArrowLeft':\n if (slotIndex > 0) target = slotIndex - 1\n break\n case 'ArrowRight':\n if (slotIndex < last) target = slotIndex + 1\n break\n case 'Home':\n target = 0\n break\n case 'End':\n target = last\n break\n }\n if (target === null) return\n event.preventDefault()\n focusBox(target)\n}\n\ndefineExpose({\n /** Moves the focus to the first empty box, or to the last one when the code is complete. */\n focus: (options?: FocusOptions) => inputAt(reachable())?.focus(options),\n /** Selects the box the focus is on, as clicking into one already does. */\n select: () => {\n const active = rootEl.value?.querySelector<HTMLInputElement>('.v-input-otp-input:focus')\n ;(active ?? inputAt(0))?.select()\n },\n /** The row itself, for what neither of the two above covers. */\n el: rootEl,\n})\n</script>\n\n<template>\n <VField\n v-bind=\"groupAttrs\"\n class=\"v-input-otp\"\n :label=\"label\"\n :hint=\"hint\"\n :error=\"error\"\n :required=\"required\"\n :disabled=\"disabled\"\n :hide-label=\"hideLabel\"\n :label-position=\"labelPosition\"\n group\n >\n <template #default=\"{ fieldProps }\">\n <div\n ref=\"rootEl\"\n v-bind=\"fieldProps\"\n class=\"v-input-otp-group v-control\"\n role=\"group\"\n :aria-label=\"rowLabel(fieldProps)\"\n :data-invalid=\"isInvalid ? '' : undefined\"\n :data-size=\"size\"\n :data-compact=\"compact ? '' : undefined\"\n :data-disabled=\"disabled ? '' : undefined\"\n :data-readonly=\"readonly ? '' : undefined\"\n >\n <div class=\"v-input-otp-boxes\">\n <template v-for=\"(cell, i) in cells\" :key=\"i\">\n <input\n v-if=\"cell.type === 'slot'\"\n type=\"text\"\n class=\"v-input-otp-input\"\n :inputmode=\"format === 'numeric' ? 'numeric' : 'text'\"\n :autocomplete=\"cell.slotIndex === 0 ? 'one-time-code' : 'off'\"\n :value=\"digits[cell.slotIndex]\"\n :disabled=\"disabled\"\n :readonly=\"readonly || undefined\"\n :aria-label=\"m.inputOTP.slot(cell.slotIndex + 1, slotCount)\"\n :aria-invalid=\"isInvalid || undefined\"\n @input=\"onInput(cell.slotIndex, $event)\"\n @keydown=\"onKeydown(cell.slotIndex, $event)\"\n @focus=\"onFocus(cell.slotIndex, $event)\"\n />\n <!-- A separator from the pattern: shown, never focusable, and never part of the\n value. It is hidden from screen readers, each box already announcing its\n own position in the code. -->\n <span v-else class=\"v-input-otp-literal\" aria-hidden=\"true\">\n <VIcon v-if=\"separatorIcon\" v-bind=\"iconProps(separatorIcon)\" />\n <template v-else>{{ cell.char }}</template>\n </span>\n </template>\n </div>\n\n <!--\n Out of the tab order and hidden from assistive technology, the boxes being the control; a\n browser focusing it to report an invalid code is sent on to the box to fill.\n -->\n <input\n v-bind=\"nativeAttrs\"\n class=\"v-input-otp-native v-visually-hidden\"\n type=\"text\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n autocomplete=\"off\"\n :value=\"model\"\n :pattern=\"`.{${slotCount}}`\"\n :required=\"required || undefined\"\n :disabled=\"disabled\"\n :readonly=\"readonly || undefined\"\n @focus=\"focusBox(reachable())\"\n />\n </div>\n </template>\n </VField>\n</template>\n\n<style>\n@layer vectis.components {\n /* Its own width rather than the line's, so that a start label stays next to the boxes. */\n .v-input-otp.v-field {\n display: inline-flex;\n align-items: start;\n }\n\n .v-input-otp-group {\n /*\n * The heights and the icon context come from the shared v-control class\n * (styles/control-size.css). The type is the one thing kept local, and set one or\n * two steps above the other fields: a single character has a whole square to\n * itself, and at the usual field size it would look lost in it.\n */\n --input-otp-font-size: var(--vectis-font-size-lg);\n }\n\n /* A code reads left to right in every language, like the HH:MM of VTimeInput: mirrored\n under `dir=\"rtl\"`, the arrows would walk against the boxes and a `GT-###` pattern would\n be drawn backwards. */\n .v-input-otp-boxes {\n direction: ltr;\n display: flex;\n align-items: center;\n gap: var(--control-gap);\n }\n\n .v-input-otp-input {\n /* The boxes are square: reading the same variable for both dimensions is what\n makes the size and the density scale them together. */\n width: var(--control-height);\n height: var(--control-height);\n text-align: center;\n background: var(--vectis-color-surface);\n color: var(--vectis-color-text);\n border: 1px solid var(--vectis-color-border-strong);\n border-radius: var(--vectis-radius-interactive);\n font-family: var(--vectis-text-family-code);\n font-size: var(--input-otp-font-size);\n transition:\n border-color var(--vectis-duration-fast) var(--vectis-ease-default),\n box-shadow var(--vectis-duration-fast) var(--vectis-ease-default),\n background-color var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n\n /*\n * The states follow VInput's, in VInput's order: read-only, hover, focus, invalid, disabled.\n * Read-only, focus, invalid and disabled all weigh (0,2,0), so the source order arbitrates\n * between them and read-only has to come first, or it would repaint the focus and error\n * borders grey.\n */\n .v-input-otp-group[data-readonly] .v-input-otp-input {\n background: var(--vectis-color-surface-sunken);\n border-color: var(--vectis-color-border);\n }\n\n /* The hover weighs (0,5,0) and keeps itself off a focused, invalid or disabled box\n through its own `:not()`, as VInput's does. */\n .v-input-otp-group:not([data-invalid]) .v-input-otp-input:hover:not(:focus, :disabled) {\n border-color: color-mix(\n in oklab,\n var(--vectis-color-border-strong),\n var(--vectis-color-text) 15%\n );\n }\n\n /*\n * `:focus` rather than `:focus-visible`, like any text field, which shows its focus when\n * clicked into too. The transparent outline is the safety net for Windows forced colours,\n * which drop box-shadows entirely.\n */\n .v-input-otp-input:focus {\n border-color: var(--vectis-color-accent);\n box-shadow: 0 0 0 1px var(--vectis-color-accent);\n outline: var(--vectis-focus-ring-width) solid transparent;\n }\n\n .v-input-otp-group[data-invalid] .v-input-otp-input {\n border-color: var(--vectis-color-danger);\n }\n\n .v-input-otp-group[data-invalid] .v-input-otp-input:focus {\n box-shadow: 0 0 0 1px var(--vectis-color-danger);\n }\n\n .v-input-otp-literal {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: var(--vectis-color-text-muted);\n font-family: var(--vectis-text-family-code);\n font-size: var(--input-otp-font-size);\n user-select: none;\n }\n\n /*\n * A disabled row greys out through the colour tokens and never through opacity, the same\n * treatment as VInput; `text-muted` inside the box, where `text-subtle` would fall under\n * 4.5:1 against `surface-muted`, and `text-subtle` for what sits on the page.\n */\n .v-input-otp-group[data-disabled] .v-input-otp-input {\n background: var(--vectis-color-surface-muted);\n color: var(--vectis-color-text-muted);\n border-color: var(--vectis-color-border);\n cursor: not-allowed;\n }\n\n .v-input-otp-group[data-disabled] .v-input-otp-literal {\n color: var(--vectis-color-text-subtle);\n }\n\n /* Of the whole size scale, only the raised type is restated here; the dimensions\n themselves come from v-control. */\n .v-input-otp-group[data-size='sm'] {\n --input-otp-font-size: var(--vectis-font-size-md);\n }\n\n .v-input-otp-group[data-size='lg'] {\n --input-otp-font-size: var(--vectis-font-size-xl);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-input-otp-input {\n transition: none;\n }\n }\n}\n</style>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"VInputOTP.js","names":["_sfc_main","VInputOTP_vue_vue_type_script_setup_true_lang_default","VInputOTP_default"],"sources":["../../../src/components/VInputOTP/VInputOTP.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @keyboard @core\n/**\n * Coordinate character inputs because HTML has no segmented code field. JavaScript filters\n * values, distributes paste and moves focus; pattern literals stay outside the model.\n */\n\nimport { computed, ref, useAttrs, watch } from 'vue'\nimport VField from '../VField/VField.vue'\nimport type { FieldLabelPosition } from '../VField/VField.vue'\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport type { IconSource } from '../VIcon/types'\n\nimport { partitionAttrs } from '../../utils/attrs'\nimport { isDev } from '../../utils/env'\n\nimport { useMessages } from '../../i18n/state'\n\n/** The height of the boxes: 32, 40 or 48 pixels. */\nexport type InputOTPSize = 'sm' | 'md' | 'lg'\n\n/** Which characters the code is made of. */\nexport type InputOTPFormat = 'numeric' | 'alpha' | 'alphanumeric'\n\ninterface InputOTPProps {\n /** How many boxes the code has. It is ignored as soon as a `pattern` is given. */\n length?: number\n /**\n * Which characters the code is made of. It filters what can be typed or pasted, and\n * decides which keyboard a phone offers.\n */\n format?: InputOTPFormat\n /**\n * The shape of the code: each `#` is a box to fill, and every other character is a separator\n * shown between the boxes without ever being part of the value, as in `'GT-###'` or\n * `'###.###.###'`.\n */\n pattern?: string\n /** An icon drawn in place of every separator of the pattern. */\n separatorIcon?: IconSource\n /** The size of the boxes: 32, 40 or 48 pixels. */\n size?: InputOTPSize\n /** Makes every box unusable, greyed out through the colour tokens. */\n disabled?: boolean\n /**\n * Shows the code without letting it be changed. The boxes keep their focus and the code can\n * still be selected and copied, which separates it from `disabled`.\n */\n readonly?: boolean\n /** Marks the code as wrong, which colours the boxes and tells assistive technology so. */\n invalid?: boolean\n /**\n * The label above the boxes, which names the row. Without it, the row is named by its\n * `aria-label` or by the design system dictionary.\n */\n label?: string\n /**\n * A line of help under the boxes: where the code was sent, how long it lasts. It is\n * tied to the row for assistive technology, so it is read out along with the label.\n */\n hint?: string\n /**\n * A message saying what is wrong with the value, shown in place of the hint so that the field\n * does not grow. It marks the field invalid, is read along with it, and is announced when it\n * appears or changes.\n */\n error?: string\n /**\n * Marks the code as required: an asterisk follows the label, and the hidden input a form reads\n * is `required`.\n */\n required?: boolean\n /** Hides the label visually. It still names the row for assistive technology. */\n hideLabel?: boolean\n /**\n * Where the label sits: above the boxes (`top`, the default), or at their start, in a column\n * of its own, moving back above when there is not room for both.\n */\n labelPosition?: FieldLabelPosition\n}\n\nconst props = withDefaults(defineProps<InputOTPProps>(), {\n length: 6,\n format: 'numeric',\n pattern: undefined,\n separatorIcon: undefined,\n size: 'md',\n disabled: false,\n readonly: false,\n invalid: false,\n label: undefined,\n hint: undefined,\n error: undefined,\n required: false,\n hideLabel: false,\n labelPosition: 'top',\n})\n\nconst m = useMessages()\n\n// @a11y\n/*\n * `aria-describedby` is a list, and the hint is appended to whatever the consumer already\n * pointed at instead of replacing it; left to the fallthrough, their value would land last and\n * take the hint out of the announcement with nothing to show for it.\n */\ndefineOptions({ inheritAttrs: false })\n\nconst attrs = useAttrs()\n\n// What the FORM reads goes on the hidden native input, and everything else on the group:\n// on the group a `name` submits nothing and `required` validates nothing, silently.\nconst NATIVE_ONLY = ['name', 'form']\nconst split = computed(() => partitionAttrs(attrs, NATIVE_ONLY))\nconst groupAttrs = computed(() => split.value.rest)\nconst nativeAttrs = computed(() => split.value.picked)\n// @a11y\n// The row has no visible label to be named by when a consumer gives none or names it\n// themselves (VField's group mode): the dictionary names it then.\nfunction rowLabel(fieldProps: Record<string, unknown>): string | undefined {\n if (fieldProps['aria-labelledby']) return undefined\n return (fieldProps['aria-label'] as string | undefined) ?? m.value.inputOTP.label\n}\n\nconst isInvalid = computed(() => props.invalid || !!props.error)\n\n/**\n * The code as one string, without the separators: a `GT-###` template still yields three\n * characters. It is empty to begin with, and shorter than the full length while it is being\n * typed.\n */\nconst model = defineModel<string>({ default: '' })\n\nconst emit = defineEmits<{\n /**\n * Emitted the moment the code BECOMES complete, carrying it. Retyping a character of a\n * complete code with the same one does not emit it again.\n */\n complete: [code: string]\n}>()\n\ntype Cell = { type: 'slot'; slotIndex: number } | { type: 'literal'; char: string }\n\nconst cells = computed<Cell[]>(() => {\n if (props.pattern?.includes('#')) {\n let slotIndex = 0\n return [...props.pattern].map((char): Cell =>\n char === '#' ? { type: 'slot', slotIndex: slotIndex++ } : { type: 'literal', char },\n )\n }\n return Array.from({ length: props.length }, (_, i) => ({ type: 'slot', slotIndex: i }))\n})\nconst slotCount = computed(() => cells.value.filter((cell) => cell.type === 'slot').length)\n\n// @devwarn\nif (isDev) {\n if (props.pattern && !props.pattern.includes('#'))\n console.warn(\"[VInputOTP] pattern without '#' — falling back to `length`.\")\n}\n\nconst filters: Record<InputOTPFormat, RegExp> = {\n numeric: /[^0-9]/g,\n alpha: /[^A-Z]/g,\n alphanumeric: /[^A-Z0-9]/g,\n}\n\n/**\n * Keeps only what the format allows. Outside a numeric code the text is put in\n * capitals first, so that the value has a single canonical form whichever case the\n * reader typed or pasted.\n */\nfunction sanitize(text: string) {\n const upper = props.format === 'numeric' ? text : text.toUpperCase()\n return upper.replace(filters[props.format], '')\n}\n\nconst rootEl = ref<HTMLElement | null>(null)\nconst digits = ref<string[]>([])\n\n// @keyboard\n// Read the rendered order on demand; changing a pattern can move or replace its input cells.\nfunction inputAt(slot: number) {\n return rootEl.value?.querySelectorAll<HTMLInputElement>('.v-input-otp-input')[slot]\n}\n\nfunction syncFromModel(value: string) {\n // A value longer than the row is simply shown cut short, and one holding characters the\n // format refuses is shown filtered; but the model is not rewritten to match: writing back\n // here would feed the watcher below and the two would keep correcting each other.\n const clean = sanitize(value)\n digits.value = Array.from({ length: slotCount.value }, (_, i) => clean[i] ?? '')\n}\nsyncFromModel(model.value)\nwatch([model, slotCount], ([value, count]) => {\n if (value !== digits.value.join('') || digits.value.length !== count) syncFromModel(value)\n})\n\n/** The first empty box, or -1 once the code is complete. Every box before it is filled. */\nconst firstEmpty = () => digits.value.findIndex((d) => !d)\n\n/** The furthest box the focus may reach: the first empty one, or the last of a full code. */\nfunction reachable() {\n const empty = firstEmpty()\n return empty === -1 ? slotCount.value - 1 : empty\n}\n\n/** Takes a character out and moves the following ones back, so no gap is left behind. */\nfunction removeAt(slot: number) {\n digits.value.splice(slot, 1)\n digits.value.push('')\n}\n\nfunction focusBox(slot: number) {\n const el = inputAt(slot)\n el?.focus()\n // Selected, so the next keystroke REPLACES the character: a box that already has the\n // focus receives no focus event to select it.\n el?.select()\n}\n\nfunction commit() {\n const code = digits.value.join('')\n const previous = model.value\n model.value = code\n // Only when the code CHANGES into a full one: retyping a character of a complete code\n // must not submit it a second time for a consumer listening to `complete`.\n if (code.length === slotCount.value && code !== previous) emit('complete', code)\n}\n\n// @core\n/**\n * Spreads a run of characters across the boxes, starting from the one that received them. It\n * returns the last box it filled, so the caller knows where to put the focus, and `null` when\n * nothing in the text was usable.\n */\nfunction distribute(raw: string, startSlot: number): number | null {\n const allCells = cells.value\n let start = allCells.findIndex((cell) => cell.type === 'slot' && cell.slotIndex === startSlot)\n const chars = [...raw]\n // Never for ONE character: a `G` typed into the first box of `GT-###` is the code's first\n // character, not the separator, and swallowing it would make such a code impossible to type.\n if (chars.length > 1) while (start > 0 && allCells[start - 1]?.type === 'literal') start--\n let charIndex = 0\n let lastFilled: number | null = null\n for (const cell of allCells.slice(start)) {\n if (charIndex >= chars.length) break\n if (cell.type === 'literal') {\n if (chars[charIndex]?.toUpperCase() === cell.char.toUpperCase()) charIndex++\n continue\n }\n let char = ''\n while (charIndex < chars.length && !char) {\n char = sanitize(chars[charIndex] ?? '')\n charIndex++\n }\n if (!char) break\n digits.value[cell.slotIndex] = char\n lastFilled = cell.slotIndex\n }\n return lastFilled\n}\n\n// @keyboard @core\n// Separate inputs into something that types like one field; spreading the characters is the\n// core behaviour underneath it.\nfunction onInput(slotIndex: number, event: Event) {\n const el = event.target as HTMLInputElement\n const empty = firstEmpty()\n const filled = empty === -1 || slotIndex < empty\n\n // A filled box whose character was not selected receives the new one NEXT to it. What\n // was inserted is what lies just before the caret, and it is what counts.\n const previous = digits.value[slotIndex] ?? ''\n let raw = el.value\n const inserted = raw.length - previous.length\n if (previous && inserted > 0 && el.selectionStart !== null) {\n raw = raw.slice(Math.max(0, el.selectionStart - inserted), el.selectionStart)\n }\n\n // The same path serves a single keystroke and a pasted code: both are spread from this box\n // onwards; or from the first empty box, when this one lies past it.\n const lastFilled = distribute(raw, filled ? slotIndex : empty)\n if (lastFilled === null) {\n // Either the box was emptied, or nothing typed was valid for this format. A filled box\n // loses its character and the ones after it close the gap.\n if (filled) removeAt(slotIndex)\n el.value = digits.value[slotIndex] ?? ''\n commit()\n return\n }\n // Written by hand: when the characters went to another box, this one's value is still\n // '' in the render, and the patch would leave the typed character on screen.\n el.value = digits.value[slotIndex] ?? ''\n focusBox(Math.min(lastFilled + 1, slotCount.value - 1))\n commit()\n}\n\n// @keyboard\n// Sends the focus there instead: a pointer landing on box 5 of a two-character code types into\n// box 3.\nfunction onFocus(slotIndex: number, event: FocusEvent) {\n const empty = firstEmpty()\n if (empty !== -1 && slotIndex > empty) inputAt(empty)?.focus()\n else (event.target as HTMLInputElement).select()\n}\n\n// @keyboard\nfunction onKeydown(slotIndex: number, event: KeyboardEvent) {\n const last = reachable()\n let target: number | null = null\n switch (event.key) {\n case 'Backspace':\n // A read-only box refuses its own edits natively, but this erases ANOTHER box, which\n // nothing native guards.\n if (props.readonly || props.disabled || digits.value[slotIndex] || slotIndex === 0) return\n removeAt(slotIndex - 1)\n commit()\n target = slotIndex - 1\n break\n case 'ArrowLeft':\n if (slotIndex > 0) target = slotIndex - 1\n break\n case 'ArrowRight':\n if (slotIndex < last) target = slotIndex + 1\n break\n case 'Home':\n target = 0\n break\n case 'End':\n target = last\n break\n }\n if (target === null) return\n event.preventDefault()\n focusBox(target)\n}\n\ndefineExpose({\n /** Moves the focus to the first empty box, or to the last one when the code is complete. */\n focus: (options?: FocusOptions) => inputAt(reachable())?.focus(options),\n /** Selects the box the focus is on, as clicking into one already does. */\n select: () => {\n const active = rootEl.value?.querySelector<HTMLInputElement>('.v-input-otp-input:focus')\n ;(active ?? inputAt(0))?.select()\n },\n /** The row itself, for what neither of the two above covers. */\n el: rootEl,\n})\n</script>\n\n<template>\n <VField\n v-bind=\"groupAttrs\"\n class=\"v-input-otp\"\n :label=\"label\"\n :hint=\"hint\"\n :error=\"error\"\n :required=\"required\"\n :disabled=\"disabled\"\n :hide-label=\"hideLabel\"\n :label-position=\"labelPosition\"\n group\n >\n <template #default=\"{ fieldProps }\">\n <div\n ref=\"rootEl\"\n v-bind=\"fieldProps\"\n class=\"v-input-otp-group v-control\"\n role=\"group\"\n :aria-label=\"rowLabel(fieldProps)\"\n :data-invalid=\"isInvalid ? '' : undefined\"\n :data-size=\"size\"\n :data-disabled=\"disabled ? '' : undefined\"\n :data-readonly=\"readonly ? '' : undefined\"\n >\n <div class=\"v-input-otp-boxes\">\n <template v-for=\"(cell, i) in cells\" :key=\"i\">\n <input\n v-if=\"cell.type === 'slot'\"\n type=\"text\"\n class=\"v-input-otp-input\"\n :inputmode=\"format === 'numeric' ? 'numeric' : 'text'\"\n :autocomplete=\"cell.slotIndex === 0 ? 'one-time-code' : 'off'\"\n :value=\"digits[cell.slotIndex]\"\n :disabled=\"disabled\"\n :readonly=\"readonly || undefined\"\n :aria-label=\"m.inputOTP.slot(cell.slotIndex + 1, slotCount)\"\n :aria-invalid=\"isInvalid || undefined\"\n @input=\"onInput(cell.slotIndex, $event)\"\n @keydown=\"onKeydown(cell.slotIndex, $event)\"\n @focus=\"onFocus(cell.slotIndex, $event)\"\n />\n <!-- A separator from the pattern: shown, never focusable, and never part of the\n value. It is hidden from screen readers, each box already announcing its\n own position in the code. -->\n <span v-else class=\"v-input-otp-literal\" aria-hidden=\"true\">\n <VIcon v-if=\"separatorIcon\" v-bind=\"iconProps(separatorIcon)\" />\n <template v-else>{{ cell.char }}</template>\n </span>\n </template>\n </div>\n\n <!--\n Out of the tab order and hidden from assistive technology, the boxes being the control; a\n browser focusing it to report an invalid code is sent on to the box to fill.\n -->\n <input\n v-bind=\"nativeAttrs\"\n class=\"v-input-otp-native v-visually-hidden\"\n type=\"text\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n autocomplete=\"off\"\n :value=\"model\"\n :pattern=\"`.{${slotCount}}`\"\n :required=\"required || undefined\"\n :disabled=\"disabled\"\n :readonly=\"readonly || undefined\"\n @focus=\"focusBox(reachable())\"\n />\n </div>\n </template>\n </VField>\n</template>\n\n<style>\n@layer vectis.components {\n /* Its own width rather than the line's, so that a start label stays next to the boxes. */\n .v-input-otp.v-field {\n display: inline-flex;\n align-items: start;\n }\n\n .v-input-otp-group {\n /*\n * The heights and the icon context come from the shared v-control class\n * (styles/control-size.css). The type is the one thing kept local, and set one or\n * two steps above the other fields: a single character has a whole square to\n * itself, and at the usual field size it would look lost in it.\n */\n --input-otp-font-size: var(--vectis-font-size-lg);\n }\n\n /* A code reads left to right in every language, like the HH:MM of VTimeInput: mirrored\n under `dir=\"rtl\"`, the arrows would walk against the boxes and a `GT-###` pattern would\n be drawn backwards. */\n .v-input-otp-boxes {\n direction: ltr;\n display: flex;\n align-items: center;\n gap: var(--control-gap);\n }\n\n .v-input-otp-input {\n /* The boxes are square: reading the same variable for both dimensions is what\n makes the size and the density scale them together. */\n width: var(--control-height);\n height: var(--control-height);\n text-align: center;\n background: var(--vectis-color-surface);\n color: var(--vectis-color-text);\n border: 1px solid var(--vectis-color-border-strong);\n border-radius: var(--vectis-radius-interactive);\n font-family: var(--vectis-text-family-code);\n font-size: var(--input-otp-font-size);\n transition:\n border-color var(--vectis-duration-fast) var(--vectis-ease-default),\n box-shadow var(--vectis-duration-fast) var(--vectis-ease-default),\n background-color var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n\n /*\n * The states follow VInput's, in VInput's order: read-only, hover, focus, invalid, disabled.\n * Read-only, focus, invalid and disabled all weigh (0,2,0), so the source order arbitrates\n * between them and read-only has to come first, or it would repaint the focus and error\n * borders grey.\n */\n .v-input-otp-group[data-readonly] .v-input-otp-input {\n background: var(--vectis-color-surface-sunken);\n border-color: var(--vectis-color-border);\n }\n\n /* The hover weighs (0,5,0) and keeps itself off a focused, invalid or disabled box\n through its own `:not()`, as VInput's does. */\n .v-input-otp-group:not([data-invalid]) .v-input-otp-input:hover:not(:focus, :disabled) {\n border-color: color-mix(\n in oklab,\n var(--vectis-color-border-strong),\n var(--vectis-color-text) 15%\n );\n }\n\n /*\n * `:focus` rather than `:focus-visible`, like any text field, which shows its focus when\n * clicked into too. The transparent outline is the safety net for Windows forced colours,\n * which drop box-shadows entirely.\n */\n .v-input-otp-input:focus {\n border-color: var(--vectis-color-accent);\n box-shadow: 0 0 0 1px var(--vectis-color-accent);\n outline: var(--vectis-focus-ring-width) solid transparent;\n }\n\n .v-input-otp-group[data-invalid] .v-input-otp-input {\n border-color: var(--vectis-color-danger);\n }\n\n .v-input-otp-group[data-invalid] .v-input-otp-input:focus {\n box-shadow: 0 0 0 1px var(--vectis-color-danger);\n }\n\n .v-input-otp-literal {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: var(--vectis-color-text-muted);\n font-family: var(--vectis-text-family-code);\n font-size: var(--input-otp-font-size);\n user-select: none;\n }\n\n /*\n * A disabled row greys out through the colour tokens and never through opacity, the same\n * treatment as VInput; `text-muted` inside the box, where `text-subtle` would fall under\n * 4.5:1 against `surface-muted`, and `text-subtle` for what sits on the page.\n */\n .v-input-otp-group[data-disabled] .v-input-otp-input {\n background: var(--vectis-color-surface-muted);\n color: var(--vectis-color-text-muted);\n border-color: var(--vectis-color-border);\n cursor: not-allowed;\n }\n\n .v-input-otp-group[data-disabled] .v-input-otp-literal {\n color: var(--vectis-color-text-subtle);\n }\n\n /* Of the whole size scale, only the raised type is restated here; the dimensions\n themselves come from v-control. */\n .v-input-otp-group[data-size='sm'] {\n --input-otp-font-size: var(--vectis-font-size-md);\n }\n\n .v-input-otp-group[data-size='lg'] {\n --input-otp-font-size: var(--vectis-font-size-xl);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-input-otp-input {\n transition: none;\n }\n }\n}\n</style>\n"],"mappings":""}
|
|
@@ -10,7 +10,6 @@ var w = [
|
|
|
10
10
|
"aria-label",
|
|
11
11
|
"data-invalid",
|
|
12
12
|
"data-size",
|
|
13
|
-
"data-compact",
|
|
14
13
|
"data-disabled",
|
|
15
14
|
"data-readonly"
|
|
16
15
|
], T = { class: "v-input-otp-boxes" }, E = [
|
|
@@ -43,10 +42,6 @@ var w = [
|
|
|
43
42
|
pattern: { default: void 0 },
|
|
44
43
|
separatorIcon: { default: void 0 },
|
|
45
44
|
size: { default: "md" },
|
|
46
|
-
compact: {
|
|
47
|
-
type: Boolean,
|
|
48
|
-
default: !1
|
|
49
|
-
},
|
|
50
45
|
disabled: {
|
|
51
46
|
type: Boolean,
|
|
52
47
|
default: !1
|
|
@@ -154,11 +149,7 @@ var w = [
|
|
|
154
149
|
let n = t.target, r = Y(), i = r === -1 || e < r, a = K.value[e] ?? "", o = n.value, s = o.length - a.length;
|
|
155
150
|
a && s > 0 && n.selectionStart !== null && (o = o.slice(Math.max(0, n.selectionStart - s), n.selectionStart));
|
|
156
151
|
let c = ee(o, i ? e : r);
|
|
157
|
-
|
|
158
|
-
i && Z(e), n.value = K.value[e] ?? "", $();
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
n.value = K.value[e] ?? "", Q(Math.min(c + 1, H.value - 1)), $();
|
|
152
|
+
c === null ? (i && Z(e), n.value = K.value[e] ?? "", $()) : (n.value = K.value[e] ?? "", Q(Math.min(c + 1, H.value - 1)), $());
|
|
162
153
|
}
|
|
163
154
|
function ne(e, t) {
|
|
164
155
|
let n = Y();
|
|
@@ -180,9 +171,7 @@ var w = [
|
|
|
180
171
|
case "Home":
|
|
181
172
|
r = 0;
|
|
182
173
|
break;
|
|
183
|
-
case "End":
|
|
184
|
-
r = n;
|
|
185
|
-
break;
|
|
174
|
+
case "End": r = n;
|
|
186
175
|
}
|
|
187
176
|
r !== null && (t.preventDefault(), Q(r));
|
|
188
177
|
}
|
|
@@ -212,7 +201,6 @@ var w = [
|
|
|
212
201
|
"aria-label": L(e),
|
|
213
202
|
"data-invalid": R.value ? "" : void 0,
|
|
214
203
|
"data-size": f.size,
|
|
215
|
-
"data-compact": f.compact ? "" : void 0,
|
|
216
204
|
"data-disabled": f.disabled ? "" : void 0,
|
|
217
205
|
"data-readonly": f.readonly ? "" : void 0
|
|
218
206
|
}), [u("div", T, [(h(!0), l(o, null, _(V.value, (e, t) => (h(), l(o, { key: t }, [e.type === "slot" ? (h(), l("input", {
|