vectis-ui 0.1.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/LICENSE +21 -0
- package/NOTICE +27 -0
- package/README.md +354 -0
- package/dist/_virtual/_plugin-vue_export-helper.js +8 -0
- package/dist/components/VAccordion/VAccordion.css +2 -0
- package/dist/components/VAccordion/VAccordion.d.ts +59 -0
- package/dist/components/VAccordion/VAccordion.js +9 -0
- package/dist/components/VAccordion/VAccordion.js.map +1 -0
- package/dist/components/VAccordion/VAccordion.vue_vue_type_script_setup_true_lang.js +42 -0
- package/dist/components/VAccordion/VAccordion.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VAccordion/VAccordionItem.css +2 -0
- package/dist/components/VAccordion/VAccordionItem.d.ts +64 -0
- package/dist/components/VAccordion/VAccordionItem.js +9 -0
- package/dist/components/VAccordion/VAccordionItem.js.map +1 -0
- package/dist/components/VAccordion/VAccordionItem.vue_vue_type_script_setup_true_lang.js +70 -0
- package/dist/components/VAccordion/VAccordionItem.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VAccordion/context.d.ts +18 -0
- package/dist/components/VAccordion/context.js +6 -0
- package/dist/components/VAccordion/context.js.map +1 -0
- package/dist/components/VAvatar/VAvatar.css +2 -0
- package/dist/components/VAvatar/VAvatar.d.ts +68 -0
- package/dist/components/VAvatar/VAvatar.js +9 -0
- package/dist/components/VAvatar/VAvatar.js.map +1 -0
- package/dist/components/VAvatar/VAvatar.vue_vue_type_script_setup_true_lang.js +87 -0
- package/dist/components/VAvatar/VAvatar.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VAvatar/VAvatarGroup.css +2 -0
- package/dist/components/VAvatar/VAvatarGroup.d.ts +59 -0
- package/dist/components/VAvatar/VAvatarGroup.js +9 -0
- package/dist/components/VAvatar/VAvatarGroup.js.map +1 -0
- package/dist/components/VAvatar/VAvatarGroup.vue_vue_type_script_setup_true_lang.js +43 -0
- package/dist/components/VAvatar/VAvatarGroup.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VAvatar/context.d.ts +17 -0
- package/dist/components/VAvatar/context.js +6 -0
- package/dist/components/VAvatar/context.js.map +1 -0
- package/dist/components/VBadge/VBadge.css +2 -0
- package/dist/components/VBadge/VBadge.d.ts +74 -0
- package/dist/components/VBadge/VBadge.js +9 -0
- package/dist/components/VBadge/VBadge.js.map +1 -0
- package/dist/components/VBadge/VBadge.vue_vue_type_script_setup_true_lang.js +40 -0
- package/dist/components/VBadge/VBadge.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VBreadcrumb/VBreadcrumb.css +2 -0
- package/dist/components/VBreadcrumb/VBreadcrumb.d.ts +68 -0
- package/dist/components/VBreadcrumb/VBreadcrumb.js +9 -0
- package/dist/components/VBreadcrumb/VBreadcrumb.js.map +1 -0
- package/dist/components/VBreadcrumb/VBreadcrumb.vue_vue_type_script_setup_true_lang.js +70 -0
- package/dist/components/VBreadcrumb/VBreadcrumb.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VButton/VButton.css +2 -0
- package/dist/components/VButton/VButton.d.ts +88 -0
- package/dist/components/VButton/VButton.js +9 -0
- package/dist/components/VButton/VButton.js.map +1 -0
- package/dist/components/VButton/VButton.vue_vue_type_script_setup_true_lang.js +86 -0
- package/dist/components/VButton/VButton.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VButton/VButtonGroup.css +2 -0
- package/dist/components/VButton/VButtonGroup.d.ts +32 -0
- package/dist/components/VButton/VButtonGroup.js +9 -0
- package/dist/components/VButton/VButtonGroup.js.map +1 -0
- package/dist/components/VButton/VButtonGroup.vue_vue_type_script_setup_true_lang.js +17 -0
- package/dist/components/VButton/VButtonGroup.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VCalendar/VCalendar.css +2 -0
- package/dist/components/VCalendar/VCalendar.d.ts +129 -0
- package/dist/components/VCalendar/VCalendar.js +9 -0
- package/dist/components/VCalendar/VCalendar.js.map +1 -0
- package/dist/components/VCalendar/VCalendar.vue_vue_type_script_setup_true_lang.js +374 -0
- package/dist/components/VCalendar/VCalendar.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VCalendar/VCalendarEvent.css +2 -0
- package/dist/components/VCalendar/VCalendarEvent.d.ts +71 -0
- package/dist/components/VCalendar/VCalendarEvent.js +9 -0
- package/dist/components/VCalendar/VCalendarEvent.js.map +1 -0
- package/dist/components/VCalendar/VCalendarEvent.vue_vue_type_script_setup_true_lang.js +106 -0
- package/dist/components/VCalendar/VCalendarEvent.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VCalendar/VCalendarMonth.css +2 -0
- package/dist/components/VCalendar/VCalendarMonth.d.ts +60 -0
- package/dist/components/VCalendar/VCalendarMonth.js +9 -0
- package/dist/components/VCalendar/VCalendarMonth.js.map +1 -0
- package/dist/components/VCalendar/VCalendarMonth.vue_vue_type_script_setup_true_lang.js +342 -0
- package/dist/components/VCalendar/VCalendarMonth.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VCalendar/VCalendarTimeGrid.css +2 -0
- package/dist/components/VCalendar/VCalendarTimeGrid.d.ts +85 -0
- package/dist/components/VCalendar/VCalendarTimeGrid.js +9 -0
- package/dist/components/VCalendar/VCalendarTimeGrid.js.map +1 -0
- package/dist/components/VCalendar/VCalendarTimeGrid.vue_vue_type_script_setup_true_lang.js +621 -0
- package/dist/components/VCalendar/VCalendarTimeGrid.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VCalendar/VCalendarYear.css +2 -0
- package/dist/components/VCalendar/VCalendarYear.d.ts +31 -0
- package/dist/components/VCalendar/VCalendarYear.js +9 -0
- package/dist/components/VCalendar/VCalendarYear.js.map +1 -0
- package/dist/components/VCalendar/VCalendarYear.vue_vue_type_script_setup_true_lang.js +76 -0
- package/dist/components/VCalendar/VCalendarYear.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VCalendar/color.d.ts +9 -0
- package/dist/components/VCalendar/color.js +9 -0
- package/dist/components/VCalendar/color.js.map +1 -0
- package/dist/components/VCalendar/edgeStep.d.ts +38 -0
- package/dist/components/VCalendar/edgeStep.js +28 -0
- package/dist/components/VCalendar/edgeStep.js.map +1 -0
- package/dist/components/VCalendar/keyboard.d.ts +78 -0
- package/dist/components/VCalendar/keyboard.js +86 -0
- package/dist/components/VCalendar/keyboard.js.map +1 -0
- package/dist/components/VCalendar/layout.d.ts +355 -0
- package/dist/components/VCalendar/layout.js +292 -0
- package/dist/components/VCalendar/layout.js.map +1 -0
- package/dist/components/VCalendar/types.d.ts +78 -0
- package/dist/components/VCarousel/VCarousel.css +2 -0
- package/dist/components/VCarousel/VCarousel.d.ts +241 -0
- package/dist/components/VCarousel/VCarousel.js +9 -0
- package/dist/components/VCarousel/VCarousel.js.map +1 -0
- package/dist/components/VCarousel/VCarousel.vue_vue_type_script_setup_true_lang.js +262 -0
- package/dist/components/VCarousel/VCarousel.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VCarousel/VCarouselItem.d.ts +41 -0
- package/dist/components/VCarousel/VCarouselItem.js +7 -0
- package/dist/components/VCarousel/VCarouselItem.js.map +1 -0
- package/dist/components/VCarousel/VCarouselItem.vue_vue_type_script_setup_true_lang.js +25 -0
- package/dist/components/VCarousel/VCarouselItem.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VCarousel/context.d.ts +23 -0
- package/dist/components/VCarousel/context.js +6 -0
- package/dist/components/VCarousel/context.js.map +1 -0
- package/dist/components/VCheckbox/VCheckbox.css +2 -0
- package/dist/components/VCheckbox/VCheckbox.d.ts +63 -0
- package/dist/components/VCheckbox/VCheckbox.js +9 -0
- package/dist/components/VCheckbox/VCheckbox.js.map +1 -0
- package/dist/components/VCheckbox/VCheckbox.vue_vue_type_script_setup_true_lang.js +83 -0
- package/dist/components/VCheckbox/VCheckbox.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VChip/VChip.css +2 -0
- package/dist/components/VChip/VChip.d.ts +120 -0
- package/dist/components/VChip/VChip.js +9 -0
- package/dist/components/VChip/VChip.js.map +1 -0
- package/dist/components/VChip/VChip.vue_vue_type_script_setup_true_lang.js +118 -0
- package/dist/components/VChip/VChip.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VCombobox/VCombobox.css +2 -0
- package/dist/components/VCombobox/VCombobox.d.ts +183 -0
- package/dist/components/VCombobox/VCombobox.js +9 -0
- package/dist/components/VCombobox/VCombobox.js.map +1 -0
- package/dist/components/VCombobox/VCombobox.vue_vue_type_script_setup_true_lang.js +428 -0
- package/dist/components/VCombobox/VCombobox.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VCombobox/VComboboxGroup.css +2 -0
- package/dist/components/VCombobox/VComboboxGroup.d.ts +26 -0
- package/dist/components/VCombobox/VComboboxGroup.js +9 -0
- package/dist/components/VCombobox/VComboboxGroup.js.map +1 -0
- package/dist/components/VCombobox/VComboboxGroup.vue_vue_type_script_setup_true_lang.js +21 -0
- package/dist/components/VCombobox/VComboboxGroup.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VCombobox/VComboboxOption.css +2 -0
- package/dist/components/VCombobox/VComboboxOption.d.ts +48 -0
- package/dist/components/VCombobox/VComboboxOption.js +9 -0
- package/dist/components/VCombobox/VComboboxOption.js.map +1 -0
- package/dist/components/VCombobox/VComboboxOption.vue_vue_type_script_setup_true_lang.js +56 -0
- package/dist/components/VCombobox/VComboboxOption.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VCombobox/VComboboxSeparator.css +2 -0
- package/dist/components/VCombobox/VComboboxSeparator.d.ts +3 -0
- package/dist/components/VCombobox/VComboboxSeparator.js +9 -0
- package/dist/components/VCombobox/VComboboxSeparator.js.map +1 -0
- package/dist/components/VCombobox/VComboboxSeparator.vue_vue_type_script_setup_true_lang.js +16 -0
- package/dist/components/VCombobox/VComboboxSeparator.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VCombobox/infiniteScroll.d.ts +22 -0
- package/dist/components/VCombobox/infiniteScroll.js +28 -0
- package/dist/components/VCombobox/infiniteScroll.js.map +1 -0
- package/dist/components/VDataTable/VDataTable.css +2 -0
- package/dist/components/VDataTable/VDataTable.d.ts +214 -0
- package/dist/components/VDataTable/VDataTable.js +9 -0
- package/dist/components/VDataTable/VDataTable.js.map +1 -0
- package/dist/components/VDataTable/VDataTable.vue_vue_type_script_setup_true_lang.js +396 -0
- package/dist/components/VDataTable/VDataTable.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VDateInput/VDateInput.css +2 -0
- package/dist/components/VDateInput/VDateInput.d.ts +152 -0
- package/dist/components/VDateInput/VDateInput.js +9 -0
- package/dist/components/VDateInput/VDateInput.js.map +1 -0
- package/dist/components/VDateInput/VDateInput.vue_vue_type_script_setup_true_lang.js +324 -0
- package/dist/components/VDateInput/VDateInput.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VDatePicker/VDatePicker.css +2 -0
- package/dist/components/VDatePicker/VDatePicker.d.ts +143 -0
- package/dist/components/VDatePicker/VDatePicker.js +9 -0
- package/dist/components/VDatePicker/VDatePicker.js.map +1 -0
- package/dist/components/VDatePicker/VDatePicker.vue_vue_type_script_setup_true_lang.js +454 -0
- package/dist/components/VDatePicker/VDatePicker.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VDatePicker/keyboard.d.ts +56 -0
- package/dist/components/VDatePicker/keyboard.js +26 -0
- package/dist/components/VDatePicker/keyboard.js.map +1 -0
- package/dist/components/VDialog/VDialog.css +2 -0
- package/dist/components/VDialog/VDialog.d.ts +96 -0
- package/dist/components/VDialog/VDialog.js +9 -0
- package/dist/components/VDialog/VDialog.js.map +1 -0
- package/dist/components/VDialog/VDialog.vue_vue_type_script_setup_true_lang.js +134 -0
- package/dist/components/VDialog/VDialog.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VDialog/VDialogAlert.d.ts +67 -0
- package/dist/components/VDialog/VDialogAlert.js +7 -0
- package/dist/components/VDialog/VDialogAlert.js.map +1 -0
- package/dist/components/VDialog/VDialogAlert.vue_vue_type_script_setup_true_lang.js +60 -0
- package/dist/components/VDialog/VDialogAlert.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VFileInput/VFileInput.css +2 -0
- package/dist/components/VFileInput/VFileInput.d.ts +156 -0
- package/dist/components/VFileInput/VFileInput.js +9 -0
- package/dist/components/VFileInput/VFileInput.js.map +1 -0
- package/dist/components/VFileInput/VFileInput.vue_vue_type_script_setup_true_lang.js +244 -0
- package/dist/components/VFileInput/VFileInput.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VFileInput/truncate.d.ts +29 -0
- package/dist/components/VFileInput/truncate.js +10 -0
- package/dist/components/VFileInput/truncate.js.map +1 -0
- package/dist/components/VFilePicker/VFilePicker.css +2 -0
- package/dist/components/VFilePicker/VFilePicker.d.ts +203 -0
- package/dist/components/VFilePicker/VFilePicker.js +9 -0
- package/dist/components/VFilePicker/VFilePicker.js.map +1 -0
- package/dist/components/VFilePicker/VFilePicker.vue_vue_type_script_setup_true_lang.js +266 -0
- package/dist/components/VFilePicker/VFilePicker.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VFilePicker/fileKind.d.ts +29 -0
- package/dist/components/VFilePicker/fileKind.js +91 -0
- package/dist/components/VFilePicker/fileKind.js.map +1 -0
- package/dist/components/VHotkeys/VHotkeys.css +2 -0
- package/dist/components/VHotkeys/VHotkeys.d.ts +100 -0
- package/dist/components/VHotkeys/VHotkeys.js +9 -0
- package/dist/components/VHotkeys/VHotkeys.js.map +1 -0
- package/dist/components/VHotkeys/VHotkeys.vue_vue_type_script_setup_true_lang.js +76 -0
- package/dist/components/VHotkeys/VHotkeys.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VHotkeys/platform.d.ts +82 -0
- package/dist/components/VHotkeys/platform.js +115 -0
- package/dist/components/VHotkeys/platform.js.map +1 -0
- package/dist/components/VIcon/VIcon.css +2 -0
- package/dist/components/VIcon/VIcon.d.ts +57 -0
- package/dist/components/VIcon/VIcon.js +9 -0
- package/dist/components/VIcon/VIcon.js.map +1 -0
- package/dist/components/VIcon/VIcon.vue_vue_type_script_setup_true_lang.js +99 -0
- package/dist/components/VIcon/VIcon.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VIcon/iconProps.d.ts +30 -0
- package/dist/components/VIcon/iconProps.js +6 -0
- package/dist/components/VIcon/iconProps.js.map +1 -0
- package/dist/components/VIcon/icons/arrow_downward.d.ts +5 -0
- package/dist/components/VIcon/icons/arrow_downward.js +9 -0
- package/dist/components/VIcon/icons/arrow_downward.js.map +1 -0
- package/dist/components/VIcon/icons/arrow_downward_alt.d.ts +5 -0
- package/dist/components/VIcon/icons/arrow_downward_alt.js +9 -0
- package/dist/components/VIcon/icons/arrow_downward_alt.js.map +1 -0
- package/dist/components/VIcon/icons/arrow_drop_down.d.ts +5 -0
- package/dist/components/VIcon/icons/arrow_drop_down.js +9 -0
- package/dist/components/VIcon/icons/arrow_drop_down.js.map +1 -0
- package/dist/components/VIcon/icons/arrow_drop_up.d.ts +5 -0
- package/dist/components/VIcon/icons/arrow_drop_up.js +9 -0
- package/dist/components/VIcon/icons/arrow_drop_up.js.map +1 -0
- package/dist/components/VIcon/icons/arrow_left_alt.d.ts +5 -0
- package/dist/components/VIcon/icons/arrow_left_alt.js +9 -0
- package/dist/components/VIcon/icons/arrow_left_alt.js.map +1 -0
- package/dist/components/VIcon/icons/arrow_right_alt.d.ts +5 -0
- package/dist/components/VIcon/icons/arrow_right_alt.js +9 -0
- package/dist/components/VIcon/icons/arrow_right_alt.js.map +1 -0
- package/dist/components/VIcon/icons/arrow_upward.d.ts +5 -0
- package/dist/components/VIcon/icons/arrow_upward.js +9 -0
- package/dist/components/VIcon/icons/arrow_upward.js.map +1 -0
- package/dist/components/VIcon/icons/arrow_upward_alt.d.ts +5 -0
- package/dist/components/VIcon/icons/arrow_upward_alt.js +9 -0
- package/dist/components/VIcon/icons/arrow_upward_alt.js.map +1 -0
- package/dist/components/VIcon/icons/attach_file.d.ts +5 -0
- package/dist/components/VIcon/icons/attach_file.js +9 -0
- package/dist/components/VIcon/icons/attach_file.js.map +1 -0
- package/dist/components/VIcon/icons/audio_file.d.ts +5 -0
- package/dist/components/VIcon/icons/audio_file.js +9 -0
- package/dist/components/VIcon/icons/audio_file.js.map +1 -0
- package/dist/components/VIcon/icons/calendar_today.d.ts +5 -0
- package/dist/components/VIcon/icons/calendar_today.js +9 -0
- package/dist/components/VIcon/icons/calendar_today.js.map +1 -0
- package/dist/components/VIcon/icons/check.d.ts +5 -0
- package/dist/components/VIcon/icons/check.js +9 -0
- package/dist/components/VIcon/icons/check.js.map +1 -0
- package/dist/components/VIcon/icons/check_circle.d.ts +5 -0
- package/dist/components/VIcon/icons/check_circle.js +9 -0
- package/dist/components/VIcon/icons/check_circle.js.map +1 -0
- package/dist/components/VIcon/icons/chevron_left.d.ts +5 -0
- package/dist/components/VIcon/icons/chevron_left.js +9 -0
- package/dist/components/VIcon/icons/chevron_left.js.map +1 -0
- package/dist/components/VIcon/icons/chevron_right.d.ts +5 -0
- package/dist/components/VIcon/icons/chevron_right.js +9 -0
- package/dist/components/VIcon/icons/chevron_right.js.map +1 -0
- package/dist/components/VIcon/icons/close.d.ts +5 -0
- package/dist/components/VIcon/icons/close.js +9 -0
- package/dist/components/VIcon/icons/close.js.map +1 -0
- package/dist/components/VIcon/icons/cloud_upload.d.ts +5 -0
- package/dist/components/VIcon/icons/cloud_upload.js +9 -0
- package/dist/components/VIcon/icons/cloud_upload.js.map +1 -0
- package/dist/components/VIcon/icons/code.d.ts +5 -0
- package/dist/components/VIcon/icons/code.js +9 -0
- package/dist/components/VIcon/icons/code.js.map +1 -0
- package/dist/components/VIcon/icons/description.d.ts +5 -0
- package/dist/components/VIcon/icons/description.js +9 -0
- package/dist/components/VIcon/icons/description.js.map +1 -0
- package/dist/components/VIcon/icons/error.d.ts +5 -0
- package/dist/components/VIcon/icons/error.js +9 -0
- package/dist/components/VIcon/icons/error.js.map +1 -0
- package/dist/components/VIcon/icons/expand_less.d.ts +5 -0
- package/dist/components/VIcon/icons/expand_less.js +9 -0
- package/dist/components/VIcon/icons/expand_less.js.map +1 -0
- package/dist/components/VIcon/icons/expand_more.d.ts +5 -0
- package/dist/components/VIcon/icons/expand_more.js +9 -0
- package/dist/components/VIcon/icons/expand_more.js.map +1 -0
- package/dist/components/VIcon/icons/folder_zip.d.ts +5 -0
- package/dist/components/VIcon/icons/folder_zip.js +9 -0
- package/dist/components/VIcon/icons/folder_zip.js.map +1 -0
- package/dist/components/VIcon/icons/image.d.ts +5 -0
- package/dist/components/VIcon/icons/image.js +9 -0
- package/dist/components/VIcon/icons/image.js.map +1 -0
- package/dist/components/VIcon/icons/index.d.ts +183 -0
- package/dist/components/VIcon/icons/index.js +77 -0
- package/dist/components/VIcon/icons/index.js.map +1 -0
- package/dist/components/VIcon/icons/info.d.ts +5 -0
- package/dist/components/VIcon/icons/info.js +9 -0
- package/dist/components/VIcon/icons/info.js.map +1 -0
- package/dist/components/VIcon/icons/more_horiz.d.ts +5 -0
- package/dist/components/VIcon/icons/more_horiz.js +9 -0
- package/dist/components/VIcon/icons/more_horiz.js.map +1 -0
- package/dist/components/VIcon/icons/names.d.ts +11 -0
- package/dist/components/VIcon/icons/names.js +5 -0
- package/dist/components/VIcon/icons/names.js.map +1 -0
- package/dist/components/VIcon/icons/notifications.d.ts +5 -0
- package/dist/components/VIcon/icons/notifications.js +9 -0
- package/dist/components/VIcon/icons/notifications.js.map +1 -0
- package/dist/components/VIcon/icons/picture_as_pdf.d.ts +5 -0
- package/dist/components/VIcon/icons/picture_as_pdf.js +9 -0
- package/dist/components/VIcon/icons/picture_as_pdf.js.map +1 -0
- package/dist/components/VIcon/icons/schedule.d.ts +5 -0
- package/dist/components/VIcon/icons/schedule.js +9 -0
- package/dist/components/VIcon/icons/schedule.js.map +1 -0
- package/dist/components/VIcon/icons/search.d.ts +5 -0
- package/dist/components/VIcon/icons/search.js +9 -0
- package/dist/components/VIcon/icons/search.js.map +1 -0
- package/dist/components/VIcon/icons/swap_vert.d.ts +5 -0
- package/dist/components/VIcon/icons/swap_vert.js +9 -0
- package/dist/components/VIcon/icons/swap_vert.js.map +1 -0
- package/dist/components/VIcon/icons/table_chart.d.ts +5 -0
- package/dist/components/VIcon/icons/table_chart.js +9 -0
- package/dist/components/VIcon/icons/table_chart.js.map +1 -0
- package/dist/components/VIcon/icons/video_file.d.ts +5 -0
- package/dist/components/VIcon/icons/video_file.js +9 -0
- package/dist/components/VIcon/icons/video_file.js.map +1 -0
- package/dist/components/VIcon/icons/viewBox.d.ts +6 -0
- package/dist/components/VIcon/icons/viewBox.js +6 -0
- package/dist/components/VIcon/icons/viewBox.js.map +1 -0
- package/dist/components/VIcon/icons/warning.d.ts +5 -0
- package/dist/components/VIcon/icons/warning.js +9 -0
- package/dist/components/VIcon/icons/warning.js.map +1 -0
- package/dist/components/VIcon/resolver.d.ts +76 -0
- package/dist/components/VIcon/resolver.js +35 -0
- package/dist/components/VIcon/resolver.js.map +1 -0
- package/dist/components/VIcon/types.d.ts +77 -0
- package/dist/components/VIconButton/VIconButton.css +2 -0
- package/dist/components/VIconButton/VIconButton.d.ts +66 -0
- package/dist/components/VIconButton/VIconButton.js +9 -0
- package/dist/components/VIconButton/VIconButton.js.map +1 -0
- package/dist/components/VIconButton/VIconButton.vue_vue_type_script_setup_true_lang.js +70 -0
- package/dist/components/VIconButton/VIconButton.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VInput/VInput.css +2 -0
- package/dist/components/VInput/VInput.d.ts +152 -0
- package/dist/components/VInput/VInput.js +9 -0
- package/dist/components/VInput/VInput.js.map +1 -0
- package/dist/components/VInput/VInput.vue_vue_type_script_setup_true_lang.js +185 -0
- package/dist/components/VInput/VInput.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VInputOTP/VInputOTP.css +2 -0
- package/dist/components/VInputOTP/VInputOTP.d.ts +76 -0
- package/dist/components/VInputOTP/VInputOTP.js +9 -0
- package/dist/components/VInputOTP/VInputOTP.js.map +1 -0
- package/dist/components/VInputOTP/VInputOTP.vue_vue_type_script_setup_true_lang.js +149 -0
- package/dist/components/VInputOTP/VInputOTP.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VMenu/VMenu.d.ts +91 -0
- package/dist/components/VMenu/VMenu.js +7 -0
- package/dist/components/VMenu/VMenu.js.map +1 -0
- package/dist/components/VMenu/VMenu.vue_vue_type_script_setup_true_lang.js +73 -0
- package/dist/components/VMenu/VMenu.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VMenu/VMenuGroup.css +2 -0
- package/dist/components/VMenu/VMenuGroup.d.ts +22 -0
- package/dist/components/VMenu/VMenuGroup.js +9 -0
- package/dist/components/VMenu/VMenuGroup.js.map +1 -0
- package/dist/components/VMenu/VMenuGroup.vue_vue_type_script_setup_true_lang.js +21 -0
- package/dist/components/VMenu/VMenuGroup.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VMenu/VMenuItem.css +2 -0
- package/dist/components/VMenu/VMenuItem.d.ts +85 -0
- package/dist/components/VMenu/VMenuItem.js +9 -0
- package/dist/components/VMenu/VMenuItem.js.map +1 -0
- package/dist/components/VMenu/VMenuItem.vue_vue_type_script_setup_true_lang.js +121 -0
- package/dist/components/VMenu/VMenuItem.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VMenu/VMenuPanel.css +2 -0
- package/dist/components/VMenu/VMenuPanel.d.ts +91 -0
- package/dist/components/VMenu/VMenuPanel.js +9 -0
- package/dist/components/VMenu/VMenuPanel.js.map +1 -0
- package/dist/components/VMenu/VMenuPanel.vue_vue_type_script_setup_true_lang.js +103 -0
- package/dist/components/VMenu/VMenuPanel.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VMenu/VMenuSeparator.css +2 -0
- package/dist/components/VMenu/VMenuSeparator.d.ts +3 -0
- package/dist/components/VMenu/VMenuSeparator.js +9 -0
- package/dist/components/VMenu/VMenuSeparator.js.map +1 -0
- package/dist/components/VMenu/VMenuSeparator.vue_vue_type_script_setup_true_lang.js +13 -0
- package/dist/components/VMenu/VMenuSeparator.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VMenu/context.d.ts +33 -0
- package/dist/components/VMenu/context.js +9 -0
- package/dist/components/VMenu/context.js.map +1 -0
- package/dist/components/VPagination/VPagination.css +2 -0
- package/dist/components/VPagination/VPagination.d.ts +103 -0
- package/dist/components/VPagination/VPagination.js +9 -0
- package/dist/components/VPagination/VPagination.js.map +1 -0
- package/dist/components/VPagination/VPagination.vue_vue_type_script_setup_true_lang.js +270 -0
- package/dist/components/VPagination/VPagination.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VPopover/VPopover.css +2 -0
- package/dist/components/VPopover/VPopover.d.ts +82 -0
- package/dist/components/VPopover/VPopover.js +9 -0
- package/dist/components/VPopover/VPopover.js.map +1 -0
- package/dist/components/VPopover/VPopover.vue_vue_type_script_setup_true_lang.js +65 -0
- package/dist/components/VPopover/VPopover.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VProgressCircular/VProgressCircular.css +2 -0
- package/dist/components/VProgressCircular/VProgressCircular.d.ts +60 -0
- package/dist/components/VProgressCircular/VProgressCircular.js +9 -0
- package/dist/components/VProgressCircular/VProgressCircular.js.map +1 -0
- package/dist/components/VProgressCircular/VProgressCircular.vue_vue_type_script_setup_true_lang.js +74 -0
- package/dist/components/VProgressCircular/VProgressCircular.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VProgressLinear/VProgressLinear.css +2 -0
- package/dist/components/VProgressLinear/VProgressLinear.d.ts +74 -0
- package/dist/components/VProgressLinear/VProgressLinear.js +9 -0
- package/dist/components/VProgressLinear/VProgressLinear.js.map +1 -0
- package/dist/components/VProgressLinear/VProgressLinear.vue_vue_type_script_setup_true_lang.js +74 -0
- package/dist/components/VProgressLinear/VProgressLinear.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VRadio/VRadio.css +2 -0
- package/dist/components/VRadio/VRadio.d.ts +58 -0
- package/dist/components/VRadio/VRadio.js +9 -0
- package/dist/components/VRadio/VRadio.js.map +1 -0
- package/dist/components/VRadio/VRadio.vue_vue_type_script_setup_true_lang.js +60 -0
- package/dist/components/VRadio/VRadio.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VSeparator/VSeparator.css +2 -0
- package/dist/components/VSeparator/VSeparator.d.ts +23 -0
- package/dist/components/VSeparator/VSeparator.js +9 -0
- package/dist/components/VSeparator/VSeparator.js.map +1 -0
- package/dist/components/VSeparator/VSeparator.vue_vue_type_script_setup_true_lang.js +17 -0
- package/dist/components/VSeparator/VSeparator.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VSideNavigation/VSideNavigation.css +2 -0
- package/dist/components/VSideNavigation/VSideNavigation.d.ts +64 -0
- package/dist/components/VSideNavigation/VSideNavigation.js +9 -0
- package/dist/components/VSideNavigation/VSideNavigation.js.map +1 -0
- package/dist/components/VSideNavigation/VSideNavigation.vue_vue_type_script_setup_true_lang.js +67 -0
- package/dist/components/VSideNavigation/VSideNavigation.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VSideNavigation/VSideNavigationGroup.css +2 -0
- package/dist/components/VSideNavigation/VSideNavigationGroup.d.ts +33 -0
- package/dist/components/VSideNavigation/VSideNavigationGroup.js +9 -0
- package/dist/components/VSideNavigation/VSideNavigationGroup.js.map +1 -0
- package/dist/components/VSideNavigation/VSideNavigationGroup.vue_vue_type_script_setup_true_lang.js +20 -0
- package/dist/components/VSideNavigation/VSideNavigationGroup.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VSideNavigation/VSideNavigationItem.css +2 -0
- package/dist/components/VSideNavigation/VSideNavigationItem.d.ts +103 -0
- package/dist/components/VSideNavigation/VSideNavigationItem.js +9 -0
- package/dist/components/VSideNavigation/VSideNavigationItem.js.map +1 -0
- package/dist/components/VSideNavigation/VSideNavigationItem.vue_vue_type_script_setup_true_lang.js +154 -0
- package/dist/components/VSideNavigation/VSideNavigationItem.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VSideNavigation/VSideNavigationSeparator.css +2 -0
- package/dist/components/VSideNavigation/VSideNavigationSeparator.d.ts +3 -0
- package/dist/components/VSideNavigation/VSideNavigationSeparator.js +17 -0
- package/dist/components/VSideNavigation/VSideNavigationSeparator.js.map +1 -0
- package/dist/components/VSideNavigation/context.d.ts +37 -0
- package/dist/components/VSideNavigation/context.js +6 -0
- package/dist/components/VSideNavigation/context.js.map +1 -0
- package/dist/components/VSkeletonLoader/VSkeletonLoader.css +2 -0
- package/dist/components/VSkeletonLoader/VSkeletonLoader.d.ts +75 -0
- package/dist/components/VSkeletonLoader/VSkeletonLoader.js +9 -0
- package/dist/components/VSkeletonLoader/VSkeletonLoader.js.map +1 -0
- package/dist/components/VSkeletonLoader/VSkeletonLoader.vue_vue_type_script_setup_true_lang.js +61 -0
- package/dist/components/VSkeletonLoader/VSkeletonLoader.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VSlider/VSlider.css +2 -0
- package/dist/components/VSlider/VSlider.d.ts +82 -0
- package/dist/components/VSlider/VSlider.js +9 -0
- package/dist/components/VSlider/VSlider.js.map +1 -0
- package/dist/components/VSlider/VSlider.vue_vue_type_script_setup_true_lang.js +220 -0
- package/dist/components/VSlider/VSlider.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VSnackbar/VSnackbar.css +2 -0
- package/dist/components/VSnackbar/VSnackbar.d.ts +51 -0
- package/dist/components/VSnackbar/VSnackbar.js +9 -0
- package/dist/components/VSnackbar/VSnackbar.js.map +1 -0
- package/dist/components/VSnackbar/VSnackbar.vue_vue_type_script_setup_true_lang.js +83 -0
- package/dist/components/VSnackbar/VSnackbar.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VSnackbar/state.d.ts +92 -0
- package/dist/components/VSnackbar/state.js +18 -0
- package/dist/components/VSnackbar/state.js.map +1 -0
- package/dist/components/VSpinner/VSpinner.css +2 -0
- package/dist/components/VSpinner/VSpinner.d.ts +21 -0
- package/dist/components/VSpinner/VSpinner.js +9 -0
- package/dist/components/VSpinner/VSpinner.js.map +1 -0
- package/dist/components/VSpinner/VSpinner.vue_vue_type_script_setup_true_lang.js +25 -0
- package/dist/components/VSpinner/VSpinner.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VSwitch/VSwitch.css +2 -0
- package/dist/components/VSwitch/VSwitch.d.ts +46 -0
- package/dist/components/VSwitch/VSwitch.js +9 -0
- package/dist/components/VSwitch/VSwitch.js.map +1 -0
- package/dist/components/VSwitch/VSwitch.vue_vue_type_script_setup_true_lang.js +51 -0
- package/dist/components/VSwitch/VSwitch.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VTabs/VTab.css +2 -0
- package/dist/components/VTabs/VTab.d.ts +42 -0
- package/dist/components/VTabs/VTab.js +9 -0
- package/dist/components/VTabs/VTab.js.map +1 -0
- package/dist/components/VTabs/VTab.vue_vue_type_script_setup_true_lang.js +66 -0
- package/dist/components/VTabs/VTab.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VTabs/VTabPanel.css +2 -0
- package/dist/components/VTabs/VTabPanel.d.ts +34 -0
- package/dist/components/VTabs/VTabPanel.js +9 -0
- package/dist/components/VTabs/VTabPanel.js.map +1 -0
- package/dist/components/VTabs/VTabPanel.vue_vue_type_script_setup_true_lang.js +34 -0
- package/dist/components/VTabs/VTabPanel.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VTabs/VTabs.css +2 -0
- package/dist/components/VTabs/VTabs.d.ts +107 -0
- package/dist/components/VTabs/VTabs.js +9 -0
- package/dist/components/VTabs/VTabs.js.map +1 -0
- package/dist/components/VTabs/VTabs.vue_vue_type_script_setup_true_lang.js +199 -0
- package/dist/components/VTabs/VTabs.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VTabs/context.d.ts +43 -0
- package/dist/components/VTabs/context.js +6 -0
- package/dist/components/VTabs/context.js.map +1 -0
- package/dist/components/VTextarea/VTextarea.css +2 -0
- package/dist/components/VTextarea/VTextarea.d.ts +140 -0
- package/dist/components/VTextarea/VTextarea.js +9 -0
- package/dist/components/VTextarea/VTextarea.js.map +1 -0
- package/dist/components/VTextarea/VTextarea.vue_vue_type_script_setup_true_lang.js +187 -0
- package/dist/components/VTextarea/VTextarea.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VTimeInput/VTimeInput.css +2 -0
- package/dist/components/VTimeInput/VTimeInput.d.ts +112 -0
- package/dist/components/VTimeInput/VTimeInput.js +9 -0
- package/dist/components/VTimeInput/VTimeInput.js.map +1 -0
- package/dist/components/VTimeInput/VTimeInput.vue_vue_type_script_setup_true_lang.js +385 -0
- package/dist/components/VTimeInput/VTimeInput.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VTimePicker/VTimePicker.css +2 -0
- package/dist/components/VTimePicker/VTimePicker.d.ts +89 -0
- package/dist/components/VTimePicker/VTimePicker.js +9 -0
- package/dist/components/VTimePicker/VTimePicker.js.map +1 -0
- package/dist/components/VTimePicker/VTimePicker.vue_vue_type_script_setup_true_lang.js +257 -0
- package/dist/components/VTimePicker/VTimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VToast/VToast.css +2 -0
- package/dist/components/VToast/VToast.d.ts +24 -0
- package/dist/components/VToast/VToast.js +9 -0
- package/dist/components/VToast/VToast.js.map +1 -0
- package/dist/components/VToast/VToast.vue_vue_type_script_setup_true_lang.js +62 -0
- package/dist/components/VToast/VToast.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VToast/VToaster.css +2 -0
- package/dist/components/VToast/VToaster.d.ts +42 -0
- package/dist/components/VToast/VToaster.js +9 -0
- package/dist/components/VToast/VToaster.js.map +1 -0
- package/dist/components/VToast/VToaster.vue_vue_type_script_setup_true_lang.js +112 -0
- package/dist/components/VToast/VToaster.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VToast/state.d.ts +74 -0
- package/dist/components/VToast/state.js +25 -0
- package/dist/components/VToast/state.js.map +1 -0
- package/dist/components/VToggle/VToggle.css +2 -0
- package/dist/components/VToggle/VToggle.d.ts +84 -0
- package/dist/components/VToggle/VToggle.js +9 -0
- package/dist/components/VToggle/VToggle.js.map +1 -0
- package/dist/components/VToggle/VToggle.vue_vue_type_script_setup_true_lang.js +103 -0
- package/dist/components/VToggle/VToggle.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VToggle/VToggleItem.css +2 -0
- package/dist/components/VToggle/VToggleItem.d.ts +35 -0
- package/dist/components/VToggle/VToggleItem.js +9 -0
- package/dist/components/VToggle/VToggleItem.js.map +1 -0
- package/dist/components/VToggle/VToggleItem.vue_vue_type_script_setup_true_lang.js +51 -0
- package/dist/components/VToggle/VToggleItem.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VToggle/context.d.ts +37 -0
- package/dist/components/VToggle/context.js +6 -0
- package/dist/components/VToggle/context.js.map +1 -0
- package/dist/components/VTooltip/VTooltip.css +2 -0
- package/dist/components/VTooltip/VTooltip.d.ts +76 -0
- package/dist/components/VTooltip/VTooltip.js +9 -0
- package/dist/components/VTooltip/VTooltip.js.map +1 -0
- package/dist/components/VTooltip/VTooltip.vue_vue_type_script_setup_true_lang.js +50 -0
- package/dist/components/VTooltip/VTooltip.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VTypography/VTypography.css +2 -0
- package/dist/components/VTypography/VTypography.d.ts +46 -0
- package/dist/components/VTypography/VTypography.js +9 -0
- package/dist/components/VTypography/VTypography.js.map +1 -0
- package/dist/components/VTypography/VTypography.vue_vue_type_script_setup_true_lang.js +49 -0
- package/dist/components/VTypography/VTypography.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/composables/useAriaLabel.d.ts +19 -0
- package/dist/composables/useAriaLabel.js +10 -0
- package/dist/composables/useAriaLabel.js.map +1 -0
- package/dist/composables/useFieldIds.d.ts +21 -0
- package/dist/composables/useFieldIds.js +14 -0
- package/dist/composables/useFieldIds.js.map +1 -0
- package/dist/composables/useFieldPanel.d.ts +61 -0
- package/dist/composables/useFieldPanel.js +39 -0
- package/dist/composables/useFieldPanel.js.map +1 -0
- package/dist/composables/useFileDrop.d.ts +30 -0
- package/dist/composables/useFileDrop.js +28 -0
- package/dist/composables/useFileDrop.js.map +1 -0
- package/dist/composables/useFileField.d.ts +36 -0
- package/dist/composables/useFileField.js +45 -0
- package/dist/composables/useFileField.js.map +1 -0
- package/dist/composables/useFocusoutDismiss.d.ts +17 -0
- package/dist/composables/useFocusoutDismiss.js +11 -0
- package/dist/composables/useFocusoutDismiss.js.map +1 -0
- package/dist/composables/useIconClickHandlers.d.ts +27 -0
- package/dist/composables/useIconClickHandlers.js +13 -0
- package/dist/composables/useIconClickHandlers.js.map +1 -0
- package/dist/composables/useMaskedField.d.ts +65 -0
- package/dist/composables/useMaskedField.js +54 -0
- package/dist/composables/useMaskedField.js.map +1 -0
- package/dist/composables/usePopover.d.ts +7 -0
- package/dist/composables/usePopover.js +24 -0
- package/dist/composables/usePopover.js.map +1 -0
- package/dist/composables/useProgressValue.d.ts +13 -0
- package/dist/composables/useProgressValue.js +14 -0
- package/dist/composables/useProgressValue.js.map +1 -0
- package/dist/composables/useRootAttrs.d.ts +34 -0
- package/dist/composables/useRootAttrs.js +15 -0
- package/dist/composables/useRootAttrs.js.map +1 -0
- package/dist/composables/useTextLimit.d.ts +31 -0
- package/dist/composables/useTextLimit.js +19 -0
- package/dist/composables/useTextLimit.js.map +1 -0
- package/dist/composables/useTimer.d.ts +18 -0
- package/dist/composables/useTimer.js +19 -0
- package/dist/composables/useTimer.js.map +1 -0
- package/dist/i18n/en.d.ts +10 -0
- package/dist/i18n/en.js +179 -0
- package/dist/i18n/en.js.map +1 -0
- package/dist/i18n/fr.d.ts +18 -0
- package/dist/i18n/fr.js +179 -0
- package/dist/i18n/fr.js.map +1 -0
- package/dist/i18n/state.d.ts +64 -0
- package/dist/i18n/state.js +40 -0
- package/dist/i18n/state.js.map +1 -0
- package/dist/i18n/types.d.ts +345 -0
- package/dist/icons.d.ts +16 -0
- package/dist/icons.js +38 -0
- package/dist/index.d.ts +90 -0
- package/dist/index.js +64 -0
- package/dist/styles.css +1 -0
- package/dist/tokens/css.d.ts +25 -0
- package/dist/tokens/css.js +29 -0
- package/dist/tokens/css.js.map +1 -0
- package/dist/tokens/index.d.ts +370 -0
- package/dist/tokens/index.js +15 -0
- package/dist/tokens/index.js.map +1 -0
- package/dist/tokens/primitives.d.ts +101 -0
- package/dist/tokens/primitives.js +166 -0
- package/dist/tokens/primitives.js.map +1 -0
- package/dist/tokens/semantic.d.ts +236 -0
- package/dist/tokens/semantic.js +219 -0
- package/dist/tokens/semantic.js.map +1 -0
- package/dist/tokens/themes/dark.d.ts +49 -0
- package/dist/tokens/themes/dark.js +53 -0
- package/dist/tokens/themes/dark.js.map +1 -0
- package/dist/tokens/types.d.ts +38 -0
- package/dist/tokens/types.js +16 -0
- package/dist/tokens/types.js.map +1 -0
- package/dist/tokens.json +1516 -0
- package/dist/utils/array.d.ts +10 -0
- package/dist/utils/array.js +8 -0
- package/dist/utils/array.js.map +1 -0
- package/dist/utils/arrowNav.d.ts +27 -0
- package/dist/utils/arrowNav.js +26 -0
- package/dist/utils/arrowNav.js.map +1 -0
- package/dist/utils/chip.d.ts +26 -0
- package/dist/utils/chip.js +13 -0
- package/dist/utils/chip.js.map +1 -0
- package/dist/utils/css.d.ts +19 -0
- package/dist/utils/css.js +13 -0
- package/dist/utils/css.js.map +1 -0
- package/dist/utils/date.d.ts +199 -0
- package/dist/utils/date.js +225 -0
- package/dist/utils/date.js.map +1 -0
- package/dist/utils/direction.d.ts +18 -0
- package/dist/utils/direction.js +8 -0
- package/dist/utils/direction.js.map +1 -0
- package/dist/utils/env.d.ts +10 -0
- package/dist/utils/file.d.ts +95 -0
- package/dist/utils/file.js +70 -0
- package/dist/utils/file.js.map +1 -0
- package/dist/utils/focus.d.ts +24 -0
- package/dist/utils/focus.js +13 -0
- package/dist/utils/focus.js.map +1 -0
- package/dist/utils/matcher.d.ts +13 -0
- package/dist/utils/matcher.js +11 -0
- package/dist/utils/matcher.js.map +1 -0
- package/dist/utils/number.d.ts +9 -0
- package/dist/utils/number.js +8 -0
- package/dist/utils/number.js.map +1 -0
- package/dist/utils/text.d.ts +19 -0
- package/dist/utils/text.js +12 -0
- package/dist/utils/text.js.map +1 -0
- package/dist/utils/time.d.ts +138 -0
- package/dist/utils/time.js +123 -0
- package/dist/utils/time.js.map +1 -0
- package/dist/utils/vnode.d.ts +21 -0
- package/dist/utils/vnode.js +14 -0
- package/dist/utils/vnode.js.map +1 -0
- package/package.json +114 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VInput.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/VInput/VInput.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @core\n/**\n * A complete text field: a label above, a hint below, icons inside — clickable ones\n * included — a character counter, a clear button and a loading state, all arranged\n * around a real `<input>`.\n *\n * The component is a wrapper around that input, so the attributes it is given are\n * split: `class` and `style` stay on the outer element, where a consumer expects to\n * style the field, and everything else is forwarded to the input, where `name`,\n * `required` and the aria-* actually do something.\n *\n * Validation stays the browser's. The field turns red through `:user-invalid`, which\n * only reacts once the reader has left it, and even the soft limit is reported by\n * marking the input invalid rather than by emitting an event of our own — so a\n * consumer's `<form>` sees exactly what it would see with a bare input.\n *\n * The behavioural JavaScript is limited to the v-model and to the clear button,\n * which has to move focus back to the field: it disappears the moment it is clicked,\n * and focus would otherwise fall back to the page.\n */\nimport { computed, ref } from 'vue'\n\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'\nimport VTypography from '../VTypography/VTypography.vue'\n\nimport { useFieldIds } from '../../composables/useFieldIds'\nimport { useIconClickHandlers } from '../../composables/useIconClickHandlers'\nimport { useRootAttrs } from '../../composables/useRootAttrs'\nimport { useTextLimit } from '../../composables/useTextLimit'\nimport { useMessages } from '../../i18n/state'\n\ninterface InputProps {\n /** The height of the field: 32, 40 or 48 pixels. */\n size?: 'sm' | 'md' | 'lg'\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?: 'text' | 'email' | 'number' | 'password' | 'search' | 'tel' | 'url'\n /**\n * Marks the field as invalid whatever the browser thinks. This is the route for a\n * rule only the server can check; anything the browser can validate on its own\n * already colours the field without this prop.\n */\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 /** The label above the field, tied to it 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 * An icon inside the field, at the start. It is decorative by default and becomes\n * a real button as soon as a `@click:icon-start` listener is attached — in which\n * case it needs `iconStartLabel`. The `#start` slot replaces it.\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 loadingLabel?: 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\n * goes into error instead of silently refusing the keystrokes. It is reported\n * through the native validity, so a form cannot be submitted over the limit.\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 iconStart: undefined,\n iconEnd: undefined,\n iconStartLabel: undefined,\n iconEndLabel: undefined,\n loading: false,\n loadingLabel: undefined,\n clearable: false,\n clearVisible: undefined,\n clearLabel: undefined,\n maxlength: undefined,\n softLimit: 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 /** Content at the start of the field, which replaces `iconStart`. */\n start?(): 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\n/**\n * The value, typed as text OR a number rather than text alone. On an\n * `<input type=\"number\">` Vue converts the value to a number by itself, so a\n * string-only model would hand a number back to a consumer who passed a string in,\n * and Vue would report an invalid prop.\n */\nconst model = defineModel<string | number>({ default: '' })\n\n/**\n * The value seen as text. Every measurement of its length — the counter, the soft\n * limit, whether the clear cross has anything to clear — goes through this, since a\n * number has no length of its own.\n */\nconst modelText = computed(() => String(model.value ?? ''))\n\nconst { attrs, rootClass, rootStyle, forwardedAttrs: restAttrs } = useRootAttrs()\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 resolvedLoadingLabel = computed(() => props.loadingLabel ?? m.value.common.loading)\nconst resolvedClearLabel = computed(() => props.clearLabel ?? m.value.common.clear)\n\nconst { fieldId, hintId, describedBy } = useFieldIds(attrs, () => !!props.hint)\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 = computed(() => {\n if (!props.clearable || props.disabled) return false\n // When `clearVisible` is supplied it is the consumer's EXPLICIT answer to \"is\n // there anything to clear?\", and it holds even on a read-only field: the value of\n // a read-only date or time picker changes through its panel rather than by typing.\n // Left out, the field answers for itself — it has text, and it can be edited.\n return props.clearVisible ?? (!props.readonly && modelText.value.length > 0)\n})\n\n// @a11y @core — moving the focus back is the accessibility half of this handler.\n// The cross vanishes the instant it empties the field, so without that call focus\n// falls back to the page body and a keyboard user loses their place in the form.\nfunction onClear() {\n model.value = ''\n emit('clear')\n controlEl.value?.focus()\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// The real input is buried inside the wrapper, out of reach of whoever renders this\n// component. These three exposed members are how the components built on top of it\n// reach it — VCombobox refocuses the field and selects its text this way.\ndefineExpose({\n focus: (options?: FocusOptions) => controlEl.value?.focus(options),\n select: () => controlEl.value?.select(),\n el: controlEl,\n})\n</script>\n\n<template>\n <div\n class=\"v-input v-control\"\n :class=\"rootClass\"\n :style=\"rootStyle\"\n :data-size=\"size\"\n :data-compact=\"compact ? '' : undefined\"\n :data-disabled=\"disabled ? '' : undefined\"\n :data-readonly=\"readonly ? '' : undefined\"\n >\n <VTypography v-if=\"label\" as=\"label\" variant=\"label\" class=\"v-input-label\" :for=\"fieldId\">\n {{ label }}\n </VTypography>\n\n <div class=\"v-input-field\">\n <slot name=\"start\">\n <button\n v-if=\"iconStart && hasIconStartHandler\"\n type=\"button\"\n class=\"v-input-action\"\n :aria-label=\"iconStartLabel ?? iconName(iconStart)\"\n :disabled=\"disabled\"\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)\" />\n </slot>\n\n <input\n v-bind=\"restAttrs\"\n :id=\"fieldId\"\n ref=\"controlEl\"\n v-model=\"model\"\n class=\"v-input-control\"\n :type=\"type\"\n :maxlength=\"softLimit ? undefined : maxlength\"\n :disabled=\"disabled\"\n :readonly=\"readonly || undefined\"\n :aria-invalid=\"invalid || undefined\"\n :aria-describedby=\"describedBy\"\n />\n\n <span v-if=\"counter\" class=\"v-input-counter\" :data-over=\"over ? '' : undefined\">\n {{ counterText }}\n </span>\n\n <button\n v-if=\"showClear\"\n type=\"button\"\n class=\"v-input-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=\"resolvedLoadingLabel\" />\n <slot v-else name=\"end\">\n <button\n v-if=\"iconEnd && hasIconEndHandler\"\n type=\"button\"\n class=\"v-input-action\"\n :aria-label=\"iconEndLabel ?? iconName(iconEnd)\"\n :disabled=\"disabled\"\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)\" />\n </slot>\n </div>\n\n <VTypography v-if=\"hint\" :id=\"hintId\" variant=\"caption\" tone=\"muted\" class=\"v-input-hint\">\n {{ hint }}\n </VTypography>\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n .v-input {\n display: flex;\n flex-direction: column;\n gap: var(--vectis-space-1);\n width: 100%;\n font-family: var(--vectis-text-family);\n }\n\n /* The label and the hint are rendered by VTypography, which carries their type. The\n .v-input-label and .v-input-hint classes remain as hooks: a consumer overrides\n through them, and the disabled state below reaches them that way. */\n\n /* This is the box that carries the border, the background and the focus ring.\n `--field-border-color` is the single source of truth for its colour, and the\n hover, error and disabled states do nothing but redefine it.\n\n Nothing here restates the size scale: the `--control-*` variables are inherited\n from the v-control root (styles/control-size.css), the icon context included. */\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 /* The yellow autofill background is painted by the browser on the input itself,\n inside our field. Its colour cannot be changed, but matching the field's radius\n at least stops it from showing square corners inside a rounded box. */\n .v-input-control:-webkit-autofill {\n border-radius: var(--vectis-radius-interactive);\n }\n\n /* A read-only field sinks slightly into the page but keeps its text at full\n strength — the value is there to be read — and still shows the accent focus ring.\n The state is read from [data-readonly] and never from `:read-only`, which the\n browser also matches on a disabled field.\n\n TRAP — this block must stay FIRST in the sequence of states: read-only, then\n hover, focus, invalid and disabled. Every one of these selectors weighs (0,3,0),\n `:has()` taking the specificity of what it contains, so nothing but the source\n order arbitrates between them. Moved further down, this rule would repaint the\n error border and the accent focus ring grey, with no error anywhere. What\n belongs to a read-only field is its BASE colour alone. */\n .v-input[data-readonly] .v-input-field {\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 /* The focused field appears to have a two-pixel border: it is really its own 1px\n border plus a 1px shadow of the same colour just outside it, which costs no\n layout and therefore makes nothing jump.\n\n The selector watches the CONTROL's focus and not `:focus-within`, so that when\n one of the field's own buttons — the cross, a clickable icon — takes keyboard\n focus, only that button's outline lights up: two indicators at once would be\n unreadable. And it is `:focus` rather than `:focus-visible`, because a text field\n shows its focus even when it was reached with the mouse.\n\n The transparent outline is the safety net for Windows forced colours, which drop\n box-shadows entirely; an outline survives and keeps the field marked. */\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 /* The invalid state, from the browser's own verdict first and from the `invalid`\n prop second. Only the colour variable is changed, which is why the border AND\n the focus ring both turn red without either being restated. */\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 /* The counter keeps its own local styling rather than going through VTypography:\n figures of equal width, so the number does not shift as it counts, and a colour\n that marks the overflow — neither of which is a typographic role. */\n .v-input-counter {\n flex: none;\n font-size: var(--vectis-text-caption-size);\n color: var(--vectis-color-text-muted);\n font-variant-numeric: tabular-nums;\n }\n\n .v-input-counter[data-over] {\n color: var(--vectis-color-danger-text);\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 /* The field's own buttons — the clear cross, a clickable icon — go from muted grey\n to full strength on hover, and take VButton's radius so their focus ring has the\n same rounded corners as everything else.\n\n The negative margin is DERIVED and never written as a number: it is exactly half\n the difference between the icon and the wider box holding it. Subtracting it\n cancels that inset, so the glyph lands precisely where a decorative icon would\n have — against the field's padding, one --control-gap from its neighbour. */\n .v-input-action {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--control-action-size);\n height: var(--control-action-size);\n margin-inline: calc((var(--vectis-icon-size) - var(--control-action-size)) / 2);\n padding: 0;\n border: none;\n background: transparent;\n color: var(--vectis-color-text-muted);\n border-radius: var(--vectis-radius-interactive);\n cursor: pointer;\n flex: none;\n transition: color var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n\n .v-input-action:hover:not(:disabled) {\n color: var(--vectis-color-text);\n }\n\n .v-input-action:focus-visible {\n outline: var(--vectis-focus-ring-width) solid var(--vectis-focus-ring-color);\n outline-offset: calc(var(--vectis-focus-ring-offset) * -1);\n }\n\n /* A disabled field greys out through the colour tokens, the same ones VCheckbox and\n VRadio use, and never through opacity. It comes LAST in the sequence of states,\n which at equal specificity is what makes it win over all of them, the error\n included: a disabled field is not submitted, so it has nothing to report.\n\n The text here is `text-muted` and not the `text-subtle` used by the label and the\n hint below, because those sit on the page surface where this sits on\n `surface-muted` — against which subtle falls to a 4.4:1 contrast. The control\n itself is exempt from that rule, being natively disabled, but the icons the field\n CONTAINS are not, and they inherit this colour. */\n .v-input[data-disabled] .v-input-field {\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[data-disabled] .v-input-label,\n .v-input[data-disabled] .v-input-hint,\n .v-input[data-disabled] .v-input-counter {\n color: var(--vectis-color-text-subtle);\n }\n\n .v-input[data-disabled] .v-input-action,\n .v-input[data-disabled] .v-input-field > .v-icon {\n color: inherit;\n cursor: not-allowed;\n }\n\n .v-input-control:disabled {\n cursor: not-allowed;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-input-field,\n .v-input-action {\n transition: none;\n }\n }\n}\n</style>\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
@layer vectis.reset, vectis.tokens, vectis.components, vectis.utilities;
|
|
2
|
+
@layer vectis.components{.v-otp{--otp-font-size:var(--vectis-font-size-lg);align-items:center;gap:var(--control-gap);display:inline-flex}.v-otp-input{width:var(--control-height);height:var(--control-height);text-align:center;background:var(--vectis-color-surface);color:var(--vectis-color-text);border:1px solid var(--vectis-color-border-strong);border-radius:var(--vectis-radius-interactive);font-family:var(--vectis-text-family-code);font-size:var(--otp-font-size);transition:border-color var(--vectis-duration-fast) var(--vectis-ease-default)}.v-otp-input:focus-visible{border-color:var(--vectis-color-accent);box-shadow:0 0 0 1px var(--vectis-color-accent);outline:var(--vectis-focus-ring-width) solid transparent}.v-otp[data-invalid] .v-otp-input{border-color:var(--vectis-color-danger)}.v-otp[data-invalid] .v-otp-input:focus-visible{box-shadow:0 0 0 1px var(--vectis-color-danger)}.v-otp-literal{color:var(--vectis-color-text-muted);font-family:var(--vectis-text-family-code);font-size:var(--otp-font-size);-webkit-user-select:none;user-select:none;justify-content:center;align-items:center;display:inline-flex}.v-otp[data-disabled] .v-otp-input{background:var(--vectis-color-surface-muted);color:var(--vectis-color-text-subtle);border-color:var(--vectis-color-border);cursor:not-allowed}.v-otp[data-disabled] .v-otp-literal{color:var(--vectis-color-text-subtle)}.v-otp[data-size=sm]{--otp-font-size:var(--vectis-font-size-md)}.v-otp[data-size=lg]{--otp-font-size:var(--vectis-font-size-xl)}@media (prefers-reduced-motion:reduce){.v-otp-input{transition:none}}}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { IconSource } from '../VIcon/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* The row of boxes a one-time code is typed into, one character per box.
|
|
4
|
+
*
|
|
5
|
+
* The platform has no such control, so each box is a real `<input>` and the
|
|
6
|
+
* JavaScript is what makes the row behave as a single field: typing a character moves
|
|
7
|
+
* to the next box, Backspace on an empty one goes back, the arrows walk along, and a
|
|
8
|
+
* code pasted anywhere is spread across the boxes. The first box carries
|
|
9
|
+
* `autocomplete="one-time-code"`, so a code filled in from an SMS or a password
|
|
10
|
+
* manager is spread the same way.
|
|
11
|
+
*
|
|
12
|
+
* `pattern` is what cuts the row up: every `#` becomes a box, and every other
|
|
13
|
+
* character becomes a separator shown between them, which is displayed but never part
|
|
14
|
+
* of the value. Pasting understands those separators — a code copied in its formatted
|
|
15
|
+
* shape, "GT-123" or "123.456.789", is consumed with them in place — and everything
|
|
16
|
+
* else is filtered by `format`, which also forces capitals outside a numeric code so
|
|
17
|
+
* that the value has one canonical form.
|
|
18
|
+
*/
|
|
19
|
+
interface InputOTPProps {
|
|
20
|
+
/** How many boxes the code has. It is ignored as soon as a `pattern` is given. */
|
|
21
|
+
length?: number;
|
|
22
|
+
/**
|
|
23
|
+
* Which characters the code is made of. It filters what can be typed or pasted, and
|
|
24
|
+
* decides which keyboard a phone offers.
|
|
25
|
+
*/
|
|
26
|
+
format?: 'numeric' | 'alpha' | 'alphanumeric';
|
|
27
|
+
/**
|
|
28
|
+
* The shape of the code: each `#` is a box to fill, and every other character is a
|
|
29
|
+
* separator shown between the boxes without ever being part of the value —
|
|
30
|
+
* `'GT-###'`, `'###.###.###'`. It wins over `length`.
|
|
31
|
+
*/
|
|
32
|
+
pattern?: string;
|
|
33
|
+
/**
|
|
34
|
+
* An icon drawn in place of EVERY separator of the pattern. It suits a template
|
|
35
|
+
* whose separators are purely decorative, `'###-###'`, and should not be used with
|
|
36
|
+
* one carrying meaningful text such as `'GT-###'`, which the icon would erase.
|
|
37
|
+
*/
|
|
38
|
+
separatorIcon?: IconSource;
|
|
39
|
+
/** The size of the boxes: 32, 40 or 48 pixels. */
|
|
40
|
+
size?: 'sm' | 'md' | 'lg';
|
|
41
|
+
/** Takes 4px off the boxes, leaving the text and the icons as they are. */
|
|
42
|
+
compact?: boolean;
|
|
43
|
+
/** Makes every box unusable, greyed out through the colour tokens. */
|
|
44
|
+
disabled?: boolean;
|
|
45
|
+
/** Marks the code as wrong, which colours the boxes and tells assistive technology so. */
|
|
46
|
+
invalid?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* What screen readers announce for the row as a whole. It falls back to the design
|
|
49
|
+
* system dictionary.
|
|
50
|
+
*/
|
|
51
|
+
label?: string;
|
|
52
|
+
}
|
|
53
|
+
type __VLS_Props = InputOTPProps;
|
|
54
|
+
type __VLS_ModelProps = {
|
|
55
|
+
modelValue?: string;
|
|
56
|
+
};
|
|
57
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
58
|
+
declare const __VLS_export: import('vue').DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
59
|
+
"update:modelValue": (value: string) => any;
|
|
60
|
+
complete: (code: string) => any;
|
|
61
|
+
}, string, import('vue').PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
62
|
+
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
63
|
+
onComplete?: ((code: string) => any) | undefined;
|
|
64
|
+
}>, {
|
|
65
|
+
label: string;
|
|
66
|
+
size: "sm" | "md" | "lg";
|
|
67
|
+
length: number;
|
|
68
|
+
pattern: string;
|
|
69
|
+
compact: boolean;
|
|
70
|
+
disabled: boolean;
|
|
71
|
+
invalid: boolean;
|
|
72
|
+
format: "numeric" | "alpha" | "alphanumeric";
|
|
73
|
+
separatorIcon: IconSource;
|
|
74
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
75
|
+
declare const _default: typeof __VLS_export;
|
|
76
|
+
export default _default;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VInputOTP.js","names":[],"sources":["../../../src/components/VInputOTP/VInputOTP.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue'\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport type { IconSource } from '../VIcon/types'\n\nimport { isDev } from '../../utils/env'\n\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useMessages } from '../../i18n/state'\n\n// @keyboard @core\n/**\n * The row of boxes a one-time code is typed into, one character per box.\n *\n * The platform has no such control, so each box is a real `<input>` and the\n * JavaScript is what makes the row behave as a single field: typing a character moves\n * to the next box, Backspace on an empty one goes back, the arrows walk along, and a\n * code pasted anywhere is spread across the boxes. The first box carries\n * `autocomplete=\"one-time-code\"`, so a code filled in from an SMS or a password\n * manager is spread the same way.\n *\n * `pattern` is what cuts the row up: every `#` becomes a box, and every other\n * character becomes a separator shown between them, which is displayed but never part\n * of the value. Pasting understands those separators — a code copied in its formatted\n * shape, \"GT-123\" or \"123.456.789\", is consumed with them in place — and everything\n * else is filtered by `format`, which also forces capitals outside a numeric code so\n * that the value has one canonical form.\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?: 'numeric' | 'alpha' | 'alphanumeric'\n /**\n * The shape of the code: each `#` is a box to fill, and every other character is a\n * separator shown between the boxes without ever being part of the value —\n * `'GT-###'`, `'###.###.###'`. It wins over `length`.\n */\n pattern?: string\n /**\n * An icon drawn in place of EVERY separator of the pattern. It suits a template\n * whose separators are purely decorative, `'###-###'`, and should not be used with\n * one carrying meaningful text such as `'GT-###'`, which the icon would erase.\n */\n separatorIcon?: IconSource\n /** The size of the boxes: 32, 40 or 48 pixels. */\n size?: 'sm' | 'md' | 'lg'\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 /** Marks the code as wrong, which colours the boxes and tells assistive technology so. */\n invalid?: boolean\n /**\n * What screen readers announce for the row as a whole. It falls back to the design\n * system dictionary.\n */\n label?: string\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 invalid: false,\n label: undefined,\n})\n\nconst m = useMessages()\nconst ariaLabel = useAriaLabel(() => props.label ?? m.value.inputOTP.label)\n\nconst model = defineModel<string>({ default: '' })\n\nconst emit = defineEmits<{\n /** Emitted the moment every box is filled, carrying the complete code. */\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<NonNullable<InputOTPProps['format']>, 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 inputs = ref<(HTMLInputElement | null)[]>([])\nconst digits = ref<string[]>([])\n\nfunction syncFromModel(value: string) {\n // A value longer than the row is simply shown cut short, and the model is NOT\n // rewritten to match: writing back here would feed the watcher below and the two\n // would keep correcting each other.\n digits.value = Array.from({ length: slotCount.value }, (_, i) => value[i] ?? '')\n}\nsyncFromModel(model.value)\nwatch([model, slotCount], ([value, count]) => {\n if (value !== digits.value.join('') || digits.value.length !== count) syncFromModel(value)\n})\n\nfunction commit() {\n const code = digits.value.join('')\n model.value = code\n if (code.length === slotCount.value) emit('complete', code)\n}\n\n// @core\n/**\n * Spreads a run of characters across the boxes, starting from the one that received\n * them. It walks the row: a separator swallows the incoming character when the two\n * match, which is what lets a code pasted in its formatted shape line up, and a box\n * takes the next character the format accepts.\n *\n * It returns the last box it filled, so the caller knows where to put the focus, and\n * `null` when 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 // Step back over the separators immediately before that box: pasting the whole\n // string onto the first box means pasting its prefix too, and \"GT-\" has to be\n // matched rather than treated as characters of the code.\n while (start > 0 && allCells[start - 1]?.type === 'literal') start--\n const chars = [...raw]\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 — moving the focus forward on its own is what turns a row of\n// separate inputs into something that types like one field; spreading the characters\n// is the core behaviour underneath it.\nfunction onInput(slotIndex: number, event: Event) {\n const el = event.target as HTMLInputElement\n // The same path serves a single keystroke and a pasted code: both are spread from\n // this box onwards.\n const lastFilled = distribute(el.value, slotIndex)\n if (lastFilled === null) {\n // Either the box was emptied, or nothing typed was valid for this format.\n digits.value[slotIndex] = ''\n el.value = ''\n commit()\n return\n }\n el.value = digits.value[slotIndex] ?? ''\n inputs.value[Math.min(lastFilled + 1, slotCount.value - 1)]?.focus()\n commit()\n}\n\n// @keyboard\nfunction onKeydown(slotIndex: number, event: KeyboardEvent) {\n if (event.key === 'Backspace' && !digits.value[slotIndex] && slotIndex > 0) {\n event.preventDefault()\n digits.value[slotIndex - 1] = ''\n commit()\n inputs.value[slotIndex - 1]?.focus()\n } else if (event.key === 'ArrowLeft' && slotIndex > 0) {\n event.preventDefault()\n inputs.value[slotIndex - 1]?.focus()\n } else if (event.key === 'ArrowRight' && slotIndex < slotCount.value - 1) {\n event.preventDefault()\n inputs.value[slotIndex + 1]?.focus()\n }\n}\n</script>\n\n<template>\n <div\n class=\"v-otp v-control\"\n role=\"group\"\n :aria-label=\"ariaLabel\"\n :data-invalid=\"invalid ? '' : undefined\"\n :data-size=\"size\"\n :data-compact=\"compact ? '' : undefined\"\n :data-disabled=\"disabled ? '' : undefined\"\n >\n <template v-for=\"(cell, i) in cells\" :key=\"i\">\n <input\n v-if=\"cell.type === 'slot'\"\n :ref=\"\n (el) => {\n inputs[cell.slotIndex] = el as HTMLInputElement | null\n }\n \"\n type=\"text\"\n class=\"v-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 :aria-label=\"m.inputOTP.slot(cell.slotIndex + 1, slotCount)\"\n :aria-invalid=\"invalid || undefined\"\n @input=\"onInput(cell.slotIndex, $event)\"\n @keydown=\"onKeydown(cell.slotIndex, $event)\"\n @focus=\"($event.target as HTMLInputElement).select()\"\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-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</template>\n\n<style>\n@layer vectis.components {\n .v-otp {\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 --otp-font-size: var(--vectis-font-size-lg);\n\n display: inline-flex;\n align-items: center;\n gap: var(--control-gap);\n }\n\n .v-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(--otp-font-size);\n transition: border-color var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n\n /* The focused box appears to have a two-pixel border, exactly as in VInput and\n VTextarea: its own 1px border plus a 1px shadow of the same colour just outside\n it. The transparent outline is the safety net for Windows forced colours, which\n drop box-shadows entirely. */\n .v-otp-input:focus-visible {\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-otp[data-invalid] .v-otp-input {\n border-color: var(--vectis-color-danger);\n }\n\n .v-otp[data-invalid] .v-otp-input:focus-visible {\n box-shadow: 0 0 0 1px var(--vectis-color-danger);\n }\n\n .v-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(--otp-font-size);\n user-select: none;\n }\n\n /* A disabled row greys out through the colour tokens and never through opacity, the\n same treatment as VInput. */\n .v-otp[data-disabled] .v-otp-input {\n background: var(--vectis-color-surface-muted);\n color: var(--vectis-color-text-subtle);\n border-color: var(--vectis-color-border);\n cursor: not-allowed;\n }\n\n .v-otp[data-disabled] .v-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-otp[data-size='sm'] {\n --otp-font-size: var(--vectis-font-size-md);\n }\n\n .v-otp[data-size='lg'] {\n --otp-font-size: var(--vectis-font-size-xl);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-otp-input {\n transition: none;\n }\n }\n}\n</style>\n"],"mappings":""}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { useMessages as e } from "../../i18n/state.js";
|
|
2
|
+
import t from "../VIcon/VIcon.js";
|
|
3
|
+
import { iconProps as n } from "../VIcon/iconProps.js";
|
|
4
|
+
import { useAriaLabel as r } from "../../composables/useAriaLabel.js";
|
|
5
|
+
import { Fragment as i, computed as a, createBlock as o, createElementBlock as s, createTextVNode as c, defineComponent as l, mergeModels as u, mergeProps as d, openBlock as f, ref as p, renderList as m, toDisplayString as h, unref as g, useModel as _, watch as v } from "vue";
|
|
6
|
+
//#region src/components/VInputOTP/VInputOTP.vue?vue&type=script&setup=true&lang.ts
|
|
7
|
+
var y = [
|
|
8
|
+
"aria-label",
|
|
9
|
+
"data-invalid",
|
|
10
|
+
"data-size",
|
|
11
|
+
"data-compact",
|
|
12
|
+
"data-disabled"
|
|
13
|
+
], b = [
|
|
14
|
+
"inputmode",
|
|
15
|
+
"autocomplete",
|
|
16
|
+
"value",
|
|
17
|
+
"disabled",
|
|
18
|
+
"aria-label",
|
|
19
|
+
"aria-invalid",
|
|
20
|
+
"onInput",
|
|
21
|
+
"onKeydown"
|
|
22
|
+
], x = {
|
|
23
|
+
key: 1,
|
|
24
|
+
class: "v-otp-literal",
|
|
25
|
+
"aria-hidden": "true"
|
|
26
|
+
}, S = /*@__PURE__*/ l({
|
|
27
|
+
__name: "VInputOTP",
|
|
28
|
+
props: /*@__PURE__*/ u({
|
|
29
|
+
length: { default: 6 },
|
|
30
|
+
format: { default: "numeric" },
|
|
31
|
+
pattern: { default: void 0 },
|
|
32
|
+
separatorIcon: { default: void 0 },
|
|
33
|
+
size: { default: "md" },
|
|
34
|
+
compact: {
|
|
35
|
+
type: Boolean,
|
|
36
|
+
default: !1
|
|
37
|
+
},
|
|
38
|
+
disabled: {
|
|
39
|
+
type: Boolean,
|
|
40
|
+
default: !1
|
|
41
|
+
},
|
|
42
|
+
invalid: {
|
|
43
|
+
type: Boolean,
|
|
44
|
+
default: !1
|
|
45
|
+
},
|
|
46
|
+
label: { default: void 0 }
|
|
47
|
+
}, {
|
|
48
|
+
modelValue: { default: "" },
|
|
49
|
+
modelModifiers: {}
|
|
50
|
+
}),
|
|
51
|
+
emits: /*@__PURE__*/ u(["complete"], ["update:modelValue"]),
|
|
52
|
+
setup(l, { emit: u }) {
|
|
53
|
+
let S = l, C = e(), w = r(() => S.label ?? C.value.inputOTP.label), T = _(l, "modelValue"), E = u, D = a(() => {
|
|
54
|
+
if (S.pattern?.includes("#")) {
|
|
55
|
+
let e = 0;
|
|
56
|
+
return [...S.pattern].map((t) => t === "#" ? {
|
|
57
|
+
type: "slot",
|
|
58
|
+
slotIndex: e++
|
|
59
|
+
} : {
|
|
60
|
+
type: "literal",
|
|
61
|
+
char: t
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
return Array.from({ length: S.length }, (e, t) => ({
|
|
65
|
+
type: "slot",
|
|
66
|
+
slotIndex: t
|
|
67
|
+
}));
|
|
68
|
+
}), O = a(() => D.value.filter((e) => e.type === "slot").length), k = {
|
|
69
|
+
numeric: /[^0-9]/g,
|
|
70
|
+
alpha: /[^A-Z]/g,
|
|
71
|
+
alphanumeric: /[^A-Z0-9]/g
|
|
72
|
+
};
|
|
73
|
+
function A(e) {
|
|
74
|
+
return (S.format === "numeric" ? e : e.toUpperCase()).replace(k[S.format], "");
|
|
75
|
+
}
|
|
76
|
+
let j = p([]), M = p([]);
|
|
77
|
+
function N(e) {
|
|
78
|
+
M.value = Array.from({ length: O.value }, (t, n) => e[n] ?? "");
|
|
79
|
+
}
|
|
80
|
+
N(T.value), v([T, O], ([e, t]) => {
|
|
81
|
+
(e !== M.value.join("") || M.value.length !== t) && N(e);
|
|
82
|
+
});
|
|
83
|
+
function P() {
|
|
84
|
+
let e = M.value.join("");
|
|
85
|
+
T.value = e, e.length === O.value && E("complete", e);
|
|
86
|
+
}
|
|
87
|
+
function F(e, t) {
|
|
88
|
+
let n = D.value, r = n.findIndex((e) => e.type === "slot" && e.slotIndex === t);
|
|
89
|
+
for (; r > 0 && n[r - 1]?.type === "literal";) r--;
|
|
90
|
+
let i = [...e], a = 0, o = null;
|
|
91
|
+
for (let e of n.slice(r)) {
|
|
92
|
+
if (a >= i.length) break;
|
|
93
|
+
if (e.type === "literal") {
|
|
94
|
+
i[a]?.toUpperCase() === e.char.toUpperCase() && a++;
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
let t = "";
|
|
98
|
+
for (; a < i.length && !t;) t = A(i[a] ?? ""), a++;
|
|
99
|
+
if (!t) break;
|
|
100
|
+
M.value[e.slotIndex] = t, o = e.slotIndex;
|
|
101
|
+
}
|
|
102
|
+
return o;
|
|
103
|
+
}
|
|
104
|
+
function I(e, t) {
|
|
105
|
+
let n = t.target, r = F(n.value, e);
|
|
106
|
+
if (r === null) {
|
|
107
|
+
M.value[e] = "", n.value = "", P();
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
n.value = M.value[e] ?? "", j.value[Math.min(r + 1, O.value - 1)]?.focus(), P();
|
|
111
|
+
}
|
|
112
|
+
function L(e, t) {
|
|
113
|
+
t.key === "Backspace" && !M.value[e] && e > 0 ? (t.preventDefault(), M.value[e - 1] = "", P(), j.value[e - 1]?.focus()) : t.key === "ArrowLeft" && e > 0 ? (t.preventDefault(), j.value[e - 1]?.focus()) : t.key === "ArrowRight" && e < O.value - 1 && (t.preventDefault(), j.value[e + 1]?.focus());
|
|
114
|
+
}
|
|
115
|
+
return (e, r) => (f(), s("div", {
|
|
116
|
+
class: "v-otp v-control",
|
|
117
|
+
role: "group",
|
|
118
|
+
"aria-label": g(w),
|
|
119
|
+
"data-invalid": l.invalid ? "" : void 0,
|
|
120
|
+
"data-size": l.size,
|
|
121
|
+
"data-compact": l.compact ? "" : void 0,
|
|
122
|
+
"data-disabled": l.disabled ? "" : void 0
|
|
123
|
+
}, [(f(!0), s(i, null, m(D.value, (e, a) => (f(), s(i, { key: a }, [e.type === "slot" ? (f(), s("input", {
|
|
124
|
+
key: 0,
|
|
125
|
+
ref_for: !0,
|
|
126
|
+
ref: (t) => {
|
|
127
|
+
j.value[e.slotIndex] = t;
|
|
128
|
+
},
|
|
129
|
+
type: "text",
|
|
130
|
+
class: "v-otp-input",
|
|
131
|
+
inputmode: l.format === "numeric" ? "numeric" : "text",
|
|
132
|
+
autocomplete: e.slotIndex === 0 ? "one-time-code" : "off",
|
|
133
|
+
value: M.value[e.slotIndex],
|
|
134
|
+
disabled: l.disabled,
|
|
135
|
+
"aria-label": g(C).inputOTP.slot(e.slotIndex + 1, O.value),
|
|
136
|
+
"aria-invalid": l.invalid || void 0,
|
|
137
|
+
onInput: (t) => I(e.slotIndex, t),
|
|
138
|
+
onKeydown: (t) => L(e.slotIndex, t),
|
|
139
|
+
onFocus: r[0] ||= (e) => e.target.select()
|
|
140
|
+
}, null, 40, b)) : (f(), s("span", x, [l.separatorIcon ? (f(), o(t, d({
|
|
141
|
+
key: 0,
|
|
142
|
+
ref_for: !0
|
|
143
|
+
}, g(n)(l.separatorIcon)), null, 16)) : (f(), s(i, { key: 1 }, [c(h(e.char), 1)], 64))]))], 64))), 128))], 8, y));
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
//#endregion
|
|
147
|
+
export { S as default };
|
|
148
|
+
|
|
149
|
+
//# sourceMappingURL=VInputOTP.vue_vue_type_script_setup_true_lang.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VInputOTP.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/VInputOTP/VInputOTP.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue'\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport type { IconSource } from '../VIcon/types'\n\nimport { isDev } from '../../utils/env'\n\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useMessages } from '../../i18n/state'\n\n// @keyboard @core\n/**\n * The row of boxes a one-time code is typed into, one character per box.\n *\n * The platform has no such control, so each box is a real `<input>` and the\n * JavaScript is what makes the row behave as a single field: typing a character moves\n * to the next box, Backspace on an empty one goes back, the arrows walk along, and a\n * code pasted anywhere is spread across the boxes. The first box carries\n * `autocomplete=\"one-time-code\"`, so a code filled in from an SMS or a password\n * manager is spread the same way.\n *\n * `pattern` is what cuts the row up: every `#` becomes a box, and every other\n * character becomes a separator shown between them, which is displayed but never part\n * of the value. Pasting understands those separators — a code copied in its formatted\n * shape, \"GT-123\" or \"123.456.789\", is consumed with them in place — and everything\n * else is filtered by `format`, which also forces capitals outside a numeric code so\n * that the value has one canonical form.\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?: 'numeric' | 'alpha' | 'alphanumeric'\n /**\n * The shape of the code: each `#` is a box to fill, and every other character is a\n * separator shown between the boxes without ever being part of the value —\n * `'GT-###'`, `'###.###.###'`. It wins over `length`.\n */\n pattern?: string\n /**\n * An icon drawn in place of EVERY separator of the pattern. It suits a template\n * whose separators are purely decorative, `'###-###'`, and should not be used with\n * one carrying meaningful text such as `'GT-###'`, which the icon would erase.\n */\n separatorIcon?: IconSource\n /** The size of the boxes: 32, 40 or 48 pixels. */\n size?: 'sm' | 'md' | 'lg'\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 /** Marks the code as wrong, which colours the boxes and tells assistive technology so. */\n invalid?: boolean\n /**\n * What screen readers announce for the row as a whole. It falls back to the design\n * system dictionary.\n */\n label?: string\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 invalid: false,\n label: undefined,\n})\n\nconst m = useMessages()\nconst ariaLabel = useAriaLabel(() => props.label ?? m.value.inputOTP.label)\n\nconst model = defineModel<string>({ default: '' })\n\nconst emit = defineEmits<{\n /** Emitted the moment every box is filled, carrying the complete code. */\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<NonNullable<InputOTPProps['format']>, 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 inputs = ref<(HTMLInputElement | null)[]>([])\nconst digits = ref<string[]>([])\n\nfunction syncFromModel(value: string) {\n // A value longer than the row is simply shown cut short, and the model is NOT\n // rewritten to match: writing back here would feed the watcher below and the two\n // would keep correcting each other.\n digits.value = Array.from({ length: slotCount.value }, (_, i) => value[i] ?? '')\n}\nsyncFromModel(model.value)\nwatch([model, slotCount], ([value, count]) => {\n if (value !== digits.value.join('') || digits.value.length !== count) syncFromModel(value)\n})\n\nfunction commit() {\n const code = digits.value.join('')\n model.value = code\n if (code.length === slotCount.value) emit('complete', code)\n}\n\n// @core\n/**\n * Spreads a run of characters across the boxes, starting from the one that received\n * them. It walks the row: a separator swallows the incoming character when the two\n * match, which is what lets a code pasted in its formatted shape line up, and a box\n * takes the next character the format accepts.\n *\n * It returns the last box it filled, so the caller knows where to put the focus, and\n * `null` when 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 // Step back over the separators immediately before that box: pasting the whole\n // string onto the first box means pasting its prefix too, and \"GT-\" has to be\n // matched rather than treated as characters of the code.\n while (start > 0 && allCells[start - 1]?.type === 'literal') start--\n const chars = [...raw]\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 — moving the focus forward on its own is what turns a row of\n// separate inputs into something that types like one field; spreading the characters\n// is the core behaviour underneath it.\nfunction onInput(slotIndex: number, event: Event) {\n const el = event.target as HTMLInputElement\n // The same path serves a single keystroke and a pasted code: both are spread from\n // this box onwards.\n const lastFilled = distribute(el.value, slotIndex)\n if (lastFilled === null) {\n // Either the box was emptied, or nothing typed was valid for this format.\n digits.value[slotIndex] = ''\n el.value = ''\n commit()\n return\n }\n el.value = digits.value[slotIndex] ?? ''\n inputs.value[Math.min(lastFilled + 1, slotCount.value - 1)]?.focus()\n commit()\n}\n\n// @keyboard\nfunction onKeydown(slotIndex: number, event: KeyboardEvent) {\n if (event.key === 'Backspace' && !digits.value[slotIndex] && slotIndex > 0) {\n event.preventDefault()\n digits.value[slotIndex - 1] = ''\n commit()\n inputs.value[slotIndex - 1]?.focus()\n } else if (event.key === 'ArrowLeft' && slotIndex > 0) {\n event.preventDefault()\n inputs.value[slotIndex - 1]?.focus()\n } else if (event.key === 'ArrowRight' && slotIndex < slotCount.value - 1) {\n event.preventDefault()\n inputs.value[slotIndex + 1]?.focus()\n }\n}\n</script>\n\n<template>\n <div\n class=\"v-otp v-control\"\n role=\"group\"\n :aria-label=\"ariaLabel\"\n :data-invalid=\"invalid ? '' : undefined\"\n :data-size=\"size\"\n :data-compact=\"compact ? '' : undefined\"\n :data-disabled=\"disabled ? '' : undefined\"\n >\n <template v-for=\"(cell, i) in cells\" :key=\"i\">\n <input\n v-if=\"cell.type === 'slot'\"\n :ref=\"\n (el) => {\n inputs[cell.slotIndex] = el as HTMLInputElement | null\n }\n \"\n type=\"text\"\n class=\"v-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 :aria-label=\"m.inputOTP.slot(cell.slotIndex + 1, slotCount)\"\n :aria-invalid=\"invalid || undefined\"\n @input=\"onInput(cell.slotIndex, $event)\"\n @keydown=\"onKeydown(cell.slotIndex, $event)\"\n @focus=\"($event.target as HTMLInputElement).select()\"\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-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</template>\n\n<style>\n@layer vectis.components {\n .v-otp {\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 --otp-font-size: var(--vectis-font-size-lg);\n\n display: inline-flex;\n align-items: center;\n gap: var(--control-gap);\n }\n\n .v-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(--otp-font-size);\n transition: border-color var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n\n /* The focused box appears to have a two-pixel border, exactly as in VInput and\n VTextarea: its own 1px border plus a 1px shadow of the same colour just outside\n it. The transparent outline is the safety net for Windows forced colours, which\n drop box-shadows entirely. */\n .v-otp-input:focus-visible {\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-otp[data-invalid] .v-otp-input {\n border-color: var(--vectis-color-danger);\n }\n\n .v-otp[data-invalid] .v-otp-input:focus-visible {\n box-shadow: 0 0 0 1px var(--vectis-color-danger);\n }\n\n .v-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(--otp-font-size);\n user-select: none;\n }\n\n /* A disabled row greys out through the colour tokens and never through opacity, the\n same treatment as VInput. */\n .v-otp[data-disabled] .v-otp-input {\n background: var(--vectis-color-surface-muted);\n color: var(--vectis-color-text-subtle);\n border-color: var(--vectis-color-border);\n cursor: not-allowed;\n }\n\n .v-otp[data-disabled] .v-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-otp[data-size='sm'] {\n --otp-font-size: var(--vectis-font-size-md);\n }\n\n .v-otp[data-size='lg'] {\n --otp-font-size: var(--vectis-font-size-xl);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-otp-input {\n transition: none;\n }\n }\n}\n</style>\n"],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { MenuPlacement } from './context.js';
|
|
2
|
+
/**
|
|
3
|
+
* A menu of actions, opened by a button and closed as soon as one is chosen. It
|
|
4
|
+
* follows the ARIA menu pattern, which is what tells a screen reader that these are
|
|
5
|
+
* commands rather than links or options in a list.
|
|
6
|
+
*
|
|
7
|
+
* It rests on the browser's own popover support: the panel closes on a click outside
|
|
8
|
+
* or on Escape without a line of code, and it positions itself in CSS against the
|
|
9
|
+
* button that opened it — the browser knows which one, since that button names the
|
|
10
|
+
* panel it opens.
|
|
11
|
+
*
|
|
12
|
+
* The JavaScript here is limited to what the platform does not do: keeping
|
|
13
|
+
* `v-model:open` and the browser's own state in step, moving the focus into the panel
|
|
14
|
+
* when it opens, and giving it back to the trigger when it closes. The keyboard inside
|
|
15
|
+
* the panel — the arrows moving from one command to the next — lives in VMenuPanel.
|
|
16
|
+
*
|
|
17
|
+
* How far the focus goes in depends on how the menu was opened. Opened from the
|
|
18
|
+
* keyboard it settles on the first command, ready to be chosen; opened with a mouse or
|
|
19
|
+
* a finger it stops at the panel, so that nothing is picked out for someone who has
|
|
20
|
+
* not asked for a choice yet — the arrows still enter the list from there.
|
|
21
|
+
*/
|
|
22
|
+
interface MenuProps {
|
|
23
|
+
/**
|
|
24
|
+
* Where the panel opens relative to its trigger. The browser moves it to another
|
|
25
|
+
* side by itself when there is not enough room.
|
|
26
|
+
*/
|
|
27
|
+
placement?: MenuPlacement;
|
|
28
|
+
/**
|
|
29
|
+
* How tall the rows are: 32, 40 or 48 pixels. Submenus inherit it, so it is set
|
|
30
|
+
* once on the menu as a whole.
|
|
31
|
+
*/
|
|
32
|
+
size?: 'sm' | 'md' | 'lg';
|
|
33
|
+
/** Takes 4px off the height of every row, submenus included. */
|
|
34
|
+
compact?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* A width for the panel, given as any CSS length or keyword — `16rem`,
|
|
37
|
+
* `max-content`. It applies to the menu itself; submenus keep the default width.
|
|
38
|
+
*/
|
|
39
|
+
width?: string;
|
|
40
|
+
/**
|
|
41
|
+
* Stops the panel from being narrower than the button that opened it, while leaving
|
|
42
|
+
* it free to grow wider for its content. Submenus are unaffected.
|
|
43
|
+
*/
|
|
44
|
+
matchTrigger?: boolean;
|
|
45
|
+
}
|
|
46
|
+
type __VLS_Props = MenuProps;
|
|
47
|
+
/**
|
|
48
|
+
* What the trigger has to carry: the link to the panel it opens, and the two
|
|
49
|
+
* attributes telling assistive technology that a menu is attached to this button and
|
|
50
|
+
* whether it is currently open.
|
|
51
|
+
*/
|
|
52
|
+
type MenuTriggerProps = {
|
|
53
|
+
popovertarget: string;
|
|
54
|
+
'aria-haspopup': 'menu';
|
|
55
|
+
'aria-expanded': boolean;
|
|
56
|
+
'aria-controls': string;
|
|
57
|
+
};
|
|
58
|
+
type __VLS_Slots = {
|
|
59
|
+
/**
|
|
60
|
+
* The button that opens the menu. Bind the `triggerProps` it receives onto it —
|
|
61
|
+
* that is what wires the two together.
|
|
62
|
+
*/
|
|
63
|
+
trigger(props: {
|
|
64
|
+
triggerProps: MenuTriggerProps;
|
|
65
|
+
}): unknown;
|
|
66
|
+
/** The contents of the menu: VMenuItem, VMenuGroup and VMenuSeparator. */
|
|
67
|
+
default(): unknown;
|
|
68
|
+
};
|
|
69
|
+
type __VLS_ModelProps = {
|
|
70
|
+
'open'?: boolean;
|
|
71
|
+
};
|
|
72
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
73
|
+
declare const __VLS_base: import('vue').DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
74
|
+
"update:open": (value: boolean) => any;
|
|
75
|
+
}, string, import('vue').PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
76
|
+
"onUpdate:open"?: ((value: boolean) => any) | undefined;
|
|
77
|
+
}>, {
|
|
78
|
+
size: "sm" | "md" | "lg";
|
|
79
|
+
placement: MenuPlacement;
|
|
80
|
+
compact: boolean;
|
|
81
|
+
width: string;
|
|
82
|
+
matchTrigger: boolean;
|
|
83
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
84
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
85
|
+
declare const _default: typeof __VLS_export;
|
|
86
|
+
export default _default;
|
|
87
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
88
|
+
new (): {
|
|
89
|
+
$slots: S;
|
|
90
|
+
};
|
|
91
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VMenu.js","names":[],"sources":["../../../src/components/VMenu/VMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, onMounted, provide, ref, useId, watch } from 'vue'\n\nimport VMenuPanel from './VMenuPanel.vue'\nimport { menuInvoker, menuKey } from './context'\nimport type { MenuPlacement } from './context'\nimport { isKeyboardFocus } from '../../utils/focus'\n\n// @a11y @core\n/**\n * A menu of actions, opened by a button and closed as soon as one is chosen. It\n * follows the ARIA menu pattern, which is what tells a screen reader that these are\n * commands rather than links or options in a list.\n *\n * It rests on the browser's own popover support: the panel closes on a click outside\n * or on Escape without a line of code, and it positions itself in CSS against the\n * button that opened it — the browser knows which one, since that button names the\n * panel it opens.\n *\n * The JavaScript here is limited to what the platform does not do: keeping\n * `v-model:open` and the browser's own state in step, moving the focus into the panel\n * when it opens, and giving it back to the trigger when it closes. The keyboard inside\n * the panel — the arrows moving from one command to the next — lives in VMenuPanel.\n *\n * How far the focus goes in depends on how the menu was opened. Opened from the\n * keyboard it settles on the first command, ready to be chosen; opened with a mouse or\n * a finger it stops at the panel, so that nothing is picked out for someone who has\n * not asked for a choice yet — the arrows still enter the list from there.\n */\ninterface MenuProps {\n /**\n * Where the panel opens relative to its trigger. The browser moves it to another\n * side by itself when there is not enough room.\n */\n placement?: MenuPlacement\n /**\n * How tall the rows are: 32, 40 or 48 pixels. Submenus inherit it, so it is set\n * once on the menu as a whole.\n */\n size?: 'sm' | 'md' | 'lg'\n /** Takes 4px off the height of every row, submenus included. */\n compact?: boolean\n /**\n * A width for the panel, given as any CSS length or keyword — `16rem`,\n * `max-content`. It applies to the menu itself; submenus keep the default width.\n */\n width?: string\n /**\n * Stops the panel from being narrower than the button that opened it, while leaving\n * it free to grow wider for its content. Submenus are unaffected.\n */\n matchTrigger?: boolean\n}\n\n// Deliberately not assigned to a variable: the template reads the props directly.\nwithDefaults(defineProps<MenuProps>(), {\n placement: 'bottom-start',\n size: 'sm',\n compact: false,\n width: undefined,\n matchTrigger: false,\n})\n\nconst open = defineModel<boolean>('open', { default: false })\n\n/**\n * What the trigger has to carry: the link to the panel it opens, and the two\n * attributes telling assistive technology that a menu is attached to this button and\n * whether it is currently open.\n */\ntype MenuTriggerProps = {\n popovertarget: string\n 'aria-haspopup': 'menu'\n 'aria-expanded': boolean\n 'aria-controls': string\n}\n\ndefineSlots<{\n /**\n * The button that opens the menu. Bind the `triggerProps` it receives onto it —\n * that is what wires the two together.\n */\n trigger(props: { triggerProps: MenuTriggerProps }): unknown\n /** The contents of the menu: VMenuItem, VMenuGroup and VMenuSeparator. */\n default(): unknown\n}>()\n\nconst panelRef = ref<InstanceType<typeof VMenuPanel> | null>(null)\nconst menuId = useId()\nconst shown = ref(false)\n\nconst triggerProps = computed<MenuTriggerProps>(() => ({\n popovertarget: menuId,\n 'aria-haspopup': 'menu',\n 'aria-expanded': open.value,\n 'aria-controls': menuId,\n}))\n\n// Closing this panel closes every submenu with it: they are rendered inside it, and\n// the browser closes a stack of popovers from the outside in.\nprovide(menuKey, { closeAll: () => panelRef.value?.hide() })\n\n// @a11y — the focus half of the bridge: into the panel when it opens, back to the\n// trigger when it closes. Keeping the state in step alone would leave a keyboard user\n// stranded at the top of the page every time a menu opened or closed.\n//\n// WHERE it lands in the panel is the whole question, and the browser is the one that\n// answers it. In a menu the focus IS the highlight (see the rule in VMenuItem), so\n// taking the first item singles out a command — which is what someone arriving on the\n// arrows wants, and what someone who has just clicked never asked for. `:focus-visible`\n// is exactly that distinction, read off whatever holds the focus at this instant: the\n// trigger, since opening a popover through `popovertarget` does not move the focus.\n//\n// The pointer branch focuses the PANEL rather than nothing at all, and that is\n// structural: every key the menu answers to is listened for on the panel element, so\n// focus left outside it — on a trigger that is a DOM sibling — would silence the arrows,\n// Home/End and the Tab that closes the menu. Both ways of being wrong are mild and\n// symmetric: a misread pointer costs one extra keystroke, a misread keyboard gives back\n// the older behaviour.\nfunction onToggle(value: boolean) {\n shown.value = value\n open.value = value\n if (value) {\n if (isKeyboardFocus(document.activeElement)) panelRef.value?.focusFirst()\n else panelRef.value?.focusPanel()\n } else {\n // The browser's own dismissal — a click outside, Escape — leaves the focus\n // nowhere, on the page body. Only then is it handed back to the trigger: if the\n // focus has already moved somewhere else deliberately, it must be left alone.\n const active = document.activeElement\n if (!active || active === document.body || panelRef.value?.el?.contains(active)) {\n menuInvoker(menuId)?.focus()\n }\n }\n}\n\n// Opening and closing from the model. The guard is what keeps the two directions from\n// chasing each other: a menu the browser has just closed already reports it here.\nwatch(open, (value) => {\n if (value === shown.value) return\n if (value) panelRef.value?.show()\n else panelRef.value?.hide()\n})\n\n// @ssr — a watcher does not run during the server render, so a menu asked to be open\n// from the start would never be told to open. Replaying the initial state on mount is\n// what covers that case.\nonMounted(() => {\n if (open.value) panelRef.value?.show()\n})\n</script>\n\n<template>\n <slot name=\"trigger\" :trigger-props=\"triggerProps\" />\n <VMenuPanel\n :id=\"menuId\"\n ref=\"panelRef\"\n :placement=\"placement\"\n :size=\"size\"\n :compact=\"compact\"\n :width=\"width\"\n :match-trigger=\"matchTrigger\"\n @toggle=\"onToggle\"\n >\n <slot />\n </VMenuPanel>\n</template>\n"],"mappings":""}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { menuInvoker as e, menuKey as t } from "./context.js";
|
|
2
|
+
import n from "./VMenuPanel.js";
|
|
3
|
+
import { isKeyboardFocus as r } from "../../utils/focus.js";
|
|
4
|
+
import { Fragment as i, computed as a, createElementBlock as o, createVNode as s, defineComponent as c, mergeModels as l, onMounted as u, openBlock as d, provide as f, ref as p, renderSlot as m, unref as h, useId as g, useModel as _, watch as v, withCtx as y } from "vue";
|
|
5
|
+
//#region src/components/VMenu/VMenu.vue?vue&type=script&setup=true&lang.ts
|
|
6
|
+
var b = /*@__PURE__*/ c({
|
|
7
|
+
__name: "VMenu",
|
|
8
|
+
props: /*@__PURE__*/ l({
|
|
9
|
+
placement: { default: "bottom-start" },
|
|
10
|
+
size: { default: "sm" },
|
|
11
|
+
compact: {
|
|
12
|
+
type: Boolean,
|
|
13
|
+
default: !1
|
|
14
|
+
},
|
|
15
|
+
width: { default: void 0 },
|
|
16
|
+
matchTrigger: {
|
|
17
|
+
type: Boolean,
|
|
18
|
+
default: !1
|
|
19
|
+
}
|
|
20
|
+
}, {
|
|
21
|
+
open: {
|
|
22
|
+
type: Boolean,
|
|
23
|
+
default: !1
|
|
24
|
+
},
|
|
25
|
+
openModifiers: {}
|
|
26
|
+
}),
|
|
27
|
+
emits: ["update:open"],
|
|
28
|
+
setup(c) {
|
|
29
|
+
let l = _(c, "open"), b = p(null), x = g(), S = p(!1), C = a(() => ({
|
|
30
|
+
popovertarget: x,
|
|
31
|
+
"aria-haspopup": "menu",
|
|
32
|
+
"aria-expanded": l.value,
|
|
33
|
+
"aria-controls": x
|
|
34
|
+
}));
|
|
35
|
+
f(t, { closeAll: () => b.value?.hide() });
|
|
36
|
+
function w(t) {
|
|
37
|
+
if (S.value = t, l.value = t, t) r(document.activeElement) ? b.value?.focusFirst() : b.value?.focusPanel();
|
|
38
|
+
else {
|
|
39
|
+
let t = document.activeElement;
|
|
40
|
+
(!t || t === document.body || b.value?.el?.contains(t)) && e(x)?.focus();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return v(l, (e) => {
|
|
44
|
+
e !== S.value && (e ? b.value?.show() : b.value?.hide());
|
|
45
|
+
}), u(() => {
|
|
46
|
+
l.value && b.value?.show();
|
|
47
|
+
}), (e, t) => (d(), o(i, null, [m(e.$slots, "trigger", { triggerProps: C.value }), s(n, {
|
|
48
|
+
id: h(x),
|
|
49
|
+
ref_key: "panelRef",
|
|
50
|
+
ref: b,
|
|
51
|
+
placement: c.placement,
|
|
52
|
+
size: c.size,
|
|
53
|
+
compact: c.compact,
|
|
54
|
+
width: c.width,
|
|
55
|
+
"match-trigger": c.matchTrigger,
|
|
56
|
+
onToggle: w
|
|
57
|
+
}, {
|
|
58
|
+
default: y(() => [m(e.$slots, "default")]),
|
|
59
|
+
_: 3
|
|
60
|
+
}, 8, [
|
|
61
|
+
"id",
|
|
62
|
+
"placement",
|
|
63
|
+
"size",
|
|
64
|
+
"compact",
|
|
65
|
+
"width",
|
|
66
|
+
"match-trigger"
|
|
67
|
+
])], 64));
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
//#endregion
|
|
71
|
+
export { b as default };
|
|
72
|
+
|
|
73
|
+
//# sourceMappingURL=VMenu.vue_vue_type_script_setup_true_lang.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VMenu.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/VMenu/VMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, onMounted, provide, ref, useId, watch } from 'vue'\n\nimport VMenuPanel from './VMenuPanel.vue'\nimport { menuInvoker, menuKey } from './context'\nimport type { MenuPlacement } from './context'\nimport { isKeyboardFocus } from '../../utils/focus'\n\n// @a11y @core\n/**\n * A menu of actions, opened by a button and closed as soon as one is chosen. It\n * follows the ARIA menu pattern, which is what tells a screen reader that these are\n * commands rather than links or options in a list.\n *\n * It rests on the browser's own popover support: the panel closes on a click outside\n * or on Escape without a line of code, and it positions itself in CSS against the\n * button that opened it — the browser knows which one, since that button names the\n * panel it opens.\n *\n * The JavaScript here is limited to what the platform does not do: keeping\n * `v-model:open` and the browser's own state in step, moving the focus into the panel\n * when it opens, and giving it back to the trigger when it closes. The keyboard inside\n * the panel — the arrows moving from one command to the next — lives in VMenuPanel.\n *\n * How far the focus goes in depends on how the menu was opened. Opened from the\n * keyboard it settles on the first command, ready to be chosen; opened with a mouse or\n * a finger it stops at the panel, so that nothing is picked out for someone who has\n * not asked for a choice yet — the arrows still enter the list from there.\n */\ninterface MenuProps {\n /**\n * Where the panel opens relative to its trigger. The browser moves it to another\n * side by itself when there is not enough room.\n */\n placement?: MenuPlacement\n /**\n * How tall the rows are: 32, 40 or 48 pixels. Submenus inherit it, so it is set\n * once on the menu as a whole.\n */\n size?: 'sm' | 'md' | 'lg'\n /** Takes 4px off the height of every row, submenus included. */\n compact?: boolean\n /**\n * A width for the panel, given as any CSS length or keyword — `16rem`,\n * `max-content`. It applies to the menu itself; submenus keep the default width.\n */\n width?: string\n /**\n * Stops the panel from being narrower than the button that opened it, while leaving\n * it free to grow wider for its content. Submenus are unaffected.\n */\n matchTrigger?: boolean\n}\n\n// Deliberately not assigned to a variable: the template reads the props directly.\nwithDefaults(defineProps<MenuProps>(), {\n placement: 'bottom-start',\n size: 'sm',\n compact: false,\n width: undefined,\n matchTrigger: false,\n})\n\nconst open = defineModel<boolean>('open', { default: false })\n\n/**\n * What the trigger has to carry: the link to the panel it opens, and the two\n * attributes telling assistive technology that a menu is attached to this button and\n * whether it is currently open.\n */\ntype MenuTriggerProps = {\n popovertarget: string\n 'aria-haspopup': 'menu'\n 'aria-expanded': boolean\n 'aria-controls': string\n}\n\ndefineSlots<{\n /**\n * The button that opens the menu. Bind the `triggerProps` it receives onto it —\n * that is what wires the two together.\n */\n trigger(props: { triggerProps: MenuTriggerProps }): unknown\n /** The contents of the menu: VMenuItem, VMenuGroup and VMenuSeparator. */\n default(): unknown\n}>()\n\nconst panelRef = ref<InstanceType<typeof VMenuPanel> | null>(null)\nconst menuId = useId()\nconst shown = ref(false)\n\nconst triggerProps = computed<MenuTriggerProps>(() => ({\n popovertarget: menuId,\n 'aria-haspopup': 'menu',\n 'aria-expanded': open.value,\n 'aria-controls': menuId,\n}))\n\n// Closing this panel closes every submenu with it: they are rendered inside it, and\n// the browser closes a stack of popovers from the outside in.\nprovide(menuKey, { closeAll: () => panelRef.value?.hide() })\n\n// @a11y — the focus half of the bridge: into the panel when it opens, back to the\n// trigger when it closes. Keeping the state in step alone would leave a keyboard user\n// stranded at the top of the page every time a menu opened or closed.\n//\n// WHERE it lands in the panel is the whole question, and the browser is the one that\n// answers it. In a menu the focus IS the highlight (see the rule in VMenuItem), so\n// taking the first item singles out a command — which is what someone arriving on the\n// arrows wants, and what someone who has just clicked never asked for. `:focus-visible`\n// is exactly that distinction, read off whatever holds the focus at this instant: the\n// trigger, since opening a popover through `popovertarget` does not move the focus.\n//\n// The pointer branch focuses the PANEL rather than nothing at all, and that is\n// structural: every key the menu answers to is listened for on the panel element, so\n// focus left outside it — on a trigger that is a DOM sibling — would silence the arrows,\n// Home/End and the Tab that closes the menu. Both ways of being wrong are mild and\n// symmetric: a misread pointer costs one extra keystroke, a misread keyboard gives back\n// the older behaviour.\nfunction onToggle(value: boolean) {\n shown.value = value\n open.value = value\n if (value) {\n if (isKeyboardFocus(document.activeElement)) panelRef.value?.focusFirst()\n else panelRef.value?.focusPanel()\n } else {\n // The browser's own dismissal — a click outside, Escape — leaves the focus\n // nowhere, on the page body. Only then is it handed back to the trigger: if the\n // focus has already moved somewhere else deliberately, it must be left alone.\n const active = document.activeElement\n if (!active || active === document.body || panelRef.value?.el?.contains(active)) {\n menuInvoker(menuId)?.focus()\n }\n }\n}\n\n// Opening and closing from the model. The guard is what keeps the two directions from\n// chasing each other: a menu the browser has just closed already reports it here.\nwatch(open, (value) => {\n if (value === shown.value) return\n if (value) panelRef.value?.show()\n else panelRef.value?.hide()\n})\n\n// @ssr — a watcher does not run during the server render, so a menu asked to be open\n// from the start would never be told to open. Replaying the initial state on mount is\n// what covers that case.\nonMounted(() => {\n if (open.value) panelRef.value?.show()\n})\n</script>\n\n<template>\n <slot name=\"trigger\" :trigger-props=\"triggerProps\" />\n <VMenuPanel\n :id=\"menuId\"\n ref=\"panelRef\"\n :placement=\"placement\"\n :size=\"size\"\n :compact=\"compact\"\n :width=\"width\"\n :match-trigger=\"matchTrigger\"\n @toggle=\"onToggle\"\n >\n <slot />\n </VMenuPanel>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+DA,IAAM,IAAO,EAAoB,GAAC,MAA0B,GAwBtD,IAAW,EAA4C,IAAI,GAC3D,IAAS,EAAM,GACf,IAAQ,EAAI,EAAK,GAEjB,IAAe,SAAkC;GACrD,eAAe;GACf,iBAAiB;GACjB,iBAAiB,EAAK;GACtB,iBAAiB;EACnB,EAAE;EAIF,EAAQ,GAAS,EAAE,gBAAgB,EAAS,OAAO,KAAK,EAAE,CAAC;EAmB3D,SAAS,EAAS,GAAgB;GAGhC,IAFA,EAAM,QAAQ,GACd,EAAK,QAAQ,GACT,GACF,AAAI,EAAgB,SAAS,aAAa,IAAG,EAAS,OAAO,WAAW,IACnE,EAAS,OAAO,WAAW;QAC3B;IAIL,IAAM,IAAS,SAAS;IACxB,CAAI,CAAC,KAAU,MAAW,SAAS,QAAQ,EAAS,OAAO,IAAI,SAAS,CAAM,MAC5E,EAAY,CAAM,CAAC,EAAE,MAAM;GAE/B;EACF;SAIA,EAAM,IAAO,MAAU;GACjB,MAAU,EAAM,UAChB,IAAO,EAAS,OAAO,KAAK,IAC3B,EAAS,OAAO,KAAK;EAC5B,CAAC,GAKD,QAAgB;GACd,AAAI,EAAK,SAAO,EAAS,OAAO,KAAK;EACvC,CAAC,+BAIC,EAAqD,EAAA,QAAA,WAAA,EAA/B,cAAe,EAAA,MAAY,CAAA,GACjD,EAWa,GAAA;GAVV,IAAI,EAAA,CAAA;YACD;GAAJ,KAAI;GACH,WAAW,EAAA;GACX,MAAM,EAAA;GACN,SAAS,EAAA;GACT,OAAO,EAAA;GACP,iBAAe,EAAA;GACP;;oBAED,CAAR,EAAQ,EAAA,QAAA,SAAA,CAAA,CAAA"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
@layer vectis.reset, vectis.tokens, vectis.components, vectis.utilities;
|
|
2
|
+
@layer vectis.components{.v-menu-group{gap:var(--vectis-space-1);flex-direction:column;display:flex}.v-menu-group-label{min-height:var(--control-height);padding:var(--vectis-space-1) var(--control-padding-inline);font-size:var(--vectis-text-overline-size);font-weight:var(--vectis-text-overline-weight);letter-spacing:var(--vectis-text-overline-tracking);color:var(--vectis-color-text-muted);align-items:center;display:flex}}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A named section inside a menu — "Sort by", "Recent files". The name is announced as
|
|
3
|
+
* the group's label rather than being read as one more item, and it is plain text: it
|
|
4
|
+
* cannot be chosen, and the arrow keys walk straight past it.
|
|
5
|
+
*/
|
|
6
|
+
interface MenuGroupProps {
|
|
7
|
+
/** The name of the section. It is a heading, not a command: nothing happens on click. */
|
|
8
|
+
label: string;
|
|
9
|
+
}
|
|
10
|
+
type __VLS_Slots = {
|
|
11
|
+
/** The commands belonging to this section. */
|
|
12
|
+
default(): unknown;
|
|
13
|
+
};
|
|
14
|
+
declare const __VLS_base: import('vue').DefineComponent<MenuGroupProps, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<MenuGroupProps> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
15
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
16
|
+
declare const _default: typeof __VLS_export;
|
|
17
|
+
export default _default;
|
|
18
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
19
|
+
new (): {
|
|
20
|
+
$slots: S;
|
|
21
|
+
};
|
|
22
|
+
};
|