vectis-ui 0.12.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/VAccordion/VAccordion.css +1 -1
- package/dist/components/VAccordion/VAccordion.d.ts +6 -5
- package/dist/components/VAccordion/VAccordion.js.map +1 -1
- package/dist/components/VAccordion/VAccordion.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VAccordion/VAccordionItem.css +1 -1
- package/dist/components/VAccordion/VAccordionItem.d.ts +1 -1
- package/dist/components/VAccordion/VAccordionItem.js.map +1 -1
- package/dist/components/VAccordion/VAccordionItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VAlert/VAlert.css +2 -0
- package/dist/components/VAlert/VAlert.d.ts +73 -0
- package/dist/components/VAlert/VAlert.js +9 -0
- package/dist/components/VAlert/VAlert.js.map +1 -0
- package/dist/components/VAlert/VAlert.vue_vue_type_script_setup_true_lang.js +96 -0
- package/dist/components/VAlert/VAlert.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VAvatar/VAvatar.d.ts +2 -2
- package/dist/components/VAvatar/VAvatarGroup.d.ts +1 -1
- package/dist/components/VAvatar/VAvatarGroup.vue_vue_type_script_setup_true_lang.js +8 -8
- package/dist/components/VBadge/VBadge.d.ts +3 -3
- package/dist/components/VBreadcrumb/VBreadcrumb.vue_vue_type_script_setup_true_lang.js +9 -9
- package/dist/components/VButton/VButton.d.ts +4 -4
- package/dist/components/VButton/VButtonGroup.css +1 -1
- package/dist/components/VButton/VButtonGroup.d.ts +2 -2
- package/dist/components/VButton/VButtonGroup.js.map +1 -1
- package/dist/components/VButton/VButtonGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCalendar/VCalendar.css +1 -1
- package/dist/components/VCalendar/VCalendar.d.ts +7 -1
- package/dist/components/VCalendar/VCalendar.js.map +1 -1
- package/dist/components/VCalendar/VCalendar.vue_vue_type_script_setup_true_lang.js +20 -18
- package/dist/components/VCalendar/VCalendar.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCalendar/VCalendarEvent.js.map +1 -1
- package/dist/components/VCalendar/VCalendarEvent.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCalendar/VCalendarMonth.css +1 -1
- package/dist/components/VCalendar/VCalendarMonth.d.ts +2 -2
- package/dist/components/VCalendar/VCalendarMonth.js.map +1 -1
- package/dist/components/VCalendar/VCalendarMonth.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCalendar/VCalendarTimeGrid.css +1 -1
- package/dist/components/VCalendar/VCalendarTimeGrid.d.ts +3 -3
- package/dist/components/VCalendar/VCalendarTimeGrid.js.map +1 -1
- package/dist/components/VCalendar/VCalendarTimeGrid.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCalendar/VCalendarYear.css +1 -1
- package/dist/components/VCalendar/VCalendarYear.js.map +1 -1
- package/dist/components/VCalendar/VCalendarYear.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCalendar/gesture.d.ts +1 -16
- package/dist/components/VCalendar/gesture.js +1 -1
- package/dist/components/VCalendar/gesture.js.map +1 -1
- package/dist/components/VCalendar/types.d.ts +2 -0
- package/dist/components/VCard/VCard.css +2 -0
- package/dist/components/VCard/VCard.d.ts +87 -0
- package/dist/components/VCard/VCard.js +9 -0
- package/dist/components/VCard/VCard.js.map +1 -0
- package/dist/components/VCard/VCard.vue_vue_type_script_setup_true_lang.js +103 -0
- package/dist/components/VCard/VCard.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VCarousel/VCarousel.d.ts +1 -1
- package/dist/components/VCarousel/VCarousel.js.map +1 -1
- package/dist/components/VCarousel/VCarousel.vue_vue_type_script_setup_true_lang.js +18 -18
- package/dist/components/VCarousel/VCarousel.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCheckbox/VCheckMark.css +2 -0
- package/dist/components/VCheckbox/VCheckMark.js +9 -0
- package/dist/components/VCheckbox/VCheckMark.js.map +1 -0
- package/dist/components/VCheckbox/VCheckMark.vue_vue_type_script_setup_true_lang.js +33 -0
- package/dist/components/VCheckbox/VCheckMark.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VCheckbox/VCheckbox.css +1 -1
- package/dist/components/VCheckbox/VCheckbox.d.ts +8 -3
- package/dist/components/VCheckbox/VCheckbox.js.map +1 -1
- package/dist/components/VCheckbox/VCheckbox.vue_vue_type_script_setup_true_lang.js +54 -69
- package/dist/components/VCheckbox/VCheckbox.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VChip/VChip.d.ts +6 -6
- package/dist/components/VChip/VChip.js.map +1 -1
- package/dist/components/VChip/VChip.vue_vue_type_script_setup_true_lang.js +26 -26
- package/dist/components/VChip/VChip.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VColorInput/VColorInput.css +2 -0
- package/dist/components/VColorInput/VColorInput.d.ts +113 -0
- package/dist/components/VColorInput/VColorInput.js +9 -0
- package/dist/components/VColorInput/VColorInput.js.map +1 -0
- package/dist/components/VColorInput/VColorInput.vue_vue_type_script_setup_true_lang.js +230 -0
- package/dist/components/VColorInput/VColorInput.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VColorPicker/VColorPicker.css +2 -0
- package/dist/components/VColorPicker/VColorPicker.d.ts +67 -0
- package/dist/components/VColorPicker/VColorPicker.js +9 -0
- package/dist/components/VColorPicker/VColorPicker.js.map +1 -0
- package/dist/components/VColorPicker/VColorPicker.vue_vue_type_script_setup_true_lang.js +390 -0
- package/dist/components/VColorPicker/VColorPicker.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VColorPicker/color.d.ts +42 -0
- package/dist/components/VColorPicker/color.js +158 -0
- package/dist/components/VColorPicker/color.js.map +1 -0
- package/dist/components/VCombobox/VCombobox.css +1 -1
- package/dist/components/VCombobox/VCombobox.d.ts +46 -60
- package/dist/components/VCombobox/VCombobox.js.map +1 -1
- package/dist/components/VCombobox/VCombobox.vue_vue_type_script_setup_true_lang.js +271 -372
- package/dist/components/VCombobox/VCombobox.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCommandPalette/VCommandPalette.css +2 -0
- package/dist/components/VCommandPalette/VCommandPalette.d.ts +163 -0
- package/dist/components/VCommandPalette/VCommandPalette.js +9 -0
- package/dist/components/VCommandPalette/VCommandPalette.js.map +1 -0
- package/dist/components/VCommandPalette/VCommandPalette.vue_vue_type_script_setup_true_lang.js +321 -0
- package/dist/components/VCommandPalette/VCommandPalette.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VCommandPalette/VCommandPaletteItem.css +2 -0
- package/dist/components/VCommandPalette/VCommandPaletteItem.d.ts +38 -0
- package/dist/components/VCommandPalette/VCommandPaletteItem.js +9 -0
- package/dist/components/VCommandPalette/VCommandPaletteItem.js.map +1 -0
- package/dist/components/VCommandPalette/VCommandPaletteItem.vue_vue_type_script_setup_true_lang.js +69 -0
- package/dist/components/VCommandPalette/VCommandPaletteItem.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VContextMenu/VContextMenu.css +2 -0
- package/dist/components/VContextMenu/VContextMenu.d.ts +66 -0
- package/dist/components/VContextMenu/VContextMenu.js +9 -0
- package/dist/components/VContextMenu/VContextMenu.js.map +1 -0
- package/dist/components/VContextMenu/VContextMenu.vue_vue_type_script_setup_true_lang.js +148 -0
- package/dist/components/VContextMenu/VContextMenu.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VDataTable/VDataTable.css +1 -1
- package/dist/components/VDataTable/VDataTable.d.ts +41 -16
- package/dist/components/VDataTable/VDataTable.js.map +1 -1
- package/dist/components/VDataTable/VDataTable.vue_vue_type_script_setup_true_lang.js +307 -195
- package/dist/components/VDataTable/VDataTable.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VDateInput/VDateInput.d.ts +27 -7
- package/dist/components/VDateInput/VDateInput.js.map +1 -1
- package/dist/components/VDateInput/VDateInput.vue_vue_type_script_setup_true_lang.js +170 -162
- package/dist/components/VDateInput/VDateInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VDatePicker/VDatePicker.d.ts +3 -3
- package/dist/components/VDatePicker/VDatePicker.js.map +1 -1
- package/dist/components/VDatePicker/VDatePicker.vue_vue_type_script_setup_true_lang.js +228 -227
- package/dist/components/VDatePicker/VDatePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VDatePicker/keyboard.d.ts +7 -7
- package/dist/components/VDatePicker/keyboard.js +8 -6
- package/dist/components/VDatePicker/keyboard.js.map +1 -1
- package/dist/components/VDatePicker/names.js +16 -20
- package/dist/components/VDatePicker/names.js.map +1 -1
- package/dist/components/VDialog/VDialog.d.ts +2 -4
- package/dist/components/VDialog/VDialog.js.map +1 -1
- package/dist/components/VDialog/VDialog.vue_vue_type_script_setup_true_lang.js +46 -77
- package/dist/components/VDialog/VDialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VDrawer/VDrawer.css +2 -0
- package/dist/components/VDrawer/VDrawer.d.ts +102 -0
- package/dist/components/VDrawer/VDrawer.js +9 -0
- package/dist/components/VDrawer/VDrawer.js.map +1 -0
- package/dist/components/VDrawer/VDrawer.vue_vue_type_script_setup_true_lang.js +128 -0
- package/dist/components/VDrawer/VDrawer.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VEmptyState/VEmptyState.css +2 -0
- package/dist/components/VEmptyState/VEmptyState.d.ts +43 -0
- package/dist/components/VEmptyState/VEmptyState.js +9 -0
- package/dist/components/VEmptyState/VEmptyState.js.map +1 -0
- package/dist/components/VEmptyState/VEmptyState.vue_vue_type_script_setup_true_lang.js +48 -0
- package/dist/components/VEmptyState/VEmptyState.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VField/VField.css +2 -0
- package/dist/components/VField/VField.d.ts +84 -0
- package/dist/components/VField/VField.js +9 -0
- package/dist/components/VField/VField.js.map +1 -0
- package/dist/components/VField/VField.vue_vue_type_script_setup_true_lang.js +99 -0
- package/dist/components/VField/VField.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VField/VFieldAnnouncer.d.ts +7 -0
- package/dist/components/VField/VFieldAnnouncer.js +7 -0
- package/dist/components/VField/VFieldAnnouncer.js.map +1 -0
- package/dist/components/VField/VFieldAnnouncer.vue_vue_type_script_setup_true_lang.js +19 -0
- package/dist/components/VField/VFieldAnnouncer.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VField/VFieldMessage.d.ts +11 -0
- package/dist/components/VField/VFieldMessage.js +7 -0
- package/dist/components/VField/VFieldMessage.js.map +1 -0
- package/dist/components/VField/VFieldMessage.vue_vue_type_script_setup_true_lang.js +32 -0
- package/dist/components/VField/VFieldMessage.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VFieldset/VFieldset.css +2 -0
- package/dist/components/VFieldset/VFieldset.d.ts +52 -0
- package/dist/components/VFieldset/VFieldset.js +9 -0
- package/dist/components/VFieldset/VFieldset.js.map +1 -0
- package/dist/components/VFieldset/VFieldset.vue_vue_type_script_setup_true_lang.js +63 -0
- package/dist/components/VFieldset/VFieldset.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VFileInput/VFileInput.css +1 -1
- package/dist/components/VFileInput/VFileInput.d.ts +31 -7
- package/dist/components/VFileInput/VFileInput.js.map +1 -1
- package/dist/components/VFileInput/VFileInput.vue_vue_type_script_setup_true_lang.js +168 -161
- package/dist/components/VFileInput/VFileInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VFilePicker/VFilePicker.d.ts +4 -4
- package/dist/components/VHotkeys/VHotkeys.css +1 -1
- package/dist/components/VHotkeys/VHotkeys.js.map +1 -1
- package/dist/components/VHotkeys/VHotkeys.vue_vue_type_script_setup_true_lang.js +27 -30
- package/dist/components/VHotkeys/VHotkeys.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VHotkeys/platform.d.ts +2 -0
- package/dist/components/VHotkeys/platform.js +24 -5
- package/dist/components/VHotkeys/platform.js.map +1 -1
- package/dist/components/VHoverCard/VHoverCard.css +2 -0
- package/dist/components/VHoverCard/VHoverCard.d.ts +62 -0
- package/dist/components/VHoverCard/VHoverCard.js +9 -0
- package/dist/components/VHoverCard/VHoverCard.js.map +1 -0
- package/dist/components/VHoverCard/VHoverCard.vue_vue_type_script_setup_true_lang.js +97 -0
- package/dist/components/VHoverCard/VHoverCard.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VIcon/icons/add.d.ts +5 -0
- package/dist/components/VIcon/icons/add.js +9 -0
- package/dist/components/VIcon/icons/add.js.map +1 -0
- package/dist/components/VIcon/icons/colorize.d.ts +5 -0
- package/dist/components/VIcon/icons/colorize.js +9 -0
- package/dist/components/VIcon/icons/colorize.js.map +1 -0
- package/dist/components/VIcon/icons/inbox.d.ts +5 -0
- package/dist/components/VIcon/icons/inbox.js +9 -0
- package/dist/components/VIcon/icons/inbox.js.map +1 -0
- package/dist/components/VIcon/icons/index.d.ts +42 -2
- package/dist/components/VIcon/icons/index.js +88 -72
- package/dist/components/VIcon/icons/index.js.map +1 -1
- package/dist/components/VIcon/icons/names.d.ts +2 -2
- package/dist/components/VIcon/icons/names.js +1 -1
- package/dist/components/VIcon/icons/names.js.map +1 -1
- package/dist/components/VIcon/icons/open_in_new.d.ts +5 -0
- package/dist/components/VIcon/icons/open_in_new.js +9 -0
- package/dist/components/VIcon/icons/open_in_new.js.map +1 -0
- package/dist/components/VIcon/icons/priority_high.d.ts +5 -0
- package/dist/components/VIcon/icons/priority_high.js +9 -0
- package/dist/components/VIcon/icons/priority_high.js.map +1 -0
- package/dist/components/VIcon/icons/remove.d.ts +5 -0
- package/dist/components/VIcon/icons/remove.js +9 -0
- package/dist/components/VIcon/icons/remove.js.map +1 -0
- package/dist/components/VIcon/icons/search_off.d.ts +5 -0
- package/dist/components/VIcon/icons/search_off.js +9 -0
- package/dist/components/VIcon/icons/search_off.js.map +1 -0
- package/dist/components/VIcon/icons/star.d.ts +5 -0
- package/dist/components/VIcon/icons/star.js +9 -0
- package/dist/components/VIcon/icons/star.js.map +1 -0
- package/dist/components/VIconButton/VIconButton.d.ts +4 -4
- package/dist/components/VInput/VInput.css +1 -1
- package/dist/components/VInput/VInput.d.ts +51 -2
- package/dist/components/VInput/VInput.js.map +1 -1
- package/dist/components/VInput/VInput.vue_vue_type_script_setup_true_lang.js +129 -106
- package/dist/components/VInput/VInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VInput/VInputGroup.css +1 -1
- package/dist/components/VInput/VInputGroup.d.ts +20 -0
- package/dist/components/VInput/VInputGroup.js.map +1 -1
- package/dist/components/VInput/VInputGroup.vue_vue_type_script_setup_true_lang.js +50 -51
- package/dist/components/VInput/VInputGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VInputOTP/VInputOTP.css +1 -1
- package/dist/components/VInputOTP/VInputOTP.d.ts +27 -4
- package/dist/components/VInputOTP/VInputOTP.js.map +1 -1
- package/dist/components/VInputOTP/VInputOTP.vue_vue_type_script_setup_true_lang.js +131 -113
- package/dist/components/VInputOTP/VInputOTP.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VLink/VLink.css +2 -0
- package/dist/components/VLink/VLink.d.ts +53 -0
- package/dist/components/VLink/VLink.js +9 -0
- package/dist/components/VLink/VLink.js.map +1 -0
- package/dist/components/VLink/VLink.vue_vue_type_script_setup_true_lang.js +58 -0
- package/dist/components/VLink/VLink.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VListbox/VListboxChevron.css +2 -0
- package/dist/components/VListbox/VListboxChevron.d.ts +12 -0
- package/dist/components/VListbox/VListboxChevron.js +9 -0
- package/dist/components/VListbox/VListboxChevron.js.map +1 -0
- package/dist/components/VListbox/VListboxChevron.vue_vue_type_script_setup_true_lang.js +25 -0
- package/dist/components/VListbox/VListboxChevron.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VListbox/VListboxGroup.css +2 -0
- package/dist/components/VListbox/VListboxGroup.d.ts +27 -0
- package/dist/components/VListbox/VListboxGroup.js +9 -0
- package/dist/components/VListbox/VListboxGroup.js.map +1 -0
- package/dist/components/VListbox/VListboxGroup.vue_vue_type_script_setup_true_lang.js +21 -0
- package/dist/components/VListbox/VListboxGroup.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VListbox/VListboxOption.css +2 -0
- package/dist/components/{VCombobox/VComboboxOption.d.ts → VListbox/VListboxOption.d.ts} +4 -4
- package/dist/components/VListbox/VListboxOption.js +9 -0
- package/dist/components/VListbox/VListboxOption.js.map +1 -0
- package/dist/components/{VCombobox/VComboboxOption.vue_vue_type_script_setup_true_lang.js → VListbox/VListboxOption.vue_vue_type_script_setup_true_lang.js} +6 -6
- package/dist/components/VListbox/VListboxOption.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VListbox/VListboxPanel.css +2 -0
- package/dist/components/VListbox/VListboxPanel.d.ts +59 -0
- package/dist/components/VListbox/VListboxPanel.js +9 -0
- package/dist/components/VListbox/VListboxPanel.js.map +1 -0
- package/dist/components/VListbox/VListboxPanel.vue_vue_type_script_setup_true_lang.js +123 -0
- package/dist/components/VListbox/VListboxPanel.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VListbox/VListboxSeparator.css +2 -0
- package/dist/components/VListbox/VListboxSeparator.d.ts +3 -0
- package/dist/components/VListbox/VListboxSeparator.js +9 -0
- package/dist/components/VListbox/VListboxSeparator.js.map +1 -0
- package/dist/components/{VCombobox/VComboboxSeparator.vue_vue_type_script_setup_true_lang.js → VListbox/VListboxSeparator.vue_vue_type_script_setup_true_lang.js} +4 -4
- package/dist/components/VListbox/VListboxSeparator.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VListbox/VListboxValues.css +2 -0
- package/dist/components/VListbox/VListboxValues.d.ts +52 -0
- package/dist/components/VListbox/VListboxValues.js +9 -0
- package/dist/components/VListbox/VListboxValues.js.map +1 -0
- package/dist/components/VListbox/VListboxValues.vue_vue_type_script_setup_true_lang.js +103 -0
- package/dist/components/VListbox/VListboxValues.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VMenu/VMenu.d.ts +1 -1
- package/dist/components/VMenu/VMenu.vue_vue_type_script_setup_true_lang.js +9 -9
- package/dist/components/VMenu/VMenuItem.d.ts +1 -1
- package/dist/components/VMenu/VMenuItem.vue_vue_type_script_setup_true_lang.js +16 -16
- package/dist/components/VMenu/VMenuPanel.d.ts +2 -2
- package/dist/components/VMenu/VMenuPanel.js.map +1 -1
- package/dist/components/VMenu/VMenuPanel.vue_vue_type_script_setup_true_lang.js +7 -7
- package/dist/components/VMenu/VMenuPanel.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VMeter/VMeter.css +2 -0
- package/dist/components/VMeter/VMeter.d.ts +77 -0
- package/dist/components/VMeter/VMeter.js +9 -0
- package/dist/components/VMeter/VMeter.js.map +1 -0
- package/dist/components/VMeter/VMeter.vue_vue_type_script_setup_true_lang.js +113 -0
- package/dist/components/VMeter/VMeter.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VNumberInput/VNumberInput.css +2 -0
- package/dist/components/VNumberInput/VNumberInput.d.ts +114 -0
- package/dist/components/VNumberInput/VNumberInput.js +9 -0
- package/dist/components/VNumberInput/VNumberInput.js.map +1 -0
- package/dist/components/VNumberInput/VNumberInput.vue_vue_type_script_setup_true_lang.js +251 -0
- package/dist/components/VNumberInput/VNumberInput.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VNumberInput/number.d.ts +30 -0
- package/dist/components/VNumberInput/number.js +38 -0
- package/dist/components/VNumberInput/number.js.map +1 -0
- package/dist/components/VPagination/VPagination.d.ts +1 -1
- package/dist/components/VPagination/VPagination.vue_vue_type_script_setup_true_lang.js +76 -76
- package/dist/components/VProgressCircular/VProgressCircular.d.ts +2 -2
- package/dist/components/VProgressLinear/VProgressLinear.css +1 -1
- package/dist/components/VProgressLinear/VProgressLinear.d.ts +10 -7
- package/dist/components/VProgressLinear/VProgressLinear.js.map +1 -1
- package/dist/components/VProgressLinear/VProgressLinear.vue_vue_type_script_setup_true_lang.js +52 -34
- package/dist/components/VProgressLinear/VProgressLinear.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VRadio/VRadio.d.ts +8 -3
- package/dist/components/VRadio/VRadio.js.map +1 -1
- package/dist/components/VRadio/VRadio.vue_vue_type_script_setup_true_lang.js +52 -46
- package/dist/components/VRadio/VRadio.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VRating/VRating.css +2 -0
- package/dist/components/VRating/VRating.d.ts +92 -0
- package/dist/components/VRating/VRating.js +9 -0
- package/dist/components/VRating/VRating.js.map +1 -0
- package/dist/components/VRating/VRating.vue_vue_type_script_setup_true_lang.js +158 -0
- package/dist/components/VRating/VRating.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VResizable/VResizable.css +2 -0
- package/dist/components/VResizable/VResizable.d.ts +50 -0
- package/dist/components/VResizable/VResizable.js +9 -0
- package/dist/components/VResizable/VResizable.js.map +1 -0
- package/dist/components/VResizable/VResizable.vue_vue_type_script_setup_true_lang.js +225 -0
- package/dist/components/VResizable/VResizable.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VResizable/VResizablePanel.css +2 -0
- package/dist/components/VResizable/VResizablePanel.d.ts +60 -0
- package/dist/components/VResizable/VResizablePanel.js +9 -0
- package/dist/components/VResizable/VResizablePanel.js.map +1 -0
- package/dist/components/VResizable/VResizablePanel.vue_vue_type_script_setup_true_lang.js +83 -0
- package/dist/components/VResizable/VResizablePanel.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VResizable/context.d.ts +24 -0
- package/dist/components/VResizable/context.js +6 -0
- package/dist/components/VResizable/context.js.map +1 -0
- package/dist/components/VResizable/layout.d.ts +28 -0
- package/dist/components/VResizable/layout.js +41 -0
- package/dist/components/VResizable/layout.js.map +1 -0
- package/dist/components/VSelect/VSelect.css +2 -0
- package/dist/components/VSelect/VSelect.d.ts +193 -0
- package/dist/components/VSelect/VSelect.js +9 -0
- package/dist/components/VSelect/VSelect.js.map +1 -0
- package/dist/components/VSelect/VSelect.vue_vue_type_script_setup_true_lang.js +424 -0
- package/dist/components/VSelect/VSelect.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VSeparator/VSeparator.js.map +1 -1
- package/dist/components/VSeparator/VSeparator.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSideNavigation/VSideNavigation.vue_vue_type_script_setup_true_lang.js +8 -8
- package/dist/components/VSideNavigation/VSideNavigationItem.d.ts +2 -2
- package/dist/components/VSideNavigation/VSideNavigationItem.js.map +1 -1
- package/dist/components/VSideNavigation/VSideNavigationItem.vue_vue_type_script_setup_true_lang.js +3 -3
- package/dist/components/VSideNavigation/VSideNavigationItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSkeletonLoader/VSkeletonLoader.d.ts +3 -3
- package/dist/components/VSlider/VSlider.css +1 -1
- package/dist/components/VSlider/VSlider.d.ts +34 -8
- package/dist/components/VSlider/VSlider.js.map +1 -1
- package/dist/components/VSlider/VSlider.vue_vue_type_script_setup_true_lang.js +236 -215
- package/dist/components/VSlider/VSlider.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSnackbar/VSnackbar.vue_vue_type_script_setup_true_lang.js +4 -4
- package/dist/components/VSnackbar/state.js.map +1 -1
- package/dist/components/VSplitButton/VSplitButton.css +2 -0
- package/dist/components/VSplitButton/VSplitButton.d.ts +114 -0
- package/dist/components/VSplitButton/VSplitButton.js +9 -0
- package/dist/components/VSplitButton/VSplitButton.js.map +1 -0
- package/dist/components/VSplitButton/VSplitButton.vue_vue_type_script_setup_true_lang.js +148 -0
- package/dist/components/VSplitButton/VSplitButton.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VStepper/VStepper.css +2 -0
- package/dist/components/VStepper/VStepper.d.ts +73 -0
- package/dist/components/VStepper/VStepper.js +9 -0
- package/dist/components/VStepper/VStepper.js.map +1 -0
- package/dist/components/VStepper/VStepper.vue_vue_type_script_setup_true_lang.js +96 -0
- package/dist/components/VStepper/VStepper.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VSwitch/VSwitch.d.ts +8 -3
- package/dist/components/VSwitch/VSwitch.js.map +1 -1
- package/dist/components/VSwitch/VSwitch.vue_vue_type_script_setup_true_lang.js +53 -47
- package/dist/components/VSwitch/VSwitch.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTabs/VTab.css +1 -1
- package/dist/components/VTabs/VTab.d.ts +1 -1
- package/dist/components/VTabs/VTab.js.map +1 -1
- package/dist/components/VTabs/VTab.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTabs/VTabs.css +1 -1
- package/dist/components/VTabs/VTabs.d.ts +13 -5
- package/dist/components/VTabs/VTabs.js.map +1 -1
- package/dist/components/VTabs/VTabs.vue_vue_type_script_setup_true_lang.js +20 -20
- package/dist/components/VTabs/VTabs.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTextarea/VTextarea.css +1 -1
- package/dist/components/VTextarea/VTextarea.d.ts +22 -2
- package/dist/components/VTextarea/VTextarea.js.map +1 -1
- package/dist/components/VTextarea/VTextarea.vue_vue_type_script_setup_true_lang.js +108 -100
- package/dist/components/VTextarea/VTextarea.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTimeInput/VTimeInput.d.ts +27 -7
- package/dist/components/VTimeInput/VTimeInput.js.map +1 -1
- package/dist/components/VTimeInput/VTimeInput.vue_vue_type_script_setup_true_lang.js +187 -171
- package/dist/components/VTimeInput/VTimeInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTimePicker/VTimePicker.d.ts +2 -2
- package/dist/components/VTimePicker/VTimePicker.js.map +1 -1
- package/dist/components/VTimePicker/VTimePicker.vue_vue_type_script_setup_true_lang.js +15 -15
- package/dist/components/VTimePicker/VTimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTimeline/VTimeline.css +2 -0
- package/dist/components/VTimeline/VTimeline.d.ts +59 -0
- package/dist/components/VTimeline/VTimeline.js +9 -0
- package/dist/components/VTimeline/VTimeline.js.map +1 -0
- package/dist/components/VTimeline/VTimeline.vue_vue_type_script_setup_true_lang.js +53 -0
- package/dist/components/VTimeline/VTimeline.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VTimeline/VTimelineItem.css +2 -0
- package/dist/components/VTimeline/VTimelineItem.d.ts +48 -0
- package/dist/components/VTimeline/VTimelineItem.js +9 -0
- package/dist/components/VTimeline/VTimelineItem.js.map +1 -0
- package/dist/components/VTimeline/VTimelineItem.vue_vue_type_script_setup_true_lang.js +70 -0
- package/dist/components/VTimeline/VTimelineItem.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VTimeline/context.d.ts +11 -0
- package/dist/components/VTimeline/context.js +6 -0
- package/dist/components/VTimeline/context.js.map +1 -0
- package/dist/components/VTimeline/datetime.d.ts +8 -0
- package/dist/components/VTimeline/datetime.js +36 -0
- package/dist/components/VTimeline/datetime.js.map +1 -0
- package/dist/components/VToast/VToast.vue_vue_type_script_setup_true_lang.js +8 -8
- package/dist/components/VToast/VToaster.vue_vue_type_script_setup_true_lang.js +12 -12
- package/dist/components/VToggle/VToggle.d.ts +4 -4
- package/dist/components/VToggle/VToggleItem.d.ts +1 -1
- package/dist/components/VTooltip/VTooltip.d.ts +8 -2
- package/dist/components/VTooltip/VTooltip.js.map +1 -1
- package/dist/components/VTooltip/VTooltip.vue_vue_type_script_setup_true_lang.js +45 -43
- package/dist/components/VTooltip/VTooltip.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTreeView/VTreeView.css +2 -0
- package/dist/components/VTreeView/VTreeView.d.ts +112 -0
- package/dist/components/VTreeView/VTreeView.js +9 -0
- package/dist/components/VTreeView/VTreeView.js.map +1 -0
- package/dist/components/VTreeView/VTreeView.vue_vue_type_script_setup_true_lang.js +321 -0
- package/dist/components/VTreeView/VTreeView.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/VTypography/VTypography.d.ts +1 -1
- package/dist/components/VVirtualList/VVirtualList.css +2 -0
- package/dist/components/VVirtualList/VVirtualList.d.ts +78 -0
- package/dist/components/VVirtualList/VVirtualList.js +9 -0
- package/dist/components/VVirtualList/VVirtualList.js.map +1 -0
- package/dist/components/VVirtualList/VVirtualList.vue_vue_type_script_setup_true_lang.js +114 -0
- package/dist/components/VVirtualList/VVirtualList.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/composables/useChoice.d.ts +28 -0
- package/dist/composables/useChoice.js +28 -0
- package/dist/composables/useChoice.js.map +1 -0
- package/dist/composables/useDebouncedSearch.d.ts +17 -0
- package/dist/composables/useDebouncedSearch.js +18 -0
- package/dist/composables/useDebouncedSearch.js.map +1 -0
- package/dist/composables/useEscapeDismiss.d.ts +8 -0
- package/dist/composables/useEscapeDismiss.js +16 -0
- package/dist/composables/useEscapeDismiss.js.map +1 -0
- package/dist/composables/useFieldIds.d.ts +2 -1
- package/dist/composables/useFieldIds.js +7 -6
- package/dist/composables/useFieldIds.js.map +1 -1
- package/dist/composables/useFieldPanel.d.ts +1 -0
- package/dist/composables/useFieldPanel.js +52 -42
- package/dist/composables/useFieldPanel.js.map +1 -1
- package/dist/composables/useFileField.d.ts +1 -3
- package/dist/composables/useFileField.js +48 -50
- package/dist/composables/useFileField.js.map +1 -1
- package/dist/composables/useHotkeyListener.d.ts +17 -0
- package/dist/composables/useHotkeyListener.js +26 -0
- package/dist/composables/useHotkeyListener.js.map +1 -0
- package/dist/composables/useIconClickHandlers.d.ts +2 -10
- package/dist/composables/useIconClickHandlers.js +1 -1
- package/dist/composables/useIconClickHandlers.js.map +1 -1
- package/dist/{components/VCombobox/infiniteScroll.d.ts → composables/useInfiniteScroll.d.ts} +6 -0
- package/dist/{components/VCombobox/infiniteScroll.js → composables/useInfiniteScroll.js} +7 -7
- package/dist/composables/useInfiniteScroll.js.map +1 -0
- package/dist/composables/useListbox.d.ts +132 -0
- package/dist/composables/useListbox.js +227 -0
- package/dist/composables/useListbox.js.map +1 -0
- package/dist/composables/useModalDialog.d.ts +28 -0
- package/dist/composables/useModalDialog.js +60 -0
- package/dist/composables/useModalDialog.js.map +1 -0
- package/dist/composables/useRootAttrs.d.ts +2 -3
- package/dist/composables/useRootAttrs.js.map +1 -1
- package/dist/composables/useVirtualList.d.ts +46 -0
- package/dist/composables/useVirtualList.js +145 -0
- package/dist/composables/useVirtualList.js.map +1 -0
- package/dist/i18n/en.js +50 -0
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/fr.js +50 -0
- package/dist/i18n/fr.js.map +1 -1
- package/dist/i18n/types.d.ts +103 -2
- package/dist/icons.js +45 -37
- package/dist/index.d.ts +49 -3
- package/dist/index.js +80 -56
- package/dist/styles.css +1 -1
- package/dist/tokens/index.d.ts +43 -0
- package/dist/tokens/semantic.d.ts +42 -0
- package/dist/tokens/semantic.js +43 -1
- package/dist/tokens/semantic.js.map +1 -1
- package/dist/tokens/themes/dark.d.ts +1 -0
- package/dist/tokens/themes/dark.js +1 -0
- package/dist/tokens/themes/dark.js.map +1 -1
- package/dist/tokens.json +215 -1
- package/dist/types.d.ts +57 -4
- package/dist/utils/arrowNav.js.map +1 -1
- package/dist/utils/attrs.d.ts +9 -0
- package/dist/utils/attrs.js +14 -0
- package/dist/utils/attrs.js.map +1 -0
- package/dist/utils/date.d.ts +1 -0
- package/dist/utils/date.js +2 -2
- package/dist/utils/date.js.map +1 -1
- package/package.json +1 -1
- package/dist/components/VCombobox/VComboboxGroup.css +0 -2
- package/dist/components/VCombobox/VComboboxGroup.d.ts +0 -17
- package/dist/components/VCombobox/VComboboxGroup.js +0 -9
- package/dist/components/VCombobox/VComboboxGroup.js.map +0 -1
- package/dist/components/VCombobox/VComboboxGroup.vue_vue_type_script_setup_true_lang.js +0 -21
- package/dist/components/VCombobox/VComboboxGroup.vue_vue_type_script_setup_true_lang.js.map +0 -1
- package/dist/components/VCombobox/VComboboxOption.css +0 -2
- package/dist/components/VCombobox/VComboboxOption.js +0 -9
- package/dist/components/VCombobox/VComboboxOption.js.map +0 -1
- package/dist/components/VCombobox/VComboboxOption.vue_vue_type_script_setup_true_lang.js.map +0 -1
- package/dist/components/VCombobox/VComboboxSeparator.css +0 -2
- package/dist/components/VCombobox/VComboboxSeparator.js +0 -9
- package/dist/components/VCombobox/VComboboxSeparator.js.map +0 -1
- package/dist/components/VCombobox/VComboboxSeparator.vue_vue_type_script_setup_true_lang.js.map +0 -1
- package/dist/components/VCombobox/infiniteScroll.js.map +0 -1
- /package/dist/components/{VCombobox/VComboboxSeparator.d.ts → VCheckbox/VCheckMark.d.ts} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VHotkeys.js","names":[],"sources":["../../../src/components/VHotkeys/VHotkeys.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Render platform-specific shortcut glyphs. Detect the platform after mount for SSR; attach\n * keyboard listeners only when listen is enabled.\n */\n\nimport { computed, onActivated, onBeforeUnmount, onDeactivated, onMounted, ref, watch } from 'vue'\n\nimport {\n DEFAULT_PLATFORM,\n capLabel,\n detectPlatform,\n isEditableTarget,\n matchesEvent,\n parseHotkeys,\n resolveKeys,\n} from './platform'\nimport type { HotkeysPlatform } from './platform'\nimport { useMessages } from '../../i18n/state'\n\n/** How a key cap is drawn. */\nexport type HotkeysVariant = 'soft' | 'outline' | 'elevated'\n/** The size of the caps, from the two smallest steps of the control scale. */\nexport type HotkeysSize = 'xs' | 'sm'\n\ninterface HotkeysProps {\n /** The combination, `+`-separated: `mod+k`, `ctrl+shift+p`, `alt+enter`, `esc`. */\n keys: string\n /** How a key cap is drawn: tinted (`soft`), outlined (`outline`), or raised off the page (`elevated`). */\n variant?: HotkeysVariant\n /**\n * Draws the whole combination as a SINGLE key rather than as several: the decoration moves\n * from each cap to the shortcut as a whole, so the separator ends up inside the key instead\n * of between two of them.\n */\n attached?: boolean\n /** The size of the caps, `xs` by default: a shortcut is chrome beside other text. */\n size?: HotkeysSize\n /** Takes 4px off the height, leaving the padding and the text as they are. */\n compact?: boolean\n /**\n * Forces the keyboard's OS instead of detecting it, for a deterministic\n * rendering (stories, tests, a table showing all three) or a host that already\n * knows (Electron, Tauri, a server reading the User-Agent).\n */\n platform?: HotkeysPlatform\n /**\n * What is written between two caps. An empty string gives the macOS convention,\n * where the symbols simply follow one another: ⇧⌘K.\n */\n separator?: string\n /**\n * Actually listens for the combination and reports it. It is off by default: a\n * component whose job is to display a shortcut must not capture the page's keyboard\n * without being asked.\n */\n listen?: boolean\n /**\n * While listening, lets the browser go on doing whatever the combination normally does. Left\n * out, the browser is stopped, which is the entire point of taking over something like ⌘K.\n */\n allowDefault?: boolean\n /**\n * While listening, fires even when the reader is typing in a field. It is off by\n * default, so a shortcut cannot fire in the middle of a sentence.\n */\n allowInInput?: boolean\n /**\n * What screen readers announce, \"Keyboard shortcut: Ctrl + K\" by default, from the\n * design system dictionary.\n */\n label?: string\n}\n\nconst props = withDefaults(defineProps<HotkeysProps>(), {\n variant: 'soft',\n attached: false,\n size: 'xs',\n compact: false,\n platform: undefined,\n separator: '+',\n listen: false,\n allowDefault: false,\n allowInInput: false,\n label: undefined,\n})\n\nconst emit = defineEmits<{\n /** The combination was pressed. It is only ever emitted while `listen` is on. */\n trigger: [event: KeyboardEvent]\n}>()\n\nconst m = useMessages()\n\n// @ssr\n/*\n * The value is held per instance and not at module level. A shared one, having already resolved\n * to macOS, would make a component hydrated later; a Nuxt island, a route loaded on demand;\n * render ⌘ on its very first client pass where the server had written Ctrl.\n */\nconst detected = ref<HotkeysPlatform>(DEFAULT_PLATFORM)\nonMounted(() => {\n detected.value = detectPlatform()\n if (props.listen) attach()\n})\n\nconst platform = computed(() => props.platform ?? detected.value)\nconst tokens = computed(() => parseHotkeys(props.keys))\nconst resolved = computed(() => resolveKeys(tokens.value, platform.value))\n\n// @a11y\n/*\n * On SCREEN the symbol wins, ⌘ being what is engraved on the key; in the ANNOUNCED NAME the\n * word does, because that symbol is either passed over in silence or read out as \"place of\n * interest sign\", depending on the screen reader. Inverting the preference is what lets one\n * table serve both.\n */\nconst caps = computed(() =>\n resolved.value.map(\n (key) => key.glyph ?? (key.word ? m.value.hotkeys[key.word] : capLabel(key.token)),\n ),\n)\nconst spoken = computed(() =>\n resolved.value\n .map((key) => (key.word ? m.value.hotkeys[key.word] : (key.glyph ?? capLabel(key.token))))\n .join(' + '),\n)\nconst resolvedLabel = computed(() => props.label ?? m.value.hotkeys.label(spoken.value))\n\n// @core\n/*\n * It is called `listening` and not `attached`. Every top-level binding of a `<script setup>` is\n * exposed to the template, where it SHADOWS the prop of the same name: called `attached`, this\n * flag would silently be what the template read instead of the prop, and the joined rendering\n * would follow whether a listener happened to be installed.\n */\nlet listening = false\n\nfunction attach() {\n if (listening || typeof document === 'undefined') return\n document.addEventListener('keydown', onKeydown)\n listening = true\n}\n\nfunction detach() {\n if (!listening) return\n document.removeEventListener('keydown', onKeydown)\n listening = false\n}\n\n// @keyboard @core\nfunction onKeydown(event: KeyboardEvent) {\n /* A held-down combination repeats at the system's auto-repeat rate, which would\n reopen the consumer's palette a dozen times a second; only the first press\n counts. */\n if (!props.listen || event.repeat) return\n /* A key another handler has already dealt with (a menu's arrow, a field's Enter) is not\n a shortcut any more. And the Enter that confirms an input method's candidate is the\n end of a word being typed, not a command. */\n if (event.defaultPrevented || event.isComposing) return\n /* The document sees a key typed inside a shadow root as coming from the shadow HOST, a\n plain element: the field itself is the first entry of the composed path. */\n if (!props.allowInInput && isEditableTarget(event.composedPath()[0] ?? event.target)) return\n if (!matchesEvent(event, tokens.value, platform.value)) return\n /*\n * Escape is never cancelled. A cancelled Escape is not turned into a close request, so every\n * open dialog and light-dismiss popover on the page would stop closing on it.\n */\n if (!props.allowDefault && !tokens.value.includes('esc')) event.preventDefault()\n emit('trigger', event)\n}\n\n/* Attaching the listener once and simply returning early inside it would be shorter to\n write, but a documentation page listing fifty shortcuts would then install fifty\n document listeners that do nothing. Following the prop is what keeps that at zero. */\nwatch(\n () => props.listen,\n (on) => (on ? attach() : detach()),\n)\nonBeforeUnmount(detach)\n/* A view kept alive by <KeepAlive> is never unmounted, only put aside: its shortcut must\n stop with it, or a hidden page would go on answering the keyboard. */\nonDeactivated(detach)\nonActivated(() => {\n if (props.listen) attach()\n})\n</script>\n\n<template>\n <kbd\n class=\"v-hotkeys v-control\"\n :data-variant=\"variant\"\n :data-attached=\"attached ? '' : undefined\"\n :data-size=\"size\"\n :data-compact=\"compact ? '' : undefined\"\n :data-platform=\"platform\"\n >\n <span class=\"v-hotkeys-keys\" aria-hidden=\"true\">\n <template v-for=\"(cap, index) in caps\" :key=\"index\">\n <span v-if=\"index > 0 && separator\" class=\"v-hotkeys-separator\">{{ separator }}</span>\n <kbd class=\"v-hotkeys-key\">{{ cap }}</kbd>\n </template>\n </span>\n <span class=\"v-visually-hidden\">{{ resolvedLabel }}</span>\n </kbd>\n</template>\n\n<style>\n@layer vectis.components {\n /*\n * The browser gives a `<kbd>` a monospaced family and a smaller size, and that reduction\n * COMPOUNDS when one `<kbd>` sits inside another, as it does here: the caps would come out at\n * roughly 69% of the surrounding text. Both are reset here and again on the caps themselves,\n * and deleting either line silently miniaturizes the whole component.\n */\n .v-hotkeys {\n display: inline-flex;\n align-items: center;\n /* Centres the content in the cases where the minimum width wins over it: a\n single-character combination drawn as one key. */\n justify-content: center;\n vertical-align: middle;\n font-family: var(--vectis-text-family);\n font-size: var(--control-font-size);\n --hotkeys-pad: var(--control-padding-inline);\n }\n\n /* The size comes from the shared class set on the ROOT: its variables inherit down,\n and it is the CAPS that read the height from them. The scale itself holds five\n steps; the component's type restricts it to the two smallest, a key cap being\n smaller than a control. */\n .v-hotkeys-keys {\n display: inline-flex;\n align-items: center;\n gap: var(--control-gap);\n }\n\n .v-hotkeys-key {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font-family: inherit;\n font-size: inherit;\n font-weight: var(--vectis-text-control-weight);\n line-height: var(--vectis-text-control-leading);\n }\n\n /*\n * Deriving the whole cap from the inherited colour is what makes the component\n * ground-independent, and it is the same reason there is no tone table at all. They set\n * VARIABLES rather than declaring the look straight away, because that look has two possible\n * carriers (see below).\n */\n .v-hotkeys[data-variant='soft'] {\n --hotkeys-bg: color-mix(in oklab, currentcolor, transparent 90%);\n --hotkeys-border: transparent;\n --hotkeys-shadow: none;\n }\n\n .v-hotkeys[data-variant='outline'] {\n --hotkeys-bg: transparent;\n --hotkeys-border: color-mix(in oklab, currentcolor, transparent 70%);\n --hotkeys-shadow: none;\n }\n\n /* Lifted rather than settled into its ground, so the tint is the lighter of the two\n and the shadow does the work. That shadow is the one paint left that is not\n derived: it is a cast rather than a colour, so on a dark ground it simply has\n nothing to fall on, and the tint is what still separates the cap there. */\n .v-hotkeys[data-variant='elevated'] {\n --hotkeys-bg: color-mix(in oklab, currentcolor, transparent 94%);\n --hotkeys-border: transparent;\n --hotkeys-shadow: var(--vectis-shadow-sm);\n }\n\n /*\n * When one key holds the whole combination, its ends take the same breathing room as the gaps\n * inside it, which gives the key a single rhythm. The usual control padding is sized to wrap\n * ONE short label; around three runs of text already spaced from one another, it reads as\n * slack at the edges.\n */\n .v-hotkeys[data-attached] {\n --hotkeys-pad: var(--control-gap);\n }\n\n /*\n * THE key recipe, written once for its two possible carriers: every cap by default, and the\n * whole shortcut alone when it is drawn as a single key; which is exactly what puts the\n * separator inside the key rather than between two of them. Written out twice, the two\n * renderings would drift apart at the first token change.\n */\n .v-hotkeys[data-attached],\n .v-hotkeys:not([data-attached]) .v-hotkeys-key {\n height: var(--control-height);\n /* A minimum equal to the height makes a single-character key read as a square\n rather than as a sliver. */\n min-inline-size: var(--control-height);\n padding-inline: var(--hotkeys-pad);\n border: 1px solid var(--hotkeys-border);\n border-radius: var(--vectis-radius-interactive);\n background: var(--hotkeys-bg);\n box-shadow: var(--hotkeys-shadow);\n }\n\n /* Softened rather than full strength: the separator is punctuation between two\n caps, and at the same weight as them it competes with what it separates. */\n .v-hotkeys-separator {\n color: color-mix(in oklab, currentcolor, transparent 40%);\n }\n\n /*\n * Forced colours flatten the tint and drop the shadow, which is all a soft or an elevated cap\n * is made of. Every variant takes the edge of the outlined one, in the system text colour.\n */\n @media (forced-colors: active) {\n .v-hotkeys[data-variant] {\n --hotkeys-border: CanvasText;\n }\n }\n}\n</style>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"VHotkeys.js","names":[],"sources":["../../../src/components/VHotkeys/VHotkeys.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Render platform-specific shortcut glyphs. Detect the platform after mount for SSR; attach\n * keyboard listeners only when listen is enabled.\n */\n\nimport { computed, onMounted, ref } from 'vue'\n\nimport { DEFAULT_PLATFORM, capLabel, detectPlatform, parseHotkeys, resolveKeys } from './platform'\nimport type { HotkeysPlatform } from './platform'\nimport { useHotkeyListener } from '../../composables/useHotkeyListener'\nimport { useMessages } from '../../i18n/state'\n\n/** How a key cap is drawn. */\nexport type HotkeysVariant = 'soft' | 'outline' | 'elevated'\n/** The size of the caps, from the two smallest steps of the control scale. */\nexport type HotkeysSize = 'xs' | 'sm'\n\ninterface HotkeysProps {\n /** The combination, `+`-separated: `mod+k`, `ctrl+shift+p`, `alt+enter`, `esc`. */\n keys: string\n /** How a key cap is drawn: tinted (`soft`), outlined (`outline`), or raised off the page (`elevated`). */\n variant?: HotkeysVariant\n /**\n * Draws the whole combination as a SINGLE key rather than as several: the decoration moves\n * from each cap to the shortcut as a whole, so the separator ends up inside the key instead\n * of between two of them.\n */\n attached?: boolean\n /** The size of the caps, `xs` by default: a shortcut is chrome beside other text. */\n size?: HotkeysSize\n /** Takes 4px off the height, leaving the padding and the text as they are. */\n compact?: boolean\n /**\n * Forces the keyboard's OS instead of detecting it, for a deterministic\n * rendering (stories, tests, a table showing all three) or a host that already\n * knows (Electron, Tauri, a server reading the User-Agent).\n */\n platform?: HotkeysPlatform\n /**\n * What is written between two caps. An empty string gives the macOS convention,\n * where the symbols simply follow one another: ⇧⌘K.\n */\n separator?: string\n /**\n * Actually listens for the combination and reports it. It is off by default: a\n * component whose job is to display a shortcut must not capture the page's keyboard\n * without being asked.\n */\n listen?: boolean\n /**\n * While listening, lets the browser go on doing whatever the combination normally does. Left\n * out, the browser is stopped, which is the entire point of taking over something like ⌘K.\n */\n allowDefault?: boolean\n /**\n * While listening, fires even when the reader is typing in a field. It is off by\n * default, so a shortcut cannot fire in the middle of a sentence.\n */\n allowInInput?: boolean\n /**\n * What screen readers announce, \"Keyboard shortcut: Ctrl + K\" by default, from the\n * design system dictionary.\n */\n label?: string\n}\n\nconst props = withDefaults(defineProps<HotkeysProps>(), {\n variant: 'soft',\n attached: false,\n size: 'xs',\n compact: false,\n platform: undefined,\n separator: '+',\n listen: false,\n allowDefault: false,\n allowInInput: false,\n label: undefined,\n})\n\nconst emit = defineEmits<{\n /** The combination was pressed. It is only ever emitted while `listen` is on. */\n trigger: [event: KeyboardEvent]\n}>()\n\nconst m = useMessages()\n\n// @ssr\n/*\n * The value is held per instance and not at module level. A shared one, having already resolved\n * to macOS, would make a component hydrated later; a Nuxt island, a route loaded on demand;\n * render ⌘ on its very first client pass where the server had written Ctrl.\n */\nconst detected = ref<HotkeysPlatform>(DEFAULT_PLATFORM)\nonMounted(() => {\n detected.value = detectPlatform()\n})\n\nconst platform = computed(() => props.platform ?? detected.value)\nconst tokens = computed(() => parseHotkeys(props.keys))\nconst resolved = computed(() => resolveKeys(tokens.value, platform.value))\n\n// @a11y\n/*\n * On SCREEN the symbol wins, ⌘ being what is engraved on the key; in the ANNOUNCED NAME the\n * word does, because that symbol is either passed over in silence or read out as \"place of\n * interest sign\", depending on the screen reader. Inverting the preference is what lets one\n * table serve both.\n */\nconst caps = computed(() =>\n resolved.value.map(\n (key) => key.glyph ?? (key.word ? m.value.hotkeys[key.word] : capLabel(key.token)),\n ),\n)\nconst spoken = computed(() =>\n resolved.value\n .map((key) => (key.word ? m.value.hotkeys[key.word] : (key.glyph ?? capLabel(key.token))))\n .join(' + '),\n)\nconst resolvedLabel = computed(() => props.label ?? m.value.hotkeys.label(spoken.value))\n\nuseHotkeyListener({\n tokens: () => tokens.value,\n platform: () => platform.value,\n enabled: () => props.listen,\n allowDefault: () => props.allowDefault,\n allowInInput: () => props.allowInInput,\n onTrigger: (event) => emit('trigger', event),\n})\n</script>\n\n<template>\n <kbd\n class=\"v-hotkeys v-control\"\n :data-variant=\"variant\"\n :data-attached=\"attached ? '' : undefined\"\n :data-size=\"size\"\n :data-compact=\"compact ? '' : undefined\"\n :data-platform=\"platform\"\n >\n <span class=\"v-hotkeys-keys\" aria-hidden=\"true\">\n <template v-for=\"(cap, index) in caps\" :key=\"index\">\n <span v-if=\"index > 0 && separator\" class=\"v-hotkeys-separator\">{{ separator }}</span>\n <kbd class=\"v-hotkeys-key\">{{ cap }}</kbd>\n </template>\n </span>\n <span class=\"v-visually-hidden\">{{ resolvedLabel }}</span>\n </kbd>\n</template>\n\n<style>\n@layer vectis.components {\n /*\n * The browser gives a `<kbd>` a monospaced family and a smaller size, and that reduction\n * COMPOUNDS when one `<kbd>` sits inside another, as it does here: the caps would come out at\n * roughly 69% of the surrounding text. Both are reset here and again on the caps themselves,\n * and deleting either line silently miniaturizes the whole component.\n */\n .v-hotkeys {\n display: inline-flex;\n align-items: center;\n /* Centres the content in the cases where the minimum width wins over it: a\n single-character combination drawn as one key. */\n justify-content: center;\n vertical-align: middle;\n font-family: var(--vectis-text-family);\n font-size: var(--control-font-size);\n }\n\n /* The size comes from the shared class set on the ROOT: its variables inherit down,\n and it is the CAPS that read the height from them. The scale itself holds five\n steps; the component's type restricts it to the two smallest, a key cap being\n smaller than a control. */\n .v-hotkeys-keys {\n display: inline-flex;\n align-items: center;\n gap: var(--control-gap);\n }\n\n .v-hotkeys-key {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font-family: inherit;\n font-size: inherit;\n font-weight: var(--vectis-text-control-weight);\n line-height: var(--vectis-text-control-leading);\n }\n\n /*\n * Deriving the whole cap from the inherited colour is what makes the component\n * ground-independent, and it is the same reason there is no tone table at all. They set\n * VARIABLES rather than declaring the look straight away, because that look has two possible\n * carriers (see below).\n */\n .v-hotkeys[data-variant='soft'] {\n --hotkeys-bg: color-mix(in oklab, currentcolor, transparent 90%);\n --hotkeys-border: transparent;\n --hotkeys-shadow: none;\n }\n\n .v-hotkeys[data-variant='outline'] {\n --hotkeys-bg: transparent;\n --hotkeys-border: color-mix(in oklab, currentcolor, transparent 70%);\n --hotkeys-shadow: none;\n }\n\n /* Lifted rather than settled into its ground, so the tint is the lighter of the two\n and the shadow does the work. That shadow is the one paint left that is not\n derived: it is a cast rather than a colour, so on a dark ground it simply has\n nothing to fall on, and the tint is what still separates the cap there. */\n .v-hotkeys[data-variant='elevated'] {\n --hotkeys-bg: color-mix(in oklab, currentcolor, transparent 94%);\n --hotkeys-border: transparent;\n --hotkeys-shadow: var(--vectis-shadow-sm);\n }\n\n /*\n * THE key recipe, written once for its two possible carriers: every cap by default, and the\n * whole shortcut alone when it is drawn as a single key; which is exactly what puts the\n * separator inside the key rather than between two of them. Written out twice, the two\n * renderings would drift apart at the first token change.\n */\n .v-hotkeys[data-attached],\n .v-hotkeys:not([data-attached]) .v-hotkeys-key {\n height: var(--control-height);\n /* A minimum equal to the height makes a single-character key read as a square\n rather than as a sliver. */\n min-inline-size: var(--control-height);\n padding-inline: var(--control-padding-inline);\n border: 1px solid var(--hotkeys-border);\n border-radius: var(--vectis-radius-interactive);\n background: var(--hotkeys-bg);\n box-shadow: var(--hotkeys-shadow);\n }\n\n /* Softened rather than full strength: the separator is punctuation between two\n caps, and at the same weight as them it competes with what it separates. */\n .v-hotkeys-separator {\n color: color-mix(in oklab, currentcolor, transparent 40%);\n }\n\n /*\n * Forced colours flatten the tint and drop the shadow, which is all a soft or an elevated cap\n * is made of. Every variant takes the edge of the outlined one, in the system text colour.\n */\n @media (forced-colors: active) {\n .v-hotkeys[data-variant] {\n --hotkeys-border: CanvasText;\n }\n }\n}\n</style>\n"],"mappings":""}
|
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
import { useMessages as e } from "../../i18n/state.js";
|
|
2
|
-
import { DEFAULT_PLATFORM as t, capLabel as n, detectPlatform as r,
|
|
3
|
-
import {
|
|
2
|
+
import { DEFAULT_PLATFORM as t, capLabel as n, detectPlatform as r, parseHotkeys as i, resolveKeys as a } from "./platform.js";
|
|
3
|
+
import { useHotkeyListener as o } from "../../composables/useHotkeyListener.js";
|
|
4
|
+
import { Fragment as s, computed as c, createCommentVNode as l, createElementBlock as u, createElementVNode as d, defineComponent as f, onMounted as p, openBlock as m, ref as h, renderList as g, toDisplayString as _ } from "vue";
|
|
4
5
|
//#region src/components/VHotkeys/VHotkeys.vue?vue&type=script&setup=true&lang.ts
|
|
5
|
-
var
|
|
6
|
+
var v = [
|
|
6
7
|
"data-variant",
|
|
7
8
|
"data-attached",
|
|
8
9
|
"data-size",
|
|
9
10
|
"data-compact",
|
|
10
11
|
"data-platform"
|
|
11
|
-
],
|
|
12
|
+
], y = {
|
|
12
13
|
class: "v-hotkeys-keys",
|
|
13
14
|
"aria-hidden": "true"
|
|
14
|
-
},
|
|
15
|
+
}, b = {
|
|
15
16
|
key: 0,
|
|
16
17
|
class: "v-hotkeys-separator"
|
|
17
|
-
},
|
|
18
|
+
}, x = { class: "v-hotkeys-key" }, S = { class: "v-visually-hidden" }, C = /*@__PURE__*/ f({
|
|
18
19
|
__name: "VHotkeys",
|
|
19
20
|
props: {
|
|
20
21
|
keys: {},
|
|
@@ -45,34 +46,30 @@ var C = [
|
|
|
45
46
|
label: { default: void 0 }
|
|
46
47
|
},
|
|
47
48
|
emits: ["trigger"],
|
|
48
|
-
setup(
|
|
49
|
-
let
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
setup(f, { emit: C }) {
|
|
50
|
+
let w = f, T = C, E = e(), D = h(t);
|
|
51
|
+
p(() => {
|
|
52
|
+
D.value = r();
|
|
52
53
|
});
|
|
53
|
-
let
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
return S(() => k.listen, (e) => e ? B() : V()), h(V), g(V), m(() => {
|
|
64
|
-
k.listen && B();
|
|
65
|
-
}), (e, t) => (v(), d("kbd", {
|
|
54
|
+
let O = c(() => w.platform ?? D.value), k = c(() => i(w.keys)), A = c(() => a(k.value, O.value)), j = c(() => A.value.map((e) => e.glyph ?? (e.word ? E.value.hotkeys[e.word] : n(e.token)))), M = c(() => A.value.map((e) => e.word ? E.value.hotkeys[e.word] : e.glyph ?? n(e.token)).join(" + ")), N = c(() => w.label ?? E.value.hotkeys.label(M.value));
|
|
55
|
+
return o({
|
|
56
|
+
tokens: () => k.value,
|
|
57
|
+
platform: () => O.value,
|
|
58
|
+
enabled: () => w.listen,
|
|
59
|
+
allowDefault: () => w.allowDefault,
|
|
60
|
+
allowInInput: () => w.allowInInput,
|
|
61
|
+
onTrigger: (e) => T("trigger", e)
|
|
62
|
+
}), (e, t) => (m(), u("kbd", {
|
|
66
63
|
class: "v-hotkeys v-control",
|
|
67
|
-
"data-variant":
|
|
68
|
-
"data-attached":
|
|
69
|
-
"data-size":
|
|
70
|
-
"data-compact":
|
|
71
|
-
"data-platform":
|
|
72
|
-
}, [
|
|
64
|
+
"data-variant": f.variant,
|
|
65
|
+
"data-attached": f.attached ? "" : void 0,
|
|
66
|
+
"data-size": f.size,
|
|
67
|
+
"data-compact": f.compact ? "" : void 0,
|
|
68
|
+
"data-platform": O.value
|
|
69
|
+
}, [d("span", y, [(m(!0), u(s, null, g(j.value, (e, t) => (m(), u(s, { key: t }, [t > 0 && f.separator ? (m(), u("span", b, _(f.separator), 1)) : l("", !0), d("kbd", x, _(e), 1)], 64))), 128))]), d("span", S, _(N.value), 1)], 8, v));
|
|
73
70
|
}
|
|
74
71
|
});
|
|
75
72
|
//#endregion
|
|
76
|
-
export {
|
|
73
|
+
export { C as default };
|
|
77
74
|
|
|
78
75
|
//# sourceMappingURL=VHotkeys.vue_vue_type_script_setup_true_lang.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VHotkeys.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/VHotkeys/VHotkeys.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Render platform-specific shortcut glyphs. Detect the platform after mount for SSR; attach\n * keyboard listeners only when listen is enabled.\n */\n\nimport { computed, onActivated, onBeforeUnmount, onDeactivated, onMounted, ref, watch } from 'vue'\n\nimport {\n DEFAULT_PLATFORM,\n capLabel,\n detectPlatform,\n isEditableTarget,\n matchesEvent,\n parseHotkeys,\n resolveKeys,\n} from './platform'\nimport type { HotkeysPlatform } from './platform'\nimport { useMessages } from '../../i18n/state'\n\n/** How a key cap is drawn. */\nexport type HotkeysVariant = 'soft' | 'outline' | 'elevated'\n/** The size of the caps, from the two smallest steps of the control scale. */\nexport type HotkeysSize = 'xs' | 'sm'\n\ninterface HotkeysProps {\n /** The combination, `+`-separated: `mod+k`, `ctrl+shift+p`, `alt+enter`, `esc`. */\n keys: string\n /** How a key cap is drawn: tinted (`soft`), outlined (`outline`), or raised off the page (`elevated`). */\n variant?: HotkeysVariant\n /**\n * Draws the whole combination as a SINGLE key rather than as several: the decoration moves\n * from each cap to the shortcut as a whole, so the separator ends up inside the key instead\n * of between two of them.\n */\n attached?: boolean\n /** The size of the caps, `xs` by default: a shortcut is chrome beside other text. */\n size?: HotkeysSize\n /** Takes 4px off the height, leaving the padding and the text as they are. */\n compact?: boolean\n /**\n * Forces the keyboard's OS instead of detecting it, for a deterministic\n * rendering (stories, tests, a table showing all three) or a host that already\n * knows (Electron, Tauri, a server reading the User-Agent).\n */\n platform?: HotkeysPlatform\n /**\n * What is written between two caps. An empty string gives the macOS convention,\n * where the symbols simply follow one another: ⇧⌘K.\n */\n separator?: string\n /**\n * Actually listens for the combination and reports it. It is off by default: a\n * component whose job is to display a shortcut must not capture the page's keyboard\n * without being asked.\n */\n listen?: boolean\n /**\n * While listening, lets the browser go on doing whatever the combination normally does. Left\n * out, the browser is stopped, which is the entire point of taking over something like ⌘K.\n */\n allowDefault?: boolean\n /**\n * While listening, fires even when the reader is typing in a field. It is off by\n * default, so a shortcut cannot fire in the middle of a sentence.\n */\n allowInInput?: boolean\n /**\n * What screen readers announce, \"Keyboard shortcut: Ctrl + K\" by default, from the\n * design system dictionary.\n */\n label?: string\n}\n\nconst props = withDefaults(defineProps<HotkeysProps>(), {\n variant: 'soft',\n attached: false,\n size: 'xs',\n compact: false,\n platform: undefined,\n separator: '+',\n listen: false,\n allowDefault: false,\n allowInInput: false,\n label: undefined,\n})\n\nconst emit = defineEmits<{\n /** The combination was pressed. It is only ever emitted while `listen` is on. */\n trigger: [event: KeyboardEvent]\n}>()\n\nconst m = useMessages()\n\n// @ssr\n/*\n * The value is held per instance and not at module level. A shared one, having already resolved\n * to macOS, would make a component hydrated later; a Nuxt island, a route loaded on demand;\n * render ⌘ on its very first client pass where the server had written Ctrl.\n */\nconst detected = ref<HotkeysPlatform>(DEFAULT_PLATFORM)\nonMounted(() => {\n detected.value = detectPlatform()\n if (props.listen) attach()\n})\n\nconst platform = computed(() => props.platform ?? detected.value)\nconst tokens = computed(() => parseHotkeys(props.keys))\nconst resolved = computed(() => resolveKeys(tokens.value, platform.value))\n\n// @a11y\n/*\n * On SCREEN the symbol wins, ⌘ being what is engraved on the key; in the ANNOUNCED NAME the\n * word does, because that symbol is either passed over in silence or read out as \"place of\n * interest sign\", depending on the screen reader. Inverting the preference is what lets one\n * table serve both.\n */\nconst caps = computed(() =>\n resolved.value.map(\n (key) => key.glyph ?? (key.word ? m.value.hotkeys[key.word] : capLabel(key.token)),\n ),\n)\nconst spoken = computed(() =>\n resolved.value\n .map((key) => (key.word ? m.value.hotkeys[key.word] : (key.glyph ?? capLabel(key.token))))\n .join(' + '),\n)\nconst resolvedLabel = computed(() => props.label ?? m.value.hotkeys.label(spoken.value))\n\n// @core\n/*\n * It is called `listening` and not `attached`. Every top-level binding of a `<script setup>` is\n * exposed to the template, where it SHADOWS the prop of the same name: called `attached`, this\n * flag would silently be what the template read instead of the prop, and the joined rendering\n * would follow whether a listener happened to be installed.\n */\nlet listening = false\n\nfunction attach() {\n if (listening || typeof document === 'undefined') return\n document.addEventListener('keydown', onKeydown)\n listening = true\n}\n\nfunction detach() {\n if (!listening) return\n document.removeEventListener('keydown', onKeydown)\n listening = false\n}\n\n// @keyboard @core\nfunction onKeydown(event: KeyboardEvent) {\n /* A held-down combination repeats at the system's auto-repeat rate, which would\n reopen the consumer's palette a dozen times a second; only the first press\n counts. */\n if (!props.listen || event.repeat) return\n /* A key another handler has already dealt with (a menu's arrow, a field's Enter) is not\n a shortcut any more. And the Enter that confirms an input method's candidate is the\n end of a word being typed, not a command. */\n if (event.defaultPrevented || event.isComposing) return\n /* The document sees a key typed inside a shadow root as coming from the shadow HOST, a\n plain element: the field itself is the first entry of the composed path. */\n if (!props.allowInInput && isEditableTarget(event.composedPath()[0] ?? event.target)) return\n if (!matchesEvent(event, tokens.value, platform.value)) return\n /*\n * Escape is never cancelled. A cancelled Escape is not turned into a close request, so every\n * open dialog and light-dismiss popover on the page would stop closing on it.\n */\n if (!props.allowDefault && !tokens.value.includes('esc')) event.preventDefault()\n emit('trigger', event)\n}\n\n/* Attaching the listener once and simply returning early inside it would be shorter to\n write, but a documentation page listing fifty shortcuts would then install fifty\n document listeners that do nothing. Following the prop is what keeps that at zero. */\nwatch(\n () => props.listen,\n (on) => (on ? attach() : detach()),\n)\nonBeforeUnmount(detach)\n/* A view kept alive by <KeepAlive> is never unmounted, only put aside: its shortcut must\n stop with it, or a hidden page would go on answering the keyboard. */\nonDeactivated(detach)\nonActivated(() => {\n if (props.listen) attach()\n})\n</script>\n\n<template>\n <kbd\n class=\"v-hotkeys v-control\"\n :data-variant=\"variant\"\n :data-attached=\"attached ? '' : undefined\"\n :data-size=\"size\"\n :data-compact=\"compact ? '' : undefined\"\n :data-platform=\"platform\"\n >\n <span class=\"v-hotkeys-keys\" aria-hidden=\"true\">\n <template v-for=\"(cap, index) in caps\" :key=\"index\">\n <span v-if=\"index > 0 && separator\" class=\"v-hotkeys-separator\">{{ separator }}</span>\n <kbd class=\"v-hotkeys-key\">{{ cap }}</kbd>\n </template>\n </span>\n <span class=\"v-visually-hidden\">{{ resolvedLabel }}</span>\n </kbd>\n</template>\n\n<style>\n@layer vectis.components {\n /*\n * The browser gives a `<kbd>` a monospaced family and a smaller size, and that reduction\n * COMPOUNDS when one `<kbd>` sits inside another, as it does here: the caps would come out at\n * roughly 69% of the surrounding text. Both are reset here and again on the caps themselves,\n * and deleting either line silently miniaturizes the whole component.\n */\n .v-hotkeys {\n display: inline-flex;\n align-items: center;\n /* Centres the content in the cases where the minimum width wins over it: a\n single-character combination drawn as one key. */\n justify-content: center;\n vertical-align: middle;\n font-family: var(--vectis-text-family);\n font-size: var(--control-font-size);\n --hotkeys-pad: var(--control-padding-inline);\n }\n\n /* The size comes from the shared class set on the ROOT: its variables inherit down,\n and it is the CAPS that read the height from them. The scale itself holds five\n steps; the component's type restricts it to the two smallest, a key cap being\n smaller than a control. */\n .v-hotkeys-keys {\n display: inline-flex;\n align-items: center;\n gap: var(--control-gap);\n }\n\n .v-hotkeys-key {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font-family: inherit;\n font-size: inherit;\n font-weight: var(--vectis-text-control-weight);\n line-height: var(--vectis-text-control-leading);\n }\n\n /*\n * Deriving the whole cap from the inherited colour is what makes the component\n * ground-independent, and it is the same reason there is no tone table at all. They set\n * VARIABLES rather than declaring the look straight away, because that look has two possible\n * carriers (see below).\n */\n .v-hotkeys[data-variant='soft'] {\n --hotkeys-bg: color-mix(in oklab, currentcolor, transparent 90%);\n --hotkeys-border: transparent;\n --hotkeys-shadow: none;\n }\n\n .v-hotkeys[data-variant='outline'] {\n --hotkeys-bg: transparent;\n --hotkeys-border: color-mix(in oklab, currentcolor, transparent 70%);\n --hotkeys-shadow: none;\n }\n\n /* Lifted rather than settled into its ground, so the tint is the lighter of the two\n and the shadow does the work. That shadow is the one paint left that is not\n derived: it is a cast rather than a colour, so on a dark ground it simply has\n nothing to fall on, and the tint is what still separates the cap there. */\n .v-hotkeys[data-variant='elevated'] {\n --hotkeys-bg: color-mix(in oklab, currentcolor, transparent 94%);\n --hotkeys-border: transparent;\n --hotkeys-shadow: var(--vectis-shadow-sm);\n }\n\n /*\n * When one key holds the whole combination, its ends take the same breathing room as the gaps\n * inside it, which gives the key a single rhythm. The usual control padding is sized to wrap\n * ONE short label; around three runs of text already spaced from one another, it reads as\n * slack at the edges.\n */\n .v-hotkeys[data-attached] {\n --hotkeys-pad: var(--control-gap);\n }\n\n /*\n * THE key recipe, written once for its two possible carriers: every cap by default, and the\n * whole shortcut alone when it is drawn as a single key; which is exactly what puts the\n * separator inside the key rather than between two of them. Written out twice, the two\n * renderings would drift apart at the first token change.\n */\n .v-hotkeys[data-attached],\n .v-hotkeys:not([data-attached]) .v-hotkeys-key {\n height: var(--control-height);\n /* A minimum equal to the height makes a single-character key read as a square\n rather than as a sliver. */\n min-inline-size: var(--control-height);\n padding-inline: var(--hotkeys-pad);\n border: 1px solid var(--hotkeys-border);\n border-radius: var(--vectis-radius-interactive);\n background: var(--hotkeys-bg);\n box-shadow: var(--hotkeys-shadow);\n }\n\n /* Softened rather than full strength: the separator is punctuation between two\n caps, and at the same weight as them it competes with what it separates. */\n .v-hotkeys-separator {\n color: color-mix(in oklab, currentcolor, transparent 40%);\n }\n\n /*\n * Forced colours flatten the tint and drop the shadow, which is all a soft or an elevated cap\n * is made of. Every variant takes the edge of the outlined one, in the system text colour.\n */\n @media (forced-colors: active) {\n .v-hotkeys[data-variant] {\n --hotkeys-border: CanvasText;\n }\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0EA,IAAM,IAAQ,GAaR,IAAO,GAKP,IAAI,EAAY,GAQhB,IAAW,EAAqB,CAAgB;EACtD,QAAgB;GAEd,AADA,EAAS,QAAQ,EAAe,GAC5B,EAAM,UAAQ,EAAO;EAC3B,CAAC;EAED,IAAM,IAAW,QAAe,EAAM,YAAY,EAAS,KAAK,GAC1D,IAAS,QAAe,EAAa,EAAM,IAAI,CAAC,GAChD,IAAW,QAAe,EAAY,EAAO,OAAO,EAAS,KAAK,CAAC,GASnE,IAAO,QACX,EAAS,MAAM,KACZ,MAAQ,EAAI,UAAU,EAAI,OAAO,EAAE,MAAM,QAAQ,EAAI,QAAQ,EAAS,EAAI,KAAK,EAClF,CACF,GACM,IAAS,QACb,EAAS,MACN,KAAK,MAAS,EAAI,OAAO,EAAE,MAAM,QAAQ,EAAI,QAAS,EAAI,SAAS,EAAS,EAAI,KAAK,CAAG,CAAA,CACxF,KAAK,KAAK,CACf,GACM,IAAgB,QAAe,EAAM,SAAS,EAAE,MAAM,QAAQ,MAAM,EAAO,KAAK,CAAC,GASnF,IAAY;EAEhB,SAAS,IAAS;GACZ,KAAa,OAAO,WAAa,QACrC,SAAS,iBAAiB,WAAW,CAAS,GAC9C,IAAY;EACd;EAEA,SAAS,IAAS;GACX,AAEL,OADA,SAAS,oBAAoB,WAAW,CAAS,GACrC;EACd;EAGA,SAAS,EAAU,GAAsB;GAInC,CAAC,EAAM,UAAU,EAAM,UAIvB,EAAM,oBAAoB,EAAM,eAGhC,CAAC,EAAM,gBAAgB,EAAiB,EAAM,aAAa,CAAC,CAAC,MAAM,EAAM,MAAM,KAC9E,EAAa,GAAO,EAAO,OAAO,EAAS,KAAK,MAKjD,CAAC,EAAM,gBAAgB,CAAC,EAAO,MAAM,SAAS,KAAK,KAAG,EAAM,eAAe,GAC/E,EAAK,WAAW,CAAK;EACvB;SAKA,QACQ,EAAM,SACX,MAAQ,IAAK,EAAO,IAAI,EAAO,CAClC,GACA,EAAgB,CAAM,GAGtB,EAAc,CAAM,GACpB,QAAkB;GAChB,AAAI,EAAM,UAAQ,EAAO;EAC3B,CAAC,mBAIC,EAeM,OAAA;GAdJ,OAAM;GACL,gBAAc,EAAA;GACd,iBAAe,EAAA,WAAQ,KAAQ,KAAA;GAC/B,aAAW,EAAA;GACX,gBAAc,EAAA,UAAO,KAAQ,KAAA;GAC7B,iBAAe,EAAA;MAEhB,EAKO,QALP,GAKO,EAAA,EAAA,EAAA,GAJL,EAGW,GAAA,MAAA,EAHsB,EAAA,QAAf,GAAK,wBAAsB,EAAK,GAAA,CACpC,IAAK,KAAQ,EAAA,aAAA,EAAA,GAAzB,EAAsF,QAAtF,GAAsF,EAAnB,EAAA,SAAS,GAAA,CAAA,KAAA,EAAA,IAAA,EAAA,GAC5E,EAA0C,OAA1C,GAA0C,EAAZ,CAAG,GAAA,CAAA,CAAA,GAAA,EAAA,cAGrC,EAA0D,QAA1D,GAA0D,EAAvB,EAAA,KAAa,GAAA,CAAA,CAAA,GAAA,GAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"VHotkeys.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/VHotkeys/VHotkeys.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Render platform-specific shortcut glyphs. Detect the platform after mount for SSR; attach\n * keyboard listeners only when listen is enabled.\n */\n\nimport { computed, onMounted, ref } from 'vue'\n\nimport { DEFAULT_PLATFORM, capLabel, detectPlatform, parseHotkeys, resolveKeys } from './platform'\nimport type { HotkeysPlatform } from './platform'\nimport { useHotkeyListener } from '../../composables/useHotkeyListener'\nimport { useMessages } from '../../i18n/state'\n\n/** How a key cap is drawn. */\nexport type HotkeysVariant = 'soft' | 'outline' | 'elevated'\n/** The size of the caps, from the two smallest steps of the control scale. */\nexport type HotkeysSize = 'xs' | 'sm'\n\ninterface HotkeysProps {\n /** The combination, `+`-separated: `mod+k`, `ctrl+shift+p`, `alt+enter`, `esc`. */\n keys: string\n /** How a key cap is drawn: tinted (`soft`), outlined (`outline`), or raised off the page (`elevated`). */\n variant?: HotkeysVariant\n /**\n * Draws the whole combination as a SINGLE key rather than as several: the decoration moves\n * from each cap to the shortcut as a whole, so the separator ends up inside the key instead\n * of between two of them.\n */\n attached?: boolean\n /** The size of the caps, `xs` by default: a shortcut is chrome beside other text. */\n size?: HotkeysSize\n /** Takes 4px off the height, leaving the padding and the text as they are. */\n compact?: boolean\n /**\n * Forces the keyboard's OS instead of detecting it, for a deterministic\n * rendering (stories, tests, a table showing all three) or a host that already\n * knows (Electron, Tauri, a server reading the User-Agent).\n */\n platform?: HotkeysPlatform\n /**\n * What is written between two caps. An empty string gives the macOS convention,\n * where the symbols simply follow one another: ⇧⌘K.\n */\n separator?: string\n /**\n * Actually listens for the combination and reports it. It is off by default: a\n * component whose job is to display a shortcut must not capture the page's keyboard\n * without being asked.\n */\n listen?: boolean\n /**\n * While listening, lets the browser go on doing whatever the combination normally does. Left\n * out, the browser is stopped, which is the entire point of taking over something like ⌘K.\n */\n allowDefault?: boolean\n /**\n * While listening, fires even when the reader is typing in a field. It is off by\n * default, so a shortcut cannot fire in the middle of a sentence.\n */\n allowInInput?: boolean\n /**\n * What screen readers announce, \"Keyboard shortcut: Ctrl + K\" by default, from the\n * design system dictionary.\n */\n label?: string\n}\n\nconst props = withDefaults(defineProps<HotkeysProps>(), {\n variant: 'soft',\n attached: false,\n size: 'xs',\n compact: false,\n platform: undefined,\n separator: '+',\n listen: false,\n allowDefault: false,\n allowInInput: false,\n label: undefined,\n})\n\nconst emit = defineEmits<{\n /** The combination was pressed. It is only ever emitted while `listen` is on. */\n trigger: [event: KeyboardEvent]\n}>()\n\nconst m = useMessages()\n\n// @ssr\n/*\n * The value is held per instance and not at module level. A shared one, having already resolved\n * to macOS, would make a component hydrated later; a Nuxt island, a route loaded on demand;\n * render ⌘ on its very first client pass where the server had written Ctrl.\n */\nconst detected = ref<HotkeysPlatform>(DEFAULT_PLATFORM)\nonMounted(() => {\n detected.value = detectPlatform()\n})\n\nconst platform = computed(() => props.platform ?? detected.value)\nconst tokens = computed(() => parseHotkeys(props.keys))\nconst resolved = computed(() => resolveKeys(tokens.value, platform.value))\n\n// @a11y\n/*\n * On SCREEN the symbol wins, ⌘ being what is engraved on the key; in the ANNOUNCED NAME the\n * word does, because that symbol is either passed over in silence or read out as \"place of\n * interest sign\", depending on the screen reader. Inverting the preference is what lets one\n * table serve both.\n */\nconst caps = computed(() =>\n resolved.value.map(\n (key) => key.glyph ?? (key.word ? m.value.hotkeys[key.word] : capLabel(key.token)),\n ),\n)\nconst spoken = computed(() =>\n resolved.value\n .map((key) => (key.word ? m.value.hotkeys[key.word] : (key.glyph ?? capLabel(key.token))))\n .join(' + '),\n)\nconst resolvedLabel = computed(() => props.label ?? m.value.hotkeys.label(spoken.value))\n\nuseHotkeyListener({\n tokens: () => tokens.value,\n platform: () => platform.value,\n enabled: () => props.listen,\n allowDefault: () => props.allowDefault,\n allowInInput: () => props.allowInInput,\n onTrigger: (event) => emit('trigger', event),\n})\n</script>\n\n<template>\n <kbd\n class=\"v-hotkeys v-control\"\n :data-variant=\"variant\"\n :data-attached=\"attached ? '' : undefined\"\n :data-size=\"size\"\n :data-compact=\"compact ? '' : undefined\"\n :data-platform=\"platform\"\n >\n <span class=\"v-hotkeys-keys\" aria-hidden=\"true\">\n <template v-for=\"(cap, index) in caps\" :key=\"index\">\n <span v-if=\"index > 0 && separator\" class=\"v-hotkeys-separator\">{{ separator }}</span>\n <kbd class=\"v-hotkeys-key\">{{ cap }}</kbd>\n </template>\n </span>\n <span class=\"v-visually-hidden\">{{ resolvedLabel }}</span>\n </kbd>\n</template>\n\n<style>\n@layer vectis.components {\n /*\n * The browser gives a `<kbd>` a monospaced family and a smaller size, and that reduction\n * COMPOUNDS when one `<kbd>` sits inside another, as it does here: the caps would come out at\n * roughly 69% of the surrounding text. Both are reset here and again on the caps themselves,\n * and deleting either line silently miniaturizes the whole component.\n */\n .v-hotkeys {\n display: inline-flex;\n align-items: center;\n /* Centres the content in the cases where the minimum width wins over it: a\n single-character combination drawn as one key. */\n justify-content: center;\n vertical-align: middle;\n font-family: var(--vectis-text-family);\n font-size: var(--control-font-size);\n }\n\n /* The size comes from the shared class set on the ROOT: its variables inherit down,\n and it is the CAPS that read the height from them. The scale itself holds five\n steps; the component's type restricts it to the two smallest, a key cap being\n smaller than a control. */\n .v-hotkeys-keys {\n display: inline-flex;\n align-items: center;\n gap: var(--control-gap);\n }\n\n .v-hotkeys-key {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font-family: inherit;\n font-size: inherit;\n font-weight: var(--vectis-text-control-weight);\n line-height: var(--vectis-text-control-leading);\n }\n\n /*\n * Deriving the whole cap from the inherited colour is what makes the component\n * ground-independent, and it is the same reason there is no tone table at all. They set\n * VARIABLES rather than declaring the look straight away, because that look has two possible\n * carriers (see below).\n */\n .v-hotkeys[data-variant='soft'] {\n --hotkeys-bg: color-mix(in oklab, currentcolor, transparent 90%);\n --hotkeys-border: transparent;\n --hotkeys-shadow: none;\n }\n\n .v-hotkeys[data-variant='outline'] {\n --hotkeys-bg: transparent;\n --hotkeys-border: color-mix(in oklab, currentcolor, transparent 70%);\n --hotkeys-shadow: none;\n }\n\n /* Lifted rather than settled into its ground, so the tint is the lighter of the two\n and the shadow does the work. That shadow is the one paint left that is not\n derived: it is a cast rather than a colour, so on a dark ground it simply has\n nothing to fall on, and the tint is what still separates the cap there. */\n .v-hotkeys[data-variant='elevated'] {\n --hotkeys-bg: color-mix(in oklab, currentcolor, transparent 94%);\n --hotkeys-border: transparent;\n --hotkeys-shadow: var(--vectis-shadow-sm);\n }\n\n /*\n * THE key recipe, written once for its two possible carriers: every cap by default, and the\n * whole shortcut alone when it is drawn as a single key; which is exactly what puts the\n * separator inside the key rather than between two of them. Written out twice, the two\n * renderings would drift apart at the first token change.\n */\n .v-hotkeys[data-attached],\n .v-hotkeys:not([data-attached]) .v-hotkeys-key {\n height: var(--control-height);\n /* A minimum equal to the height makes a single-character key read as a square\n rather than as a sliver. */\n min-inline-size: var(--control-height);\n padding-inline: var(--control-padding-inline);\n border: 1px solid var(--hotkeys-border);\n border-radius: var(--vectis-radius-interactive);\n background: var(--hotkeys-bg);\n box-shadow: var(--hotkeys-shadow);\n }\n\n /* Softened rather than full strength: the separator is punctuation between two\n caps, and at the same weight as them it competes with what it separates. */\n .v-hotkeys-separator {\n color: color-mix(in oklab, currentcolor, transparent 40%);\n }\n\n /*\n * Forced colours flatten the tint and drop the shadow, which is all a soft or an elevated cap\n * is made of. Every variant takes the edge of the outlined one, in the system text colour.\n */\n @media (forced-colors: active) {\n .v-hotkeys[data-variant] {\n --hotkeys-border: CanvasText;\n }\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmEA,IAAM,IAAQ,GAaR,IAAO,GAKP,IAAI,EAAY,GAQhB,IAAW,EAAqB,CAAgB;EACtD,QAAgB;GACd,EAAS,QAAQ,EAAe;EAClC,CAAC;EAED,IAAM,IAAW,QAAe,EAAM,YAAY,EAAS,KAAK,GAC1D,IAAS,QAAe,EAAa,EAAM,IAAI,CAAC,GAChD,IAAW,QAAe,EAAY,EAAO,OAAO,EAAS,KAAK,CAAC,GASnE,IAAO,QACX,EAAS,MAAM,KACZ,MAAQ,EAAI,UAAU,EAAI,OAAO,EAAE,MAAM,QAAQ,EAAI,QAAQ,EAAS,EAAI,KAAK,EAClF,CACF,GACM,IAAS,QACb,EAAS,MACN,KAAK,MAAS,EAAI,OAAO,EAAE,MAAM,QAAQ,EAAI,QAAS,EAAI,SAAS,EAAS,EAAI,KAAK,CAAG,CAAA,CACxF,KAAK,KAAK,CACf,GACM,IAAgB,QAAe,EAAM,SAAS,EAAE,MAAM,QAAQ,MAAM,EAAO,KAAK,CAAC;SAEvF,EAAkB;GAChB,cAAc,EAAO;GACrB,gBAAgB,EAAS;GACzB,eAAe,EAAM;GACrB,oBAAoB,EAAM;GAC1B,oBAAoB,EAAM;GAC1B,YAAY,MAAU,EAAK,WAAW,CAAK;EAC7C,CAAC,mBAIC,EAeM,OAAA;GAdJ,OAAM;GACL,gBAAc,EAAA;GACd,iBAAe,EAAA,WAAQ,KAAQ,KAAA;GAC/B,aAAW,EAAA;GACX,gBAAc,EAAA,UAAO,KAAQ,KAAA;GAC7B,iBAAe,EAAA;MAEhB,EAKO,QALP,GAKO,EAAA,EAAA,EAAA,GAJL,EAGW,GAAA,MAAA,EAHsB,EAAA,QAAf,GAAK,wBAAsB,EAAK,GAAA,CACpC,IAAK,KAAQ,EAAA,aAAA,EAAA,GAAzB,EAAsF,QAAtF,GAAsF,EAAnB,EAAA,SAAS,GAAA,CAAA,KAAA,EAAA,IAAA,EAAA,GAC5E,EAA0C,OAA1C,GAA0C,EAAZ,CAAG,GAAA,CAAA,CAAA,GAAA,EAAA,cAGrC,EAA0D,QAA1D,GAA0D,EAAvB,EAAA,KAAa,GAAA,CAAA,CAAA,GAAA,GAAA,CAAA"}
|
|
@@ -40,6 +40,8 @@ export declare function capLabel(token: string): string;
|
|
|
40
40
|
* on it and the dictionary entry naming it, where either exists.
|
|
41
41
|
*/
|
|
42
42
|
export declare function resolveKeys(tokens: string[], platform: HotkeysPlatform): ResolvedKey[];
|
|
43
|
+
/** Spells a combination as the `aria-keyshortcuts` attribute does: `Control+K`, `Meta+K`. */
|
|
44
|
+
export declare function ariaKeyshortcuts(tokens: string[], platform: HotkeysPlatform): string;
|
|
43
45
|
/** Whether a key press IS this combination. */
|
|
44
46
|
export declare function matchesEvent(event: KeyboardEvent, tokens: string[], platform: HotkeysPlatform): boolean;
|
|
45
47
|
export declare function isEditableTarget(target: EventTarget | null | undefined): boolean;
|
|
@@ -104,23 +104,42 @@ function p(e, t) {
|
|
|
104
104
|
word: f(e, t)
|
|
105
105
|
}));
|
|
106
106
|
}
|
|
107
|
-
|
|
107
|
+
var m = {
|
|
108
|
+
meta: "Meta",
|
|
109
|
+
ctrl: "Control",
|
|
110
|
+
alt: "Alt",
|
|
111
|
+
shift: "Shift",
|
|
112
|
+
enter: "Enter",
|
|
113
|
+
esc: "Escape",
|
|
114
|
+
space: "Space",
|
|
115
|
+
backspace: "Backspace",
|
|
116
|
+
delete: "Delete",
|
|
117
|
+
tab: "Tab",
|
|
118
|
+
up: "ArrowUp",
|
|
119
|
+
down: "ArrowDown",
|
|
120
|
+
left: "ArrowLeft",
|
|
121
|
+
right: "ArrowRight"
|
|
122
|
+
};
|
|
123
|
+
function h(e, t) {
|
|
124
|
+
return p(e, t).map(({ token: e }) => e === "mod" ? t === "mac" ? "Meta" : "Control" : m[e] ?? d(e)).join("+");
|
|
125
|
+
}
|
|
126
|
+
function g(e) {
|
|
108
127
|
let t = e.key.toLowerCase();
|
|
109
128
|
return r[t] ?? t;
|
|
110
129
|
}
|
|
111
|
-
function
|
|
130
|
+
function _(e, t, n) {
|
|
112
131
|
let r = t.includes("ctrl") || n !== "mac" && t.includes("mod"), i = t.includes("meta") || n === "mac" && t.includes("mod");
|
|
113
132
|
if (e.ctrlKey !== r || e.metaKey !== i || e.altKey !== t.includes("alt") || e.shiftKey !== t.includes("shift")) return !1;
|
|
114
133
|
let a = t.find((e) => !u(e));
|
|
115
|
-
return a !== void 0 &&
|
|
134
|
+
return a !== void 0 && g(e) === a;
|
|
116
135
|
}
|
|
117
|
-
function
|
|
136
|
+
function v(e) {
|
|
118
137
|
if (!(e instanceof HTMLElement)) return !1;
|
|
119
138
|
if (e.isContentEditable) return !0;
|
|
120
139
|
let t = e.tagName;
|
|
121
140
|
return t === "TEXTAREA" || t === "SELECT" || t === "INPUT" && !c.has(e.type);
|
|
122
141
|
}
|
|
123
142
|
//#endregion
|
|
124
|
-
export { t as DEFAULT_PLATFORM, d as capLabel, n as detectPlatform,
|
|
143
|
+
export { t as DEFAULT_PLATFORM, h as ariaKeyshortcuts, d as capLabel, n as detectPlatform, v as isEditableTarget, _ as matchesEvent, l as parseHotkeys, p as resolveKeys };
|
|
125
144
|
|
|
126
145
|
//# sourceMappingURL=platform.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platform.js","names":[],"sources":["../../../src/components/VHotkeys/platform.ts"],"sourcesContent":["// @core\n// Shortcut parsing and platform glyphs are pure; read navigator only after mount to preserve\n// deterministic SSR output.\n/**\n * Detecting the platform must only ever be done once a component is mounted. There is nothing\n * to read it from on a server, and sniffing a request header is not this library's business.\n */\n\nimport { isDev } from '../../utils/env'\n\n/** The system a keyboard belongs to, which decides its symbols and some of its words. */\nexport type HotkeysPlatform = 'mac' | 'windows' | 'linux' | 'other'\n\n/**\n * The dictionary entries naming a key, and only those: the sentence framing the shortcut is not\n * one of them.\n */\nexport type HotkeysWord =\n | 'command'\n | 'ctrl'\n | 'alt'\n | 'shift'\n | 'windows'\n | 'super'\n | 'enter'\n | 'escape'\n | 'space'\n | 'backspace'\n | 'delete'\n | 'tab'\n | 'up'\n | 'down'\n | 'left'\n | 'right'\n\n/** One key of a shortcut, once resolved for a given platform. */\nexport interface ResolvedKey {\n /** Its canonical name, which the matcher compares a key press against. */\n token: string\n /** The symbol engraved on that key, where the system engraves one. */\n glyph?: string\n /**\n * Which dictionary entry names it. Nothing here means the design system does not\n * know this key, and it is printed as it was written.\n */\n word?: HotkeysWord\n}\n\n// @ssr\n/** What a SERVER renders, and therefore what the browser's first render must be as well. */\nexport const DEFAULT_PLATFORM: HotkeysPlatform = 'other'\n\n// @ssr @fallback\n/** Works out which system the keyboard belongs to, from two sources in order. */\nexport function detectPlatform(): HotkeysPlatform {\n if (typeof navigator === 'undefined') return DEFAULT_PLATFORM\n const nav = navigator as Navigator & { userAgentData?: { platform?: string } }\n const source = (nav.userAgentData?.platform || nav.platform || '').toLowerCase()\n /*\n * IPadOS reports itself as a Mac, which is fine here: an attached keyboard carries the same\n * modifier symbols either way.\n */\n if (/mac|iphone|ipad|ipod/.test(source)) return 'mac'\n if (source.includes('win')) return 'windows'\n /* ChromeOS spells itself two different ways depending on which of the two sources\n answered. Both have to be listed, or the branch is dead precisely where it\n matters. */\n if (/linux|android|cros|chrome os/.test(source)) return 'linux'\n return DEFAULT_PLATFORM\n}\n\n/*\n * Serving both is what guarantees the two can never disagree. The `+` key is canonically named\n * `plus`, since `+` is the separator and cannot name itself in the prop; but the browser does\n * report it as `'+'`, hence its presence here.\n */\nconst ALIASES: Record<string, string> = {\n cmd: 'meta',\n command: 'meta',\n win: 'meta',\n windows: 'meta',\n super: 'meta',\n os: 'meta',\n cmdorctrl: 'mod',\n commandorcontrol: 'mod',\n control: 'ctrl',\n option: 'alt',\n opt: 'alt',\n return: 'enter',\n escape: 'esc',\n spacebar: 'space',\n ' ': 'space',\n del: 'delete',\n arrowup: 'up',\n arrowdown: 'down',\n arrowleft: 'left',\n arrowright: 'right',\n '+': 'plus',\n}\n\n/* The symbols engraved on an Apple keyboard, and on no other. Escape and the space bar\n are deliberately absent: the Mac key really does read \"esc\", and the space bar\n carries no symbol at all. */\nconst MAC_GLYPHS: Record<string, string> = {\n mod: '⌘',\n meta: '⌘',\n ctrl: '⌃',\n alt: '⌥',\n shift: '⇧',\n enter: '↵',\n backspace: '⌫',\n delete: '⌦',\n tab: '⇥',\n}\n\n/* Symbols that are the same everywhere: an arrow key is engraved with an arrow on\n every keyboard ever made. */\nconst GLYPHS: Record<string, string> = {\n up: '↑',\n down: '↓',\n left: '←',\n right: '→',\n plus: '+',\n}\n\nconst WORDS: Record<string, HotkeysWord> = {\n ctrl: 'ctrl',\n alt: 'alt',\n shift: 'shift',\n enter: 'enter',\n esc: 'escape',\n space: 'space',\n backspace: 'backspace',\n delete: 'delete',\n tab: 'tab',\n up: 'up',\n down: 'down',\n left: 'left',\n right: 'right',\n}\n\nconst MODIFIERS = new Set(['mod', 'meta', 'ctrl', 'alt', 'shift'])\n\n/**\n * The kinds of field one cannot type prose into. A shortcut stays live over a\n * checkbox, a button or a colour picker: there is no sentence to interrupt there.\n */\nconst NON_TEXT_INPUT_TYPES = new Set([\n 'button',\n 'submit',\n 'reset',\n 'checkbox',\n 'radio',\n 'file',\n 'range',\n 'color',\n 'image',\n])\n\n/**\n * Reads a combination as it was written and returns its keys in canonical form: `'mod+k'` and\n * `' Mod + K '` both give the same two.\n */\nexport function parseHotkeys(keys: string): string[] {\n const tokens = keys\n .split('+')\n .map((token) => token.trim().toLowerCase())\n .filter(Boolean)\n .map((token) => ALIASES[token] ?? token)\n if (isDev) {\n const pressed = tokens.filter((token) => !isModifier(token)).length\n if (tokens.length === 0) {\n console.warn(`[VHotkeys] \\`keys\\` is empty: \"${keys}\" declares no key.`)\n } else if (pressed === 0) {\n /* `ctrl++` reads as Ctrl and the + key, but the second + is a separator: the key\n itself is written `plus`. */\n console.warn(\n `[VHotkeys] \\`keys\\` holds only modifiers: \"${keys}\" never fires. The + key is written \\`plus\\`.`,\n )\n } else if (pressed > 1) {\n /* A shortcut is modifiers and ONE key: `g+h` is not a sequence, and only its first\n key would ever be matched. */\n console.warn(\n `[VHotkeys] \\`keys\\` names more than one key: \"${keys}\" is matched on the first alone.`,\n )\n }\n }\n return tokens\n}\n\n/** Whether this key is one that is held down rather than pressed. */\nfunction isModifier(token: string): boolean {\n return MODIFIERS.has(token)\n}\n\n/**\n * How a key nobody has a word or a symbol for is printed: as it was written, merely\n * capitalized: `k` becomes K, `f5` becomes F5, and a slash stays a slash.\n */\nexport function capLabel(token: string): string {\n return token.charAt(0).toUpperCase() + token.slice(1)\n}\n\nfunction wordOf(token: string, platform: HotkeysPlatform): HotkeysWord | undefined {\n /*\n * The two keys whose name depends on the system. `mod` is the modifier a consumer writes when\n * they mean \"the usual one here\"; Command on a Mac, Ctrl elsewhere; while `meta` names that\n * physical key literally, and it is called something different on each system.\n */\n if (token === 'mod') return platform === 'mac' ? 'command' : 'ctrl'\n if (token === 'meta') {\n if (platform === 'mac') return 'command'\n return platform === 'windows' ? 'windows' : 'super'\n }\n return WORDS[token]\n}\n\n/**\n * Resolves each key of a combination for a given system, attaching the symbol engraved\n * on it and the dictionary entry naming it, where either exists.\n */\nexport function resolveKeys(tokens: string[], platform: HotkeysPlatform): ResolvedKey[] {\n /* A modifier named twice is one key held down: `ctrl+ctrl+k`, or `mod+ctrl+k` away from a\n Mac, where `mod` IS Ctrl. Drawn twice it would read as a chord of two keys. */\n const held = new Set<string>()\n const once = tokens.filter((token) => {\n if (!isModifier(token)) return true\n const key = token === 'mod' ? (platform === 'mac' ? 'meta' : 'ctrl') : token\n if (held.has(key)) return false\n held.add(key)\n return true\n })\n return once.map((token) => ({\n token,\n glyph: (platform === 'mac' ? MAC_GLYPHS[token] : undefined) ?? GLYPHS[token],\n word: wordOf(token, platform),\n }))\n}\n\nfunction normalizeEventKey(event: KeyboardEvent): string {\n const key = event.key.toLowerCase()\n return ALIASES[key] ?? key\n}\n\n/** Whether a key press IS this combination. */\nexport function matchesEvent(\n event: KeyboardEvent,\n tokens: string[],\n platform: HotkeysPlatform,\n): boolean {\n const wantCtrl = tokens.includes('ctrl') || (platform !== 'mac' && tokens.includes('mod'))\n const wantMeta = tokens.includes('meta') || (platform === 'mac' && tokens.includes('mod'))\n if (event.ctrlKey !== wantCtrl) return false\n if (event.metaKey !== wantMeta) return false\n if (event.altKey !== tokens.includes('alt')) return false\n if (event.shiftKey !== tokens.includes('shift')) return false\n const main = tokens.find((token) => !isModifier(token))\n /* A combination made of modifiers alone never fires: there is no key to press. */\n if (main === undefined) return false\n /*\n * Both sides go through the same normalization, which is also what makes a press reported as\n * \"K\"; because Shift was held; match a shortcut written `k`.\n */\n return normalizeEventKey(event) === main\n}\n\n// @keyboard\nexport function isEditableTarget(target: EventTarget | null | undefined): boolean {\n if (!(target instanceof HTMLElement)) return false\n if (target.isContentEditable) return true\n const tag = target.tagName\n if (tag === 'TEXTAREA' || tag === 'SELECT') return true\n if (tag !== 'INPUT') return false\n return !NON_TEXT_INPUT_TYPES.has((target as HTMLInputElement).type)\n}\n"],"mappings":";;AAkDA,IAAa,IAAoC;AAIjD,SAAgB,IAAkC;CAChD,IAAI,OAAO,YAAc,KAAa,OAAO;CAC7C,IAAM,IAAM,WACN,KAAU,EAAI,eAAe,YAAY,EAAI,YAAY,GAAA,CAAI,YAAY;CAW/E,OANI,uBAAuB,KAAK,CAAM,IAAU,QAC5C,EAAO,SAAS,KAAK,IAAU,YAI/B,+BAA+B,KAAK,CAAM,IAAU,UACjD;AACT;AAOA,IAAM,IAAkC;CACtC,KAAK;CACL,SAAS;CACT,KAAK;CACL,SAAS;CACT,OAAO;CACP,IAAI;CACJ,WAAW;CACX,kBAAkB;CAClB,SAAS;CACT,QAAQ;CACR,KAAK;CACL,QAAQ;CACR,QAAQ;CACR,UAAU;CACV,KAAK;CACL,KAAK;CACL,SAAS;CACT,WAAW;CACX,WAAW;CACX,YAAY;CACZ,KAAK;AACP,GAKM,IAAqC;CACzC,KAAK;CACL,MAAM;CACN,MAAM;CACN,KAAK;CACL,OAAO;CACP,OAAO;CACP,WAAW;CACX,QAAQ;CACR,KAAK;AACP,GAIM,IAAiC;CACrC,IAAI;CACJ,MAAM;CACN,MAAM;CACN,OAAO;CACP,MAAM;AACR,GAEM,IAAqC;CACzC,MAAM;CACN,KAAK;CACL,OAAO;CACP,OAAO;CACP,KAAK;CACL,OAAO;CACP,WAAW;CACX,QAAQ;CACR,KAAK;CACL,IAAI;CACJ,MAAM;CACN,MAAM;CACN,OAAO;AACT,GAEM,oBAAY,IAAI,IAAI;CAAC;CAAO;CAAQ;CAAQ;CAAO;AAAO,CAAC,GAM3D,oBAAuB,IAAI,IAAI;CACnC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAMD,SAAgB,EAAa,GAAwB;CACnD,IAAM,IAAS,EACZ,MAAM,GAAG,CAAC,CACV,KAAK,MAAU,EAAM,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAC1C,OAAO,OAAO,CAAC,CACf,KAAK,MAAU,EAAQ,MAAU,CAAK;CACzC,IAAI,GAAO;EACT,IAAM,IAAU,EAAO,QAAQ,MAAU,CAAC,EAAW,CAAK,CAAC,CAAC,CAAC;EAC7D,AAAI,EAAO,WAAW,IACpB,QAAQ,KAAK,kCAAkC,EAAK,mBAAmB,IAC9D,MAAY,IAGrB,QAAQ,KACN,8CAA8C,EAAK,8CACrD,IACS,IAAU,KAGnB,QAAQ,KACN,iDAAiD,EAAK,iCACxD;CAEJ;CACA,OAAO;AACT;AAGA,SAAS,EAAW,GAAwB;CAC1C,OAAO,EAAU,IAAI,CAAK;AAC5B;AAMA,SAAgB,EAAS,GAAuB;CAC9C,OAAO,EAAM,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,EAAM,MAAM,CAAC;AACtD;AAEA,SAAS,EAAO,GAAe,GAAoD;CAWjF,OALI,MAAU,QAAc,MAAa,QAAQ,YAAY,SACzD,MAAU,SACR,MAAa,QAAc,YACxB,MAAa,YAAY,YAAY,UAEvC,EAAM;AACf;AAMA,SAAgB,EAAY,GAAkB,GAA0C;CAGtF,IAAM,oBAAO,IAAI,IAAY;CAQ7B,OAPa,EAAO,QAAQ,MAAU;EACpC,IAAI,CAAC,EAAW,CAAK,GAAG,OAAO;EAC/B,IAAM,IAAM,MAAU,QAAS,MAAa,QAAQ,SAAS,SAAU;EAGvE,OAFI,EAAK,IAAI,CAAG,IAAU,MAC1B,EAAK,IAAI,CAAG,GACL;CACT,CACO,CAAA,CAAK,KAAK,OAAW;EAC1B;EACA,QAAQ,MAAa,QAAQ,EAAW,KAAS,KAAA,MAAc,EAAO;EACtE,MAAM,EAAO,GAAO,CAAQ;CAC9B,EAAE;AACJ;AAEA,SAAS,EAAkB,GAA8B;CACvD,IAAM,IAAM,EAAM,IAAI,YAAY;CAClC,OAAO,EAAQ,MAAQ;AACzB;AAGA,SAAgB,EACd,GACA,GACA,GACS;CACT,IAAM,IAAW,EAAO,SAAS,MAAM,KAAM,MAAa,SAAS,EAAO,SAAS,KAAK,GAClF,IAAW,EAAO,SAAS,MAAM,KAAM,MAAa,SAAS,EAAO,SAAS,KAAK;CAIxF,IAHI,EAAM,YAAY,KAClB,EAAM,YAAY,KAClB,EAAM,WAAW,EAAO,SAAS,KAAK,KACtC,EAAM,aAAa,EAAO,SAAS,OAAO,GAAG,OAAO;CACxD,IAAM,IAAO,EAAO,MAAM,MAAU,CAAC,EAAW,CAAK,CAAC;CAOtD,OALI,MAAS,KAAA,KAKN,EAAkB,CAAK,MAAM;AACtC;AAGA,SAAgB,EAAiB,GAAiD;CAChF,IAAI,EAAE,aAAkB,cAAc,OAAO;CAC7C,IAAI,EAAO,mBAAmB,OAAO;CACrC,IAAM,IAAM,EAAO;CAGnB,OAFI,MAAQ,cAAc,MAAQ,YAC9B,MAAQ,WACL,CAAC,EAAqB,IAAK,EAA4B,IAAI;AACpE"}
|
|
1
|
+
{"version":3,"file":"platform.js","names":[],"sources":["../../../src/components/VHotkeys/platform.ts"],"sourcesContent":["// @core\n// Shortcut parsing and platform glyphs are pure; read navigator only after mount to preserve\n// deterministic SSR output.\n/**\n * Detecting the platform must only ever be done once a component is mounted. There is nothing\n * to read it from on a server, and sniffing a request header is not this library's business.\n */\n\nimport { isDev } from '../../utils/env'\n\n/** The system a keyboard belongs to, which decides its symbols and some of its words. */\nexport type HotkeysPlatform = 'mac' | 'windows' | 'linux' | 'other'\n\n/**\n * The dictionary entries naming a key, and only those: the sentence framing the shortcut is not\n * one of them.\n */\nexport type HotkeysWord =\n | 'command'\n | 'ctrl'\n | 'alt'\n | 'shift'\n | 'windows'\n | 'super'\n | 'enter'\n | 'escape'\n | 'space'\n | 'backspace'\n | 'delete'\n | 'tab'\n | 'up'\n | 'down'\n | 'left'\n | 'right'\n\n/** One key of a shortcut, once resolved for a given platform. */\nexport interface ResolvedKey {\n /** Its canonical name, which the matcher compares a key press against. */\n token: string\n /** The symbol engraved on that key, where the system engraves one. */\n glyph?: string\n /**\n * Which dictionary entry names it. Nothing here means the design system does not\n * know this key, and it is printed as it was written.\n */\n word?: HotkeysWord\n}\n\n// @ssr\n/** What a SERVER renders, and therefore what the browser's first render must be as well. */\nexport const DEFAULT_PLATFORM: HotkeysPlatform = 'other'\n\n// @ssr @fallback\n/** Works out which system the keyboard belongs to, from two sources in order. */\nexport function detectPlatform(): HotkeysPlatform {\n if (typeof navigator === 'undefined') return DEFAULT_PLATFORM\n const nav = navigator as Navigator & { userAgentData?: { platform?: string } }\n const source = (nav.userAgentData?.platform || nav.platform || '').toLowerCase()\n /*\n * IPadOS reports itself as a Mac, which is fine here: an attached keyboard carries the same\n * modifier symbols either way.\n */\n if (/mac|iphone|ipad|ipod/.test(source)) return 'mac'\n if (source.includes('win')) return 'windows'\n /* ChromeOS spells itself two different ways depending on which of the two sources\n answered. Both have to be listed, or the branch is dead precisely where it\n matters. */\n if (/linux|android|cros|chrome os/.test(source)) return 'linux'\n return DEFAULT_PLATFORM\n}\n\n/*\n * Serving both is what guarantees the two can never disagree. The `+` key is canonically named\n * `plus`, since `+` is the separator and cannot name itself in the prop; but the browser does\n * report it as `'+'`, hence its presence here.\n */\nconst ALIASES: Record<string, string> = {\n cmd: 'meta',\n command: 'meta',\n win: 'meta',\n windows: 'meta',\n super: 'meta',\n os: 'meta',\n cmdorctrl: 'mod',\n commandorcontrol: 'mod',\n control: 'ctrl',\n option: 'alt',\n opt: 'alt',\n return: 'enter',\n escape: 'esc',\n spacebar: 'space',\n ' ': 'space',\n del: 'delete',\n arrowup: 'up',\n arrowdown: 'down',\n arrowleft: 'left',\n arrowright: 'right',\n '+': 'plus',\n}\n\n/* The symbols engraved on an Apple keyboard, and on no other. Escape and the space bar\n are deliberately absent: the Mac key really does read \"esc\", and the space bar\n carries no symbol at all. */\nconst MAC_GLYPHS: Record<string, string> = {\n mod: '⌘',\n meta: '⌘',\n ctrl: '⌃',\n alt: '⌥',\n shift: '⇧',\n enter: '↵',\n backspace: '⌫',\n delete: '⌦',\n tab: '⇥',\n}\n\n/* Symbols that are the same everywhere: an arrow key is engraved with an arrow on\n every keyboard ever made. */\nconst GLYPHS: Record<string, string> = {\n up: '↑',\n down: '↓',\n left: '←',\n right: '→',\n plus: '+',\n}\n\nconst WORDS: Record<string, HotkeysWord> = {\n ctrl: 'ctrl',\n alt: 'alt',\n shift: 'shift',\n enter: 'enter',\n esc: 'escape',\n space: 'space',\n backspace: 'backspace',\n delete: 'delete',\n tab: 'tab',\n up: 'up',\n down: 'down',\n left: 'left',\n right: 'right',\n}\n\nconst MODIFIERS = new Set(['mod', 'meta', 'ctrl', 'alt', 'shift'])\n\n/**\n * The kinds of field one cannot type prose into. A shortcut stays live over a\n * checkbox, a button or a colour picker: there is no sentence to interrupt there.\n */\nconst NON_TEXT_INPUT_TYPES = new Set([\n 'button',\n 'submit',\n 'reset',\n 'checkbox',\n 'radio',\n 'file',\n 'range',\n 'color',\n 'image',\n])\n\n/**\n * Reads a combination as it was written and returns its keys in canonical form: `'mod+k'` and\n * `' Mod + K '` both give the same two.\n */\nexport function parseHotkeys(keys: string): string[] {\n const tokens = keys\n .split('+')\n .map((token) => token.trim().toLowerCase())\n .filter(Boolean)\n .map((token) => ALIASES[token] ?? token)\n if (isDev) {\n const pressed = tokens.filter((token) => !isModifier(token)).length\n if (tokens.length === 0) {\n console.warn(`[VHotkeys] \\`keys\\` is empty: \"${keys}\" declares no key.`)\n } else if (pressed === 0) {\n /* `ctrl++` reads as Ctrl and the + key, but the second + is a separator: the key\n itself is written `plus`. */\n console.warn(\n `[VHotkeys] \\`keys\\` holds only modifiers: \"${keys}\" never fires. The + key is written \\`plus\\`.`,\n )\n } else if (pressed > 1) {\n /* A shortcut is modifiers and ONE key: `g+h` is not a sequence, and only its first\n key would ever be matched. */\n console.warn(\n `[VHotkeys] \\`keys\\` names more than one key: \"${keys}\" is matched on the first alone.`,\n )\n }\n }\n return tokens\n}\n\n/** Whether this key is one that is held down rather than pressed. */\nfunction isModifier(token: string): boolean {\n return MODIFIERS.has(token)\n}\n\n/**\n * How a key nobody has a word or a symbol for is printed: as it was written, merely\n * capitalized: `k` becomes K, `f5` becomes F5, and a slash stays a slash.\n */\nexport function capLabel(token: string): string {\n return token.charAt(0).toUpperCase() + token.slice(1)\n}\n\nfunction wordOf(token: string, platform: HotkeysPlatform): HotkeysWord | undefined {\n /*\n * The two keys whose name depends on the system. `mod` is the modifier a consumer writes when\n * they mean \"the usual one here\"; Command on a Mac, Ctrl elsewhere; while `meta` names that\n * physical key literally, and it is called something different on each system.\n */\n if (token === 'mod') return platform === 'mac' ? 'command' : 'ctrl'\n if (token === 'meta') {\n if (platform === 'mac') return 'command'\n return platform === 'windows' ? 'windows' : 'super'\n }\n return WORDS[token]\n}\n\n/**\n * Resolves each key of a combination for a given system, attaching the symbol engraved\n * on it and the dictionary entry naming it, where either exists.\n */\nexport function resolveKeys(tokens: string[], platform: HotkeysPlatform): ResolvedKey[] {\n /* A modifier named twice is one key held down: `ctrl+ctrl+k`, or `mod+ctrl+k` away from a\n Mac, where `mod` IS Ctrl. Drawn twice it would read as a chord of two keys. */\n const held = new Set<string>()\n const once = tokens.filter((token) => {\n if (!isModifier(token)) return true\n const key = token === 'mod' ? (platform === 'mac' ? 'meta' : 'ctrl') : token\n if (held.has(key)) return false\n held.add(key)\n return true\n })\n return once.map((token) => ({\n token,\n glyph: (platform === 'mac' ? MAC_GLYPHS[token] : undefined) ?? GLYPHS[token],\n word: wordOf(token, platform),\n }))\n}\n\n/* The key names `aria-keyshortcuts` expects, which are those of `KeyboardEvent.key`. */\nconst ARIA_KEYS: Record<string, string> = {\n meta: 'Meta',\n ctrl: 'Control',\n alt: 'Alt',\n shift: 'Shift',\n enter: 'Enter',\n esc: 'Escape',\n space: 'Space',\n backspace: 'Backspace',\n delete: 'Delete',\n tab: 'Tab',\n up: 'ArrowUp',\n down: 'ArrowDown',\n left: 'ArrowLeft',\n right: 'ArrowRight',\n}\n\n// @a11y\n/** Spells a combination as the `aria-keyshortcuts` attribute does: `Control+K`, `Meta+K`. */\nexport function ariaKeyshortcuts(tokens: string[], platform: HotkeysPlatform): string {\n return resolveKeys(tokens, platform)\n .map(({ token }) =>\n token === 'mod'\n ? platform === 'mac'\n ? 'Meta'\n : 'Control'\n : (ARIA_KEYS[token] ?? capLabel(token)),\n )\n .join('+')\n}\n\nfunction normalizeEventKey(event: KeyboardEvent): string {\n const key = event.key.toLowerCase()\n return ALIASES[key] ?? key\n}\n\n/** Whether a key press IS this combination. */\nexport function matchesEvent(\n event: KeyboardEvent,\n tokens: string[],\n platform: HotkeysPlatform,\n): boolean {\n const wantCtrl = tokens.includes('ctrl') || (platform !== 'mac' && tokens.includes('mod'))\n const wantMeta = tokens.includes('meta') || (platform === 'mac' && tokens.includes('mod'))\n if (event.ctrlKey !== wantCtrl) return false\n if (event.metaKey !== wantMeta) return false\n if (event.altKey !== tokens.includes('alt')) return false\n if (event.shiftKey !== tokens.includes('shift')) return false\n const main = tokens.find((token) => !isModifier(token))\n /* A combination made of modifiers alone never fires: there is no key to press. */\n if (main === undefined) return false\n /*\n * Both sides go through the same normalization, which is also what makes a press reported as\n * \"K\"; because Shift was held; match a shortcut written `k`.\n */\n return normalizeEventKey(event) === main\n}\n\n// @keyboard\nexport function isEditableTarget(target: EventTarget | null | undefined): boolean {\n if (!(target instanceof HTMLElement)) return false\n if (target.isContentEditable) return true\n const tag = target.tagName\n if (tag === 'TEXTAREA' || tag === 'SELECT') return true\n if (tag !== 'INPUT') return false\n return !NON_TEXT_INPUT_TYPES.has((target as HTMLInputElement).type)\n}\n"],"mappings":";;AAkDA,IAAa,IAAoC;AAIjD,SAAgB,IAAkC;CAChD,IAAI,OAAO,YAAc,KAAa,OAAO;CAC7C,IAAM,IAAM,WACN,KAAU,EAAI,eAAe,YAAY,EAAI,YAAY,GAAA,CAAI,YAAY;CAW/E,OANI,uBAAuB,KAAK,CAAM,IAAU,QAC5C,EAAO,SAAS,KAAK,IAAU,YAI/B,+BAA+B,KAAK,CAAM,IAAU,UACjD;AACT;AAOA,IAAM,IAAkC;CACtC,KAAK;CACL,SAAS;CACT,KAAK;CACL,SAAS;CACT,OAAO;CACP,IAAI;CACJ,WAAW;CACX,kBAAkB;CAClB,SAAS;CACT,QAAQ;CACR,KAAK;CACL,QAAQ;CACR,QAAQ;CACR,UAAU;CACV,KAAK;CACL,KAAK;CACL,SAAS;CACT,WAAW;CACX,WAAW;CACX,YAAY;CACZ,KAAK;AACP,GAKM,IAAqC;CACzC,KAAK;CACL,MAAM;CACN,MAAM;CACN,KAAK;CACL,OAAO;CACP,OAAO;CACP,WAAW;CACX,QAAQ;CACR,KAAK;AACP,GAIM,IAAiC;CACrC,IAAI;CACJ,MAAM;CACN,MAAM;CACN,OAAO;CACP,MAAM;AACR,GAEM,IAAqC;CACzC,MAAM;CACN,KAAK;CACL,OAAO;CACP,OAAO;CACP,KAAK;CACL,OAAO;CACP,WAAW;CACX,QAAQ;CACR,KAAK;CACL,IAAI;CACJ,MAAM;CACN,MAAM;CACN,OAAO;AACT,GAEM,oBAAY,IAAI,IAAI;CAAC;CAAO;CAAQ;CAAQ;CAAO;AAAO,CAAC,GAM3D,oBAAuB,IAAI,IAAI;CACnC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAMD,SAAgB,EAAa,GAAwB;CACnD,IAAM,IAAS,EACZ,MAAM,GAAG,CAAC,CACV,KAAK,MAAU,EAAM,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAC1C,OAAO,OAAO,CAAC,CACf,KAAK,MAAU,EAAQ,MAAU,CAAK;CACzC,IAAI,GAAO;EACT,IAAM,IAAU,EAAO,QAAQ,MAAU,CAAC,EAAW,CAAK,CAAC,CAAC,CAAC;EAC7D,AAAI,EAAO,WAAW,IACpB,QAAQ,KAAK,kCAAkC,EAAK,mBAAmB,IAC9D,MAAY,IAGrB,QAAQ,KACN,8CAA8C,EAAK,8CACrD,IACS,IAAU,KAGnB,QAAQ,KACN,iDAAiD,EAAK,iCACxD;CAEJ;CACA,OAAO;AACT;AAGA,SAAS,EAAW,GAAwB;CAC1C,OAAO,EAAU,IAAI,CAAK;AAC5B;AAMA,SAAgB,EAAS,GAAuB;CAC9C,OAAO,EAAM,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,EAAM,MAAM,CAAC;AACtD;AAEA,SAAS,EAAO,GAAe,GAAoD;CAWjF,OALI,MAAU,QAAc,MAAa,QAAQ,YAAY,SACzD,MAAU,SACR,MAAa,QAAc,YACxB,MAAa,YAAY,YAAY,UAEvC,EAAM;AACf;AAMA,SAAgB,EAAY,GAAkB,GAA0C;CAGtF,IAAM,oBAAO,IAAI,IAAY;CAQ7B,OAPa,EAAO,QAAQ,MAAU;EACpC,IAAI,CAAC,EAAW,CAAK,GAAG,OAAO;EAC/B,IAAM,IAAM,MAAU,QAAS,MAAa,QAAQ,SAAS,SAAU;EAGvE,OAFI,EAAK,IAAI,CAAG,IAAU,MAC1B,EAAK,IAAI,CAAG,GACL;CACT,CACO,CAAA,CAAK,KAAK,OAAW;EAC1B;EACA,QAAQ,MAAa,QAAQ,EAAW,KAAS,KAAA,MAAc,EAAO;EACtE,MAAM,EAAO,GAAO,CAAQ;CAC9B,EAAE;AACJ;AAGA,IAAM,IAAoC;CACxC,MAAM;CACN,MAAM;CACN,KAAK;CACL,OAAO;CACP,OAAO;CACP,KAAK;CACL,OAAO;CACP,WAAW;CACX,QAAQ;CACR,KAAK;CACL,IAAI;CACJ,MAAM;CACN,MAAM;CACN,OAAO;AACT;AAIA,SAAgB,EAAiB,GAAkB,GAAmC;CACpF,OAAO,EAAY,GAAQ,CAAQ,CAAC,CACjC,KAAK,EAAE,eACN,MAAU,QACN,MAAa,QACX,SACA,YACD,EAAU,MAAU,EAAS,CAAK,CACzC,CAAC,CACA,KAAK,GAAG;AACb;AAEA,SAAS,EAAkB,GAA8B;CACvD,IAAM,IAAM,EAAM,IAAI,YAAY;CAClC,OAAO,EAAQ,MAAQ;AACzB;AAGA,SAAgB,EACd,GACA,GACA,GACS;CACT,IAAM,IAAW,EAAO,SAAS,MAAM,KAAM,MAAa,SAAS,EAAO,SAAS,KAAK,GAClF,IAAW,EAAO,SAAS,MAAM,KAAM,MAAa,SAAS,EAAO,SAAS,KAAK;CAIxF,IAHI,EAAM,YAAY,KAClB,EAAM,YAAY,KAClB,EAAM,WAAW,EAAO,SAAS,KAAK,KACtC,EAAM,aAAa,EAAO,SAAS,OAAO,GAAG,OAAO;CACxD,IAAM,IAAO,EAAO,MAAM,MAAU,CAAC,EAAW,CAAK,CAAC;CAOtD,OALI,MAAS,KAAA,KAKN,EAAkB,CAAK,MAAM;AACtC;AAGA,SAAgB,EAAiB,GAAiD;CAChF,IAAI,EAAE,aAAkB,cAAc,OAAO;CAC7C,IAAI,EAAO,mBAAmB,OAAO;CACrC,IAAM,IAAM,EAAO;CAGnB,OAFI,MAAQ,cAAc,MAAQ,YAC9B,MAAQ,WACL,CAAC,EAAqB,IAAK,EAA4B,IAAI;AACpE"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
@layer vectis.reset, vectis.tokens, vectis.components, vectis.utilities;
|
|
2
|
+
@layer vectis.components{.v-hover-card{anchor-name:--hover-card-anchor;anchor-scope:--hover-card-anchor;align-items:center;display:inline-flex}.v-panel.v-hover-card-panel{position-anchor:--hover-card-anchor;gap:var(--vectis-space-2);padding:var(--vectis-space-4);inline-size:max-content;max-inline-size:min(var(--vectis-control-size-hover-card-max), calc(100dvi - var(--vectis-space-8)));font-size:var(--vectis-text-body-md-size);font-weight:var(--vectis-text-body-md-weight);line-height:var(--vectis-text-body-md-leading);text-align:start;white-space:normal}}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/** Which side of the trigger the card appears on. */
|
|
2
|
+
export type HoverCardPlacement = 'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'left' | 'left-start' | 'left-end' | 'right' | 'right-start' | 'right-end';
|
|
3
|
+
/** What the trigger has to carry: the link to the card holding its details. */
|
|
4
|
+
export type HoverCardTriggerProps = {
|
|
5
|
+
'aria-details': string;
|
|
6
|
+
};
|
|
7
|
+
interface HoverCardProps {
|
|
8
|
+
/**
|
|
9
|
+
* Which side of the trigger the card appears on. The browser flips it to the opposite side by
|
|
10
|
+
* itself when there is not enough room.
|
|
11
|
+
*/
|
|
12
|
+
placement?: HoverCardPlacement;
|
|
13
|
+
/**
|
|
14
|
+
* How long the pointer or the keyboard focus must rest on the trigger before the card opens,
|
|
15
|
+
* in milliseconds.
|
|
16
|
+
*/
|
|
17
|
+
openDelay?: number;
|
|
18
|
+
/**
|
|
19
|
+
* How long the card stays once the pointer has left both the trigger and the card, in
|
|
20
|
+
* milliseconds. It is the time to cross the gap between them.
|
|
21
|
+
*/
|
|
22
|
+
closeDelay?: number;
|
|
23
|
+
}
|
|
24
|
+
type __VLS_Props = HoverCardProps;
|
|
25
|
+
type __VLS_Slots = {
|
|
26
|
+
/** The trigger, usually a link. Bind the `triggerProps` it receives onto it. */
|
|
27
|
+
default(props: {
|
|
28
|
+
triggerProps: HoverCardTriggerProps;
|
|
29
|
+
}): unknown;
|
|
30
|
+
/** What the card contains. It may hold links and buttons, and is rendered on first opening. */
|
|
31
|
+
content?(): unknown;
|
|
32
|
+
};
|
|
33
|
+
declare function hide(): void;
|
|
34
|
+
type __VLS_ModelProps = {
|
|
35
|
+
/** Whether the card is showing. Setting it opens or closes the card without any delay. */
|
|
36
|
+
'open'?: boolean;
|
|
37
|
+
};
|
|
38
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
39
|
+
declare const __VLS_base: import('vue').DefineComponent<__VLS_PublicProps, {
|
|
40
|
+
/** Opens the card at once, without the delay. */
|
|
41
|
+
show: () => void;
|
|
42
|
+
/** Closes the card, handing a focus inside it back to the trigger. */
|
|
43
|
+
close: typeof hide;
|
|
44
|
+
/** The card element. */
|
|
45
|
+
el: import('vue').Ref<HTMLElement | null, HTMLElement | null>;
|
|
46
|
+
}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
47
|
+
"update:open": (value: boolean) => any;
|
|
48
|
+
}, string, import('vue').PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
49
|
+
"onUpdate:open"?: ((value: boolean) => any) | undefined;
|
|
50
|
+
}>, {
|
|
51
|
+
placement: HoverCardPlacement;
|
|
52
|
+
openDelay: number;
|
|
53
|
+
closeDelay: number;
|
|
54
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
55
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
56
|
+
declare const _default: typeof __VLS_export;
|
|
57
|
+
export default _default;
|
|
58
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
59
|
+
new (): {
|
|
60
|
+
$slots: S;
|
|
61
|
+
};
|
|
62
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import './VHoverCard.css';
|
|
2
|
+
import e from "./VHoverCard.vue_vue_type_script_setup_true_lang.js";
|
|
3
|
+
/* empty css */
|
|
4
|
+
//#region src/components/VHoverCard/VHoverCard.vue
|
|
5
|
+
var t = e;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { t as default };
|
|
8
|
+
|
|
9
|
+
//# sourceMappingURL=VHoverCard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VHoverCard.js","names":[],"sources":["../../../src/components/VHoverCard/VHoverCard.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * A manual popover driven by hover and keyboard focus: no stable HTML primitive opens a panel\n * with a delay, as `popover=\"hint\"` and interest invokers are missing at the browser floor.\n * Manual mode also leaves any open menu or popover untouched.\n */\n\nimport { ref, useId } from 'vue'\n\nimport { useEscapeDismiss } from '../../composables/useEscapeDismiss'\nimport { usePopover, usePopoverModel } from '../../composables/usePopover'\nimport { useTimer } from '../../composables/useTimer'\nimport { isKeyboardFocus } from '../../utils/focus'\n\n/** Which side of the trigger the card appears on. */\nexport type HoverCardPlacement =\n | 'top'\n | 'top-start'\n | 'top-end'\n | 'bottom'\n | 'bottom-start'\n | 'bottom-end'\n | 'left'\n | 'left-start'\n | 'left-end'\n | 'right'\n | 'right-start'\n | 'right-end'\n\n/** What the trigger has to carry: the link to the card holding its details. */\nexport type HoverCardTriggerProps = {\n 'aria-details': string\n}\n\ninterface HoverCardProps {\n /**\n * Which side of the trigger the card appears on. The browser flips it to the opposite side by\n * itself when there is not enough room.\n */\n placement?: HoverCardPlacement\n /**\n * How long the pointer or the keyboard focus must rest on the trigger before the card opens,\n * in milliseconds.\n */\n openDelay?: number\n /**\n * How long the card stays once the pointer has left both the trigger and the card, in\n * milliseconds. It is the time to cross the gap between them.\n */\n closeDelay?: number\n}\n\nconst props = withDefaults(defineProps<HoverCardProps>(), {\n placement: 'bottom',\n openDelay: 500,\n closeDelay: 300,\n})\n\n/** Whether the card is showing. Setting it opens or closes the card without any delay. */\nconst open = defineModel<boolean>('open', { default: false })\n\ndefineSlots<{\n /** The trigger, usually a link. Bind the `triggerProps` it receives onto it. */\n default(props: { triggerProps: HoverCardTriggerProps }): unknown\n /** What the card contains. It may hold links and buttons, and is rendered on first opening. */\n content?(): unknown\n}>()\n\nconst cardId = useId()\nconst rootEl = ref<HTMLElement | null>(null)\nconst panelEl = ref<HTMLElement | null>(null)\nconst { shown, syncShown, show: showPanel, hide: hidePanel } = usePopover(panelEl)\n\n// @ssr\n/*\n * The card is a `<span>` and its content mounts on first opening, so a trigger inside a\n * paragraph still produces valid server HTML: the parser closes a `<p>` at the first `<div>` or\n * `<p>` it meets, which would break hydration. The content then stays for the exit transition.\n */\nconst rendered = ref(false)\n\nconst timer = useTimer()\n\nlet hovered = false\nlet focused = false\n// Set while the card hands the focus back to its trigger, whose keyboard focus would reopen it.\nlet returningFocus = false\n\nconst inCard = (node: EventTarget | null) => !!panelEl.value?.contains(node as Node | null)\n\nfunction trigger() {\n return rootEl.value?.querySelector<HTMLElement>(`[aria-details=\"${cardId}\"]`) ?? null\n}\n\n// @core\nfunction show(immediate = false) {\n if (shown.value) {\n timer.cancel()\n return\n }\n // A delay of 0 runs the callback synchronously; the convention useTimer documents.\n timer.start(showPanel, immediate ? 0 : props.openDelay)\n}\n\n// @a11y\n/*\n * The trigger takes the focus back before the card hides. Left inside, the focus would follow\n * the browser's own restoration, which returns it to whatever held it when the card OPENED: for\n * a card opened by hover, an unrelated control elsewhere on the page.\n */\nfunction returnFocus() {\n if (!inCard(document.activeElement)) return\n returningFocus = true\n trigger()?.focus()\n returningFocus = false\n}\n\nfunction hide() {\n timer.cancel()\n returnFocus()\n hidePanel()\n}\n\n// @a11y\n// There is no hover on a touch screen: a tap keeps its usual meaning and opens nothing, so\n// whatever the card shows must also be reachable through the trigger's destination.\nfunction onPointerEnter(event: PointerEvent) {\n if (event.pointerType === 'touch') return\n hovered = true\n show()\n}\n\nfunction onPointerLeave(event: PointerEvent) {\n if (event.pointerType === 'touch') return\n hovered = false\n if (!focused) timer.start(hide, props.closeDelay)\n}\n\n/*\n * Pressing the trigger closes the card so it cannot stand over a dialog or a page the trigger\n * opens. A press inside the card is a use of its content and keeps it.\n */\nfunction onPointerDown(event: PointerEvent) {\n if (inCard(event.target)) return\n hovered = false\n focused = false\n hide()\n}\n\n// @a11y\n/*\n * Only the KEYBOARD focus opens the card from the trigger, read from `:focus-visible` as VTooltip\n * does: a focus given by a click opens nothing. Any focus inside the card keeps it, since a\n * click on one of its controls is still a use of it.\n */\nfunction onFocusIn(event: FocusEvent) {\n if (returningFocus) return\n if (inCard(event.target)) {\n focused = true\n timer.cancel()\n return\n }\n if (!isKeyboardFocus(event.target)) return\n focused = true\n show()\n}\n\nfunction onFocusOut(event: FocusEvent) {\n if (rootEl.value?.contains(event.relatedTarget as Node | null)) return\n focused = false\n if (!hovered) hide()\n}\n\n// Escape closes the card, handing a focus inside it back to the trigger.\nconst listen = useEscapeDismiss(() => {\n hovered = false\n focused = false\n hide()\n})\n\nfunction onBeforeToggle(event: Event) {\n syncShown(event)\n if (shown.value) rendered.value = true\n}\n\n// The toggle event is synchronous, so Escape works from the moment the card shows.\nfunction onToggle(event: Event) {\n onBeforeToggle(event)\n open.value = shown.value\n listen(shown.value)\n}\n\n// A model closing the card goes through `hide`, which hands a focus inside it back as well.\nusePopoverModel(open, () => shown.value, showPanel, hide)\n\ndefineExpose({\n /** Opens the card at once, without the delay. */\n show: () => show(true),\n /** Closes the card, handing a focus inside it back to the trigger. */\n close: hide,\n /** The card element. */\n el: panelEl,\n})\n</script>\n\n<template>\n <span\n ref=\"rootEl\"\n class=\"v-hover-card\"\n @pointerenter=\"onPointerEnter\"\n @pointerleave=\"onPointerLeave\"\n @pointerdown=\"onPointerDown\"\n @focusin=\"onFocusIn\"\n @focusout=\"onFocusOut\"\n >\n <slot :trigger-props=\"{ 'aria-details': cardId }\" />\n <!--\n The card follows the trigger in the DOM, so Tab moves from the trigger into the card's\n content while it shows.\n -->\n <span\n :id=\"cardId\"\n ref=\"panelEl\"\n popover=\"manual\"\n class=\"v-overlay v-floating v-panel v-hover-card-panel\"\n :data-placement=\"placement\"\n @beforetoggle=\"onBeforeToggle\"\n @toggle=\"onToggle\"\n >\n <slot v-if=\"rendered\" name=\"content\" />\n </span>\n </span>\n</template>\n\n<style>\n@layer vectis.components {\n .v-hover-card {\n display: inline-flex;\n align-items: center;\n anchor-name: --hover-card-anchor;\n /*\n * A visible card sits in the top layer, which anchor resolution treats as following the\n * whole document: without the scope, every card would attach to the last wrapper.\n */\n anchor-scope: --hover-card-anchor;\n }\n\n /*\n * Compound with `.v-panel` so the card's spacing outranks the shared panel chrome whatever\n * order the stylesheets load in.\n */\n .v-panel.v-hover-card-panel {\n position-anchor: --hover-card-anchor;\n gap: var(--vectis-space-2);\n padding: var(--vectis-space-4);\n inline-size: max-content;\n max-inline-size: min(\n var(--vectis-control-size-hover-card-max),\n calc(100dvi - var(--vectis-space-8))\n );\n font-size: var(--vectis-text-body-md-size);\n font-weight: var(--vectis-text-body-md-weight);\n line-height: var(--vectis-text-body-md-leading);\n text-align: start;\n white-space: normal;\n }\n}\n</style>\n"],"mappings":""}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { usePopover as e, usePopoverModel as t } from "../../composables/usePopover.js";
|
|
2
|
+
import { isKeyboardFocus as n } from "../../utils/focus.js";
|
|
3
|
+
import { useTimer as r } from "../../composables/useTimer.js";
|
|
4
|
+
import { useEscapeDismiss as i } from "../../composables/useEscapeDismiss.js";
|
|
5
|
+
import { createCommentVNode as a, createElementBlock as o, createElementVNode as s, defineComponent as c, mergeModels as l, openBlock as u, ref as d, renderSlot as f, unref as p, useId as m, useModel as h } from "vue";
|
|
6
|
+
//#region src/components/VHoverCard/VHoverCard.vue?vue&type=script&setup=true&lang.ts
|
|
7
|
+
var g = ["id", "data-placement"], _ = /*@__PURE__*/ c({
|
|
8
|
+
__name: "VHoverCard",
|
|
9
|
+
props: /*@__PURE__*/ l({
|
|
10
|
+
placement: { default: "bottom" },
|
|
11
|
+
openDelay: { default: 500 },
|
|
12
|
+
closeDelay: { default: 300 }
|
|
13
|
+
}, {
|
|
14
|
+
open: {
|
|
15
|
+
type: Boolean,
|
|
16
|
+
default: !1
|
|
17
|
+
},
|
|
18
|
+
openModifiers: {}
|
|
19
|
+
}),
|
|
20
|
+
emits: ["update:open"],
|
|
21
|
+
setup(c, { expose: l }) {
|
|
22
|
+
let _ = c, v = h(c, "open"), y = m(), b = d(null), x = d(null), { shown: S, syncShown: C, show: w, hide: T } = e(x), E = d(!1), D = r(), O = !1, k = !1, A = !1, j = (e) => !!x.value?.contains(e);
|
|
23
|
+
function M() {
|
|
24
|
+
return b.value?.querySelector(`[aria-details="${y}"]`) ?? null;
|
|
25
|
+
}
|
|
26
|
+
function N(e = !1) {
|
|
27
|
+
if (S.value) {
|
|
28
|
+
D.cancel();
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
D.start(w, e ? 0 : _.openDelay);
|
|
32
|
+
}
|
|
33
|
+
function P() {
|
|
34
|
+
j(document.activeElement) && (A = !0, M()?.focus(), A = !1);
|
|
35
|
+
}
|
|
36
|
+
function F() {
|
|
37
|
+
D.cancel(), P(), T();
|
|
38
|
+
}
|
|
39
|
+
function I(e) {
|
|
40
|
+
e.pointerType !== "touch" && (O = !0, N());
|
|
41
|
+
}
|
|
42
|
+
function L(e) {
|
|
43
|
+
e.pointerType !== "touch" && (O = !1, k || D.start(F, _.closeDelay));
|
|
44
|
+
}
|
|
45
|
+
function R(e) {
|
|
46
|
+
j(e.target) || (O = !1, k = !1, F());
|
|
47
|
+
}
|
|
48
|
+
function z(e) {
|
|
49
|
+
if (!A) {
|
|
50
|
+
if (j(e.target)) {
|
|
51
|
+
k = !0, D.cancel();
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
n(e.target) && (k = !0, N());
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function B(e) {
|
|
58
|
+
b.value?.contains(e.relatedTarget) || (k = !1, O || F());
|
|
59
|
+
}
|
|
60
|
+
let V = i(() => {
|
|
61
|
+
O = !1, k = !1, F();
|
|
62
|
+
});
|
|
63
|
+
function H(e) {
|
|
64
|
+
C(e), S.value && (E.value = !0);
|
|
65
|
+
}
|
|
66
|
+
function U(e) {
|
|
67
|
+
H(e), v.value = S.value, V(S.value);
|
|
68
|
+
}
|
|
69
|
+
return t(v, () => S.value, w, F), l({
|
|
70
|
+
show: () => N(!0),
|
|
71
|
+
close: F,
|
|
72
|
+
el: x
|
|
73
|
+
}), (e, t) => (u(), o("span", {
|
|
74
|
+
ref_key: "rootEl",
|
|
75
|
+
ref: b,
|
|
76
|
+
class: "v-hover-card",
|
|
77
|
+
onPointerenter: I,
|
|
78
|
+
onPointerleave: L,
|
|
79
|
+
onPointerdown: R,
|
|
80
|
+
onFocusin: z,
|
|
81
|
+
onFocusout: B
|
|
82
|
+
}, [f(e.$slots, "default", { triggerProps: { "aria-details": p(y) } }), s("span", {
|
|
83
|
+
id: p(y),
|
|
84
|
+
ref_key: "panelEl",
|
|
85
|
+
ref: x,
|
|
86
|
+
popover: "manual",
|
|
87
|
+
class: "v-overlay v-floating v-panel v-hover-card-panel",
|
|
88
|
+
"data-placement": c.placement,
|
|
89
|
+
onBeforetoggle: H,
|
|
90
|
+
onToggle: U
|
|
91
|
+
}, [E.value ? f(e.$slots, "content", {}, void 0, void 0, 0) : a("", !0)], 40, g)], 544));
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
//#endregion
|
|
95
|
+
export { _ as default };
|
|
96
|
+
|
|
97
|
+
//# sourceMappingURL=VHoverCard.vue_vue_type_script_setup_true_lang.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VHoverCard.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/VHoverCard/VHoverCard.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * A manual popover driven by hover and keyboard focus: no stable HTML primitive opens a panel\n * with a delay, as `popover=\"hint\"` and interest invokers are missing at the browser floor.\n * Manual mode also leaves any open menu or popover untouched.\n */\n\nimport { ref, useId } from 'vue'\n\nimport { useEscapeDismiss } from '../../composables/useEscapeDismiss'\nimport { usePopover, usePopoverModel } from '../../composables/usePopover'\nimport { useTimer } from '../../composables/useTimer'\nimport { isKeyboardFocus } from '../../utils/focus'\n\n/** Which side of the trigger the card appears on. */\nexport type HoverCardPlacement =\n | 'top'\n | 'top-start'\n | 'top-end'\n | 'bottom'\n | 'bottom-start'\n | 'bottom-end'\n | 'left'\n | 'left-start'\n | 'left-end'\n | 'right'\n | 'right-start'\n | 'right-end'\n\n/** What the trigger has to carry: the link to the card holding its details. */\nexport type HoverCardTriggerProps = {\n 'aria-details': string\n}\n\ninterface HoverCardProps {\n /**\n * Which side of the trigger the card appears on. The browser flips it to the opposite side by\n * itself when there is not enough room.\n */\n placement?: HoverCardPlacement\n /**\n * How long the pointer or the keyboard focus must rest on the trigger before the card opens,\n * in milliseconds.\n */\n openDelay?: number\n /**\n * How long the card stays once the pointer has left both the trigger and the card, in\n * milliseconds. It is the time to cross the gap between them.\n */\n closeDelay?: number\n}\n\nconst props = withDefaults(defineProps<HoverCardProps>(), {\n placement: 'bottom',\n openDelay: 500,\n closeDelay: 300,\n})\n\n/** Whether the card is showing. Setting it opens or closes the card without any delay. */\nconst open = defineModel<boolean>('open', { default: false })\n\ndefineSlots<{\n /** The trigger, usually a link. Bind the `triggerProps` it receives onto it. */\n default(props: { triggerProps: HoverCardTriggerProps }): unknown\n /** What the card contains. It may hold links and buttons, and is rendered on first opening. */\n content?(): unknown\n}>()\n\nconst cardId = useId()\nconst rootEl = ref<HTMLElement | null>(null)\nconst panelEl = ref<HTMLElement | null>(null)\nconst { shown, syncShown, show: showPanel, hide: hidePanel } = usePopover(panelEl)\n\n// @ssr\n/*\n * The card is a `<span>` and its content mounts on first opening, so a trigger inside a\n * paragraph still produces valid server HTML: the parser closes a `<p>` at the first `<div>` or\n * `<p>` it meets, which would break hydration. The content then stays for the exit transition.\n */\nconst rendered = ref(false)\n\nconst timer = useTimer()\n\nlet hovered = false\nlet focused = false\n// Set while the card hands the focus back to its trigger, whose keyboard focus would reopen it.\nlet returningFocus = false\n\nconst inCard = (node: EventTarget | null) => !!panelEl.value?.contains(node as Node | null)\n\nfunction trigger() {\n return rootEl.value?.querySelector<HTMLElement>(`[aria-details=\"${cardId}\"]`) ?? null\n}\n\n// @core\nfunction show(immediate = false) {\n if (shown.value) {\n timer.cancel()\n return\n }\n // A delay of 0 runs the callback synchronously; the convention useTimer documents.\n timer.start(showPanel, immediate ? 0 : props.openDelay)\n}\n\n// @a11y\n/*\n * The trigger takes the focus back before the card hides. Left inside, the focus would follow\n * the browser's own restoration, which returns it to whatever held it when the card OPENED: for\n * a card opened by hover, an unrelated control elsewhere on the page.\n */\nfunction returnFocus() {\n if (!inCard(document.activeElement)) return\n returningFocus = true\n trigger()?.focus()\n returningFocus = false\n}\n\nfunction hide() {\n timer.cancel()\n returnFocus()\n hidePanel()\n}\n\n// @a11y\n// There is no hover on a touch screen: a tap keeps its usual meaning and opens nothing, so\n// whatever the card shows must also be reachable through the trigger's destination.\nfunction onPointerEnter(event: PointerEvent) {\n if (event.pointerType === 'touch') return\n hovered = true\n show()\n}\n\nfunction onPointerLeave(event: PointerEvent) {\n if (event.pointerType === 'touch') return\n hovered = false\n if (!focused) timer.start(hide, props.closeDelay)\n}\n\n/*\n * Pressing the trigger closes the card so it cannot stand over a dialog or a page the trigger\n * opens. A press inside the card is a use of its content and keeps it.\n */\nfunction onPointerDown(event: PointerEvent) {\n if (inCard(event.target)) return\n hovered = false\n focused = false\n hide()\n}\n\n// @a11y\n/*\n * Only the KEYBOARD focus opens the card from the trigger, read from `:focus-visible` as VTooltip\n * does: a focus given by a click opens nothing. Any focus inside the card keeps it, since a\n * click on one of its controls is still a use of it.\n */\nfunction onFocusIn(event: FocusEvent) {\n if (returningFocus) return\n if (inCard(event.target)) {\n focused = true\n timer.cancel()\n return\n }\n if (!isKeyboardFocus(event.target)) return\n focused = true\n show()\n}\n\nfunction onFocusOut(event: FocusEvent) {\n if (rootEl.value?.contains(event.relatedTarget as Node | null)) return\n focused = false\n if (!hovered) hide()\n}\n\n// Escape closes the card, handing a focus inside it back to the trigger.\nconst listen = useEscapeDismiss(() => {\n hovered = false\n focused = false\n hide()\n})\n\nfunction onBeforeToggle(event: Event) {\n syncShown(event)\n if (shown.value) rendered.value = true\n}\n\n// The toggle event is synchronous, so Escape works from the moment the card shows.\nfunction onToggle(event: Event) {\n onBeforeToggle(event)\n open.value = shown.value\n listen(shown.value)\n}\n\n// A model closing the card goes through `hide`, which hands a focus inside it back as well.\nusePopoverModel(open, () => shown.value, showPanel, hide)\n\ndefineExpose({\n /** Opens the card at once, without the delay. */\n show: () => show(true),\n /** Closes the card, handing a focus inside it back to the trigger. */\n close: hide,\n /** The card element. */\n el: panelEl,\n})\n</script>\n\n<template>\n <span\n ref=\"rootEl\"\n class=\"v-hover-card\"\n @pointerenter=\"onPointerEnter\"\n @pointerleave=\"onPointerLeave\"\n @pointerdown=\"onPointerDown\"\n @focusin=\"onFocusIn\"\n @focusout=\"onFocusOut\"\n >\n <slot :trigger-props=\"{ 'aria-details': cardId }\" />\n <!--\n The card follows the trigger in the DOM, so Tab moves from the trigger into the card's\n content while it shows.\n -->\n <span\n :id=\"cardId\"\n ref=\"panelEl\"\n popover=\"manual\"\n class=\"v-overlay v-floating v-panel v-hover-card-panel\"\n :data-placement=\"placement\"\n @beforetoggle=\"onBeforeToggle\"\n @toggle=\"onToggle\"\n >\n <slot v-if=\"rendered\" name=\"content\" />\n </span>\n </span>\n</template>\n\n<style>\n@layer vectis.components {\n .v-hover-card {\n display: inline-flex;\n align-items: center;\n anchor-name: --hover-card-anchor;\n /*\n * A visible card sits in the top layer, which anchor resolution treats as following the\n * whole document: without the scope, every card would attach to the last wrapper.\n */\n anchor-scope: --hover-card-anchor;\n }\n\n /*\n * Compound with `.v-panel` so the card's spacing outranks the shared panel chrome whatever\n * order the stylesheets load in.\n */\n .v-panel.v-hover-card-panel {\n position-anchor: --hover-card-anchor;\n gap: var(--vectis-space-2);\n padding: var(--vectis-space-4);\n inline-size: max-content;\n max-inline-size: min(\n var(--vectis-control-size-hover-card-max),\n calc(100dvi - var(--vectis-space-8))\n );\n font-size: var(--vectis-text-body-md-size);\n font-weight: var(--vectis-text-body-md-weight);\n line-height: var(--vectis-text-body-md-leading);\n text-align: start;\n white-space: normal;\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;EAoDA,IAAM,IAAQ,GAOR,IAAO,EAAoB,GAAC,MAA0B,GAStD,IAAS,EAAM,GACf,IAAS,EAAwB,IAAI,GACrC,IAAU,EAAwB,IAAI,GACtC,EAAE,UAAO,cAAW,MAAM,GAAW,MAAM,MAAc,EAAW,CAAO,GAQ3E,IAAW,EAAI,EAAK,GAEpB,IAAQ,EAAS,GAEnB,IAAU,IACV,IAAU,IAEV,IAAiB,IAEf,KAAU,MAA6B,CAAC,CAAC,EAAQ,OAAO,SAAS,CAAmB;EAE1F,SAAS,IAAU;GACjB,OAAO,EAAO,OAAO,cAA2B,kBAAkB,EAAO,GAAG,KAAK;EACnF;EAGA,SAAS,EAAK,IAAY,IAAO;GAC/B,IAAI,EAAM,OAAO;IACf,EAAM,OAAO;IACb;GACF;GAEA,EAAM,MAAM,GAAW,IAAY,IAAI,EAAM,SAAS;EACxD;EAQA,SAAS,IAAc;GAChB,EAAO,SAAS,aAAa,MAClC,IAAiB,IACjB,EAAQ,CAAC,EAAE,MAAM,GACjB,IAAiB;EACnB;EAEA,SAAS,IAAO;GAGd,AAFA,EAAM,OAAO,GACb,EAAY,GACZ,EAAU;EACZ;EAKA,SAAS,EAAe,GAAqB;GACvC,EAAM,gBAAgB,YAC1B,IAAU,IACV,EAAK;EACP;EAEA,SAAS,EAAe,GAAqB;GACvC,EAAM,gBAAgB,YAC1B,IAAU,IACL,KAAS,EAAM,MAAM,GAAM,EAAM,UAAU;EAClD;EAMA,SAAS,EAAc,GAAqB;GACtC,EAAO,EAAM,MAAM,MACvB,IAAU,IACV,IAAU,IACV,EAAK;EACP;EAQA,SAAS,EAAU,GAAmB;GAChC,QACJ;QAAI,EAAO,EAAM,MAAM,GAAG;KAExB,AADA,IAAU,IACV,EAAM,OAAO;KACb;IACF;IACK,EAAgB,EAAM,MAAM,MACjC,IAAU,IACV,EAAK;GAHL;EAIF;EAEA,SAAS,EAAW,GAAmB;GACjC,EAAO,OAAO,SAAS,EAAM,aAA4B,MAC7D,IAAU,IACL,KAAS,EAAK;EACrB;EAGA,IAAM,IAAS,QAAuB;GAGpC,AAFA,IAAU,IACV,IAAU,IACV,EAAK;EACP,CAAC;EAED,SAAS,EAAe,GAAc;GAEpC,AADA,EAAU,CAAK,GACX,EAAM,UAAO,EAAS,QAAQ;EACpC;EAGA,SAAS,EAAS,GAAc;GAG9B,AAFA,EAAe,CAAK,GACpB,EAAK,QAAQ,EAAM,OACnB,EAAO,EAAM,KAAK;EACpB;SAGA,EAAgB,SAAY,EAAM,OAAO,GAAW,CAAI,GAExD,EAAa;GAEX,YAAY,EAAK,EAAI;GAErB,OAAO;GAEP,IAAI;EACN,CAAC,mBAIC,EAyBO,QAAA;YAxBD;GAAJ,KAAI;GACJ,OAAM;GACL,gBAAc;GACd,gBAAc;GACd,eAAa;GACb,WAAS;GACT,YAAU;MAEX,EAAoD,EAAA,QAAA,WAAA,EAA7C,cAAa,EAAA,gBAAoB,EAAA,CAAA,EAAM,EAAA,CAAA,GAK9C,EAUO,QAAA;GATJ,IAAI,EAAA,CAAA;YACD;GAAJ,KAAI;GACJ,SAAQ;GACR,OAAM;GACL,kBAAgB,EAAA;GAChB,gBAAc;GACN;MAEG,EAAA,QAAZ,EAAuC,EAAA,QAAA,WAAA,CAAA,GAAA,KAAA,GAAA,KAAA,GAAA,CAAA,IAAA,EAAA,IAAA,EAAA,CAAA,GAAA,IAAA,CAAA,CAAA,GAAA,GAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Material Symbols Rounded `add`. */
|
|
2
|
+
export declare const add: {
|
|
3
|
+
readonly name: "add";
|
|
4
|
+
readonly paths: readonly ["M440-440H240q-17 0-28.5-11.5T200-480q0-17 11.5-28.5T240-520h200v-200q0-17 11.5-28.5T480-760q17 0 28.5 11.5T520-720v200h200q17 0 28.5 11.5T760-480q0 17-11.5 28.5T720-440H520v200q0 17-11.5 28.5T480-200q-17 0-28.5-11.5T440-240v-200Z"];
|
|
5
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region src/components/VIcon/icons/add.ts
|
|
2
|
+
var e = {
|
|
3
|
+
name: "add",
|
|
4
|
+
paths: ["M440-440H240q-17 0-28.5-11.5T200-480q0-17 11.5-28.5T240-520h200v-200q0-17 11.5-28.5T480-760q17 0 28.5 11.5T520-720v200h200q17 0 28.5 11.5T760-480q0 17-11.5 28.5T720-440H520v200q0 17-11.5 28.5T480-200q-17 0-28.5-11.5T440-240v-200Z"]
|
|
5
|
+
};
|
|
6
|
+
//#endregion
|
|
7
|
+
export { e as add };
|
|
8
|
+
|
|
9
|
+
//# sourceMappingURL=add.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add.js","names":[],"sources":["../../../../src/components/VIcon/icons/add.ts"],"sourcesContent":["/*\n * GENERATED FILE — do not edit by hand.\n * Regenerate: pnpm icons · Source: scripts/build-icons.ts\n *\n * Material Symbols Rounded (wght 400 · GRAD 0 · opsz 24)\n * google/material-design-icons @ 528cb964c01fb2b09bc3b9208f82b6d8f8c1c1e2\n * Apache-2.0 licence © Google.\n */\nimport type { BuiltinIcon } from '../types'\n\n/** Material Symbols Rounded `add`. */\nexport const add = {\n name: 'add',\n paths: [\n 'M440-440H240q-17 0-28.5-11.5T200-480q0-17 11.5-28.5T240-520h200v-200q0-17 11.5-28.5T480-760q17 0 28.5 11.5T520-720v200h200q17 0 28.5 11.5T760-480q0 17-11.5 28.5T720-440H520v200q0 17-11.5 28.5T480-200q-17 0-28.5-11.5T440-240v-200Z',\n ],\n} as const satisfies BuiltinIcon\n"],"mappings":";AAWA,IAAa,IAAM;CACjB,MAAM;CACN,OAAO,CACL,uOACF;AACF"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Material Symbols Rounded `colorize`, outline then filled. */
|
|
2
|
+
export declare const colorize: {
|
|
3
|
+
readonly name: "colorize";
|
|
4
|
+
readonly paths: readonly ["M120-160v-117q0-16 6-30.5t17-25.5l335-335-58-56 58-56 76 76 124-124q5-5 12.5-8t15.5-3q8 0 15 3t13 8l94 94q5 6 8 13t3 15q0 8-3 15.5t-8 12.5L705-555l76 78-57 57-56-58-335 335q-11 11-25.5 17t-30.5 6H160q-17 0-28.5-11.5T120-160Zm80-40h78l332-334-76-76-334 332v78Zm447-410 96-96-37-37-96 96 37 37Zm0 0-37-37 37 37Z", "M120-160v-117q0-16 6-30.5t17-25.5l335-335-58-56 58-56 76 76 124-124q5-5 12.5-8t15.5-3q8 0 15 3t13 8l94 94q5 6 8 13t3 15q0 8-3 15.5t-8 12.5L705-555l76 78-57 57-56-58-335 335q-11 11-25.5 17t-30.5 6H160q-17 0-28.5-11.5T120-160Zm80-40h78l332-334-76-76-334 332v78Z"];
|
|
5
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region src/components/VIcon/icons/colorize.ts
|
|
2
|
+
var e = {
|
|
3
|
+
name: "colorize",
|
|
4
|
+
paths: ["M120-160v-117q0-16 6-30.5t17-25.5l335-335-58-56 58-56 76 76 124-124q5-5 12.5-8t15.5-3q8 0 15 3t13 8l94 94q5 6 8 13t3 15q0 8-3 15.5t-8 12.5L705-555l76 78-57 57-56-58-335 335q-11 11-25.5 17t-30.5 6H160q-17 0-28.5-11.5T120-160Zm80-40h78l332-334-76-76-334 332v78Zm447-410 96-96-37-37-96 96 37 37Zm0 0-37-37 37 37Z", "M120-160v-117q0-16 6-30.5t17-25.5l335-335-58-56 58-56 76 76 124-124q5-5 12.5-8t15.5-3q8 0 15 3t13 8l94 94q5 6 8 13t3 15q0 8-3 15.5t-8 12.5L705-555l76 78-57 57-56-58-335 335q-11 11-25.5 17t-30.5 6H160q-17 0-28.5-11.5T120-160Zm80-40h78l332-334-76-76-334 332v78Z"]
|
|
5
|
+
};
|
|
6
|
+
//#endregion
|
|
7
|
+
export { e as colorize };
|
|
8
|
+
|
|
9
|
+
//# sourceMappingURL=colorize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"colorize.js","names":[],"sources":["../../../../src/components/VIcon/icons/colorize.ts"],"sourcesContent":["/*\n * GENERATED FILE — do not edit by hand.\n * Regenerate: pnpm icons · Source: scripts/build-icons.ts\n *\n * Material Symbols Rounded (wght 400 · GRAD 0 · opsz 24)\n * google/material-design-icons @ 528cb964c01fb2b09bc3b9208f82b6d8f8c1c1e2\n * Apache-2.0 licence © Google.\n */\nimport type { BuiltinIcon } from '../types'\n\n/** Material Symbols Rounded `colorize`, outline then filled. */\nexport const colorize = {\n name: 'colorize',\n paths: [\n 'M120-160v-117q0-16 6-30.5t17-25.5l335-335-58-56 58-56 76 76 124-124q5-5 12.5-8t15.5-3q8 0 15 3t13 8l94 94q5 6 8 13t3 15q0 8-3 15.5t-8 12.5L705-555l76 78-57 57-56-58-335 335q-11 11-25.5 17t-30.5 6H160q-17 0-28.5-11.5T120-160Zm80-40h78l332-334-76-76-334 332v78Zm447-410 96-96-37-37-96 96 37 37Zm0 0-37-37 37 37Z',\n 'M120-160v-117q0-16 6-30.5t17-25.5l335-335-58-56 58-56 76 76 124-124q5-5 12.5-8t15.5-3q8 0 15 3t13 8l94 94q5 6 8 13t3 15q0 8-3 15.5t-8 12.5L705-555l76 78-57 57-56-58-335 335q-11 11-25.5 17t-30.5 6H160q-17 0-28.5-11.5T120-160Zm80-40h78l332-334-76-76-334 332v78Z',\n ],\n} as const satisfies BuiltinIcon\n"],"mappings":";AAWA,IAAa,IAAW;CACtB,MAAM;CACN,OAAO,CACL,yTACA,qQACF;AACF"}
|