vectis-ui 0.12.0 → 0.14.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 -194
- 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.js.map +1 -1
- package/dist/components/VPagination/VPagination.vue_vue_type_script_setup_true_lang.js +77 -77
- package/dist/components/VPagination/VPagination.vue_vue_type_script_setup_true_lang.js.map +1 -1
- 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 +418 -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 +16 -16
- 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/VToggle.js.map +1 -1
- package/dist/components/VToggle/VToggle.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/VToggle/VToggle.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VToggle/VToggleItem.d.ts +1 -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 +317 -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 +29 -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} +9 -9
- 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/useTypeahead.d.ts +13 -0
- package/dist/composables/useTypeahead.js +23 -0
- package/dist/composables/useTypeahead.js.map +1 -0
- 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/state.d.ts +1 -1
- package/dist/i18n/state.js +17 -6
- package/dist/i18n/state.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 +5 -4
- 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
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { useMessages as e, useResolvedLocale as t } from "../../i18n/state.js";
|
|
2
|
+
import n from "../VIcon/VIcon.js";
|
|
3
|
+
import ee from "../VSeparator/VSeparator.js";
|
|
4
|
+
import { useControlShape as r } from "../../composables/useControlShape.js";
|
|
5
|
+
import { expand_more as te } from "../VIcon/icons/expand_more.js";
|
|
6
|
+
import { expand_less as ne } from "../VIcon/icons/expand_less.js";
|
|
7
|
+
import { canClear as re } from "../../composables/useClearable.js";
|
|
8
|
+
import { inputGroupKey as ie } from "../VInput/context.js";
|
|
9
|
+
import ae from "../VInput/VInput.js";
|
|
10
|
+
import { add as i } from "../VIcon/icons/add.js";
|
|
11
|
+
import { remove as a } from "../VIcon/icons/remove.js";
|
|
12
|
+
import { partitionAttrs as oe } from "../../utils/attrs.js";
|
|
13
|
+
import { clamp as o, numberSeparators as se, parseNumber as s, scale as c, stepValue as l } from "./number.js";
|
|
14
|
+
import { Fragment as u, computed as d, createBlock as ce, createCommentVNode as f, createElementBlock as p, createElementVNode as m, createSlots as le, createVNode as h, defineComponent as g, inject as ue, mergeModels as _, mergeProps as v, openBlock as y, ref as b, unref as x, useAttrs as S, useModel as C, watch as de, withCtx as w, withModifiers as T } from "vue";
|
|
15
|
+
//#region src/components/VNumberInput/VNumberInput.vue?vue&type=script&setup=true&lang.ts
|
|
16
|
+
var fe = ["aria-label", "disabled"], pe = ["aria-label", "disabled"], me = { class: "v-number-input-stack" }, he = ["aria-label", "disabled"], ge = ["aria-label", "disabled"], _e = [
|
|
17
|
+
"name",
|
|
18
|
+
"form",
|
|
19
|
+
"value",
|
|
20
|
+
"disabled"
|
|
21
|
+
], E = /*@__PURE__*/ g({
|
|
22
|
+
inheritAttrs: !1,
|
|
23
|
+
__name: "VNumberInput",
|
|
24
|
+
props: /*@__PURE__*/ _({
|
|
25
|
+
min: { default: void 0 },
|
|
26
|
+
max: { default: void 0 },
|
|
27
|
+
step: { default: 1 },
|
|
28
|
+
formatOptions: { default: void 0 },
|
|
29
|
+
locale: { default: void 0 },
|
|
30
|
+
controls: { default: "split" },
|
|
31
|
+
incrementLabel: { default: void 0 },
|
|
32
|
+
decrementLabel: { default: void 0 },
|
|
33
|
+
size: { default: "md" },
|
|
34
|
+
compact: {
|
|
35
|
+
type: Boolean,
|
|
36
|
+
default: !1
|
|
37
|
+
},
|
|
38
|
+
label: { default: void 0 },
|
|
39
|
+
hint: { default: void 0 },
|
|
40
|
+
error: { default: void 0 },
|
|
41
|
+
required: {
|
|
42
|
+
type: Boolean,
|
|
43
|
+
default: !1
|
|
44
|
+
},
|
|
45
|
+
hideLabel: {
|
|
46
|
+
type: Boolean,
|
|
47
|
+
default: !1
|
|
48
|
+
},
|
|
49
|
+
labelPosition: { default: "top" },
|
|
50
|
+
invalid: {
|
|
51
|
+
type: Boolean,
|
|
52
|
+
default: !1
|
|
53
|
+
},
|
|
54
|
+
disabled: {
|
|
55
|
+
type: Boolean,
|
|
56
|
+
default: !1
|
|
57
|
+
},
|
|
58
|
+
readonly: {
|
|
59
|
+
type: Boolean,
|
|
60
|
+
default: !1
|
|
61
|
+
},
|
|
62
|
+
clearable: {
|
|
63
|
+
type: Boolean,
|
|
64
|
+
default: !1
|
|
65
|
+
},
|
|
66
|
+
clearLabel: { default: void 0 },
|
|
67
|
+
loading: {
|
|
68
|
+
type: Boolean,
|
|
69
|
+
default: !1
|
|
70
|
+
},
|
|
71
|
+
loadingText: { default: void 0 }
|
|
72
|
+
}, {
|
|
73
|
+
modelValue: { default: null },
|
|
74
|
+
modelModifiers: {}
|
|
75
|
+
}),
|
|
76
|
+
emits: /*@__PURE__*/ _(["clear"], ["update:modelValue"]),
|
|
77
|
+
setup(g, { expose: _, emit: E }) {
|
|
78
|
+
let D = g, O = E, k = C(g, "modelValue"), A = e(), j = t(() => D.locale), M = d(() => D.incrementLabel ?? A.value.numberInput.increment), N = d(() => D.decrementLabel ?? A.value.numberInput.decrement), { disabled: P } = r(D, ue(ie, null)), F = S(), I = d(() => oe(F, ["name", "form"])), ve = d(() => I.value.rest), L = d(() => I.value.picked.name), ye = d(() => I.value.picked.form), R = d(() => D.formatOptions?.style === "percent"), be = d(() => se(j.value)), z = d(() => new Intl.NumberFormat(j.value, D.formatOptions)), B = d(() => new Intl.NumberFormat(j.value, {
|
|
79
|
+
useGrouping: !1,
|
|
80
|
+
maximumFractionDigits: 20
|
|
81
|
+
})), V = (e) => e === null ? "" : z.value.format(e), xe = (e) => e === null ? "" : B.value.format(R.value ? c(e, 100) : e);
|
|
82
|
+
function H() {
|
|
83
|
+
let e = s(K.value, be.value);
|
|
84
|
+
return e === null || Number.isNaN(e) || !R.value ? e : c(e, .01);
|
|
85
|
+
}
|
|
86
|
+
let U = b(null), W = b(null), G = b(!1), K = b(V(k.value));
|
|
87
|
+
function q() {
|
|
88
|
+
K.value = G.value ? xe(k.value) : V(k.value);
|
|
89
|
+
}
|
|
90
|
+
de([
|
|
91
|
+
k,
|
|
92
|
+
z,
|
|
93
|
+
B
|
|
94
|
+
], q);
|
|
95
|
+
function J(e) {
|
|
96
|
+
k.value = e, q(), W.value && (W.value.value = e === null ? "" : String(e));
|
|
97
|
+
}
|
|
98
|
+
function Y() {
|
|
99
|
+
let e = H();
|
|
100
|
+
Number.isNaN(e) ? q() : J(e === null ? null : o(e, D.min, D.max));
|
|
101
|
+
}
|
|
102
|
+
let X = d(() => !P.value && !D.readonly), Se = d(() => D.loading || re(D, P.value, K.value !== "")), Z = d(() => k.value !== null && D.min !== void 0 && k.value <= D.min), Q = d(() => k.value !== null && D.max !== void 0 && k.value >= D.max);
|
|
103
|
+
function $(e) {
|
|
104
|
+
if (!X.value) return;
|
|
105
|
+
let t = G.value ? H() : k.value, n = t === null || Number.isNaN(t) ? k.value : t;
|
|
106
|
+
if (n === null) return J(o(0, D.min, D.max));
|
|
107
|
+
J(o(l(n, e, D.step > 0 ? D.step : 1, D.min ?? 0), D.min, D.max));
|
|
108
|
+
}
|
|
109
|
+
function Ce(e) {
|
|
110
|
+
if (e.altKey || e.ctrlKey || e.metaKey) return;
|
|
111
|
+
let t = {
|
|
112
|
+
ArrowUp: 1,
|
|
113
|
+
ArrowDown: -1,
|
|
114
|
+
PageUp: 10,
|
|
115
|
+
PageDown: -10
|
|
116
|
+
};
|
|
117
|
+
e.key in t ? (e.preventDefault(), $(t[e.key])) : e.key === "Home" && D.min !== void 0 && X.value ? (e.preventDefault(), J(D.min)) : e.key === "End" && D.max !== void 0 && X.value ? (e.preventDefault(), J(D.max)) : e.key === "Enter" && Y();
|
|
118
|
+
}
|
|
119
|
+
function we() {
|
|
120
|
+
G.value = !0, q();
|
|
121
|
+
}
|
|
122
|
+
function Te() {
|
|
123
|
+
G.value = !1, Y();
|
|
124
|
+
}
|
|
125
|
+
function Ee() {
|
|
126
|
+
J(null), O("clear");
|
|
127
|
+
}
|
|
128
|
+
return _({
|
|
129
|
+
focus: (e) => U.value?.focus(e),
|
|
130
|
+
select: () => U.value?.select(),
|
|
131
|
+
el: d(() => U.value?.el ?? null)
|
|
132
|
+
}), (e, t) => (y(), p(u, null, [h(ae, v({
|
|
133
|
+
ref_key: "inputRef",
|
|
134
|
+
ref: U,
|
|
135
|
+
modelValue: K.value,
|
|
136
|
+
"onUpdate:modelValue": t[8] ||= (e) => K.value = e,
|
|
137
|
+
class: "v-number-input",
|
|
138
|
+
role: "spinbutton",
|
|
139
|
+
inputmode: "decimal",
|
|
140
|
+
autocomplete: "off",
|
|
141
|
+
"aria-valuenow": k.value ?? void 0,
|
|
142
|
+
"aria-valuemin": g.min,
|
|
143
|
+
"aria-valuemax": g.max,
|
|
144
|
+
"aria-valuetext": k.value === null ? void 0 : V(k.value),
|
|
145
|
+
"data-controls": g.controls
|
|
146
|
+
}, ve.value, {
|
|
147
|
+
size: g.size,
|
|
148
|
+
compact: g.compact,
|
|
149
|
+
label: g.label,
|
|
150
|
+
hint: g.hint,
|
|
151
|
+
error: g.error,
|
|
152
|
+
required: g.required,
|
|
153
|
+
"hide-label": g.hideLabel,
|
|
154
|
+
"label-position": g.labelPosition,
|
|
155
|
+
invalid: g.invalid,
|
|
156
|
+
disabled: g.disabled,
|
|
157
|
+
readonly: g.readonly,
|
|
158
|
+
clearable: g.clearable,
|
|
159
|
+
"clear-label": g.clearLabel,
|
|
160
|
+
loading: g.loading,
|
|
161
|
+
"loading-text": g.loadingText,
|
|
162
|
+
onFocus: we,
|
|
163
|
+
onBlur: Te,
|
|
164
|
+
onKeydown: Ce,
|
|
165
|
+
onClear: Ee
|
|
166
|
+
}), le({ _: 2 }, [g.controls === "split" ? {
|
|
167
|
+
name: "start",
|
|
168
|
+
fn: w(() => [m("button", {
|
|
169
|
+
type: "button",
|
|
170
|
+
tabindex: "-1",
|
|
171
|
+
class: "v-field-action v-number-input-step",
|
|
172
|
+
"aria-label": N.value,
|
|
173
|
+
disabled: !X.value || Z.value,
|
|
174
|
+
onMousedown: t[0] ||= T(() => {}, ["prevent"]),
|
|
175
|
+
onClick: t[1] ||= (e) => $(-1)
|
|
176
|
+
}, [h(n, { name: x(a) }, null, 8, ["name"])], 40, fe)]),
|
|
177
|
+
key: "0"
|
|
178
|
+
} : void 0, g.controls === "split" ? {
|
|
179
|
+
name: "value-end",
|
|
180
|
+
fn: w(() => [m("button", {
|
|
181
|
+
type: "button",
|
|
182
|
+
tabindex: "-1",
|
|
183
|
+
class: "v-field-action v-number-input-step",
|
|
184
|
+
"aria-label": M.value,
|
|
185
|
+
disabled: !X.value || Q.value,
|
|
186
|
+
onMousedown: t[2] ||= T(() => {}, ["prevent"]),
|
|
187
|
+
onClick: t[3] ||= (e) => $(1)
|
|
188
|
+
}, [h(n, { name: x(i) }, null, 8, ["name"])], 40, pe), Se.value ? (y(), ce(ee, {
|
|
189
|
+
key: 0,
|
|
190
|
+
orientation: "vertical",
|
|
191
|
+
class: "v-number-input-divider"
|
|
192
|
+
})) : f("", !0)]),
|
|
193
|
+
key: "1"
|
|
194
|
+
} : g.controls === "stacked" ? {
|
|
195
|
+
name: "value-end",
|
|
196
|
+
fn: w(() => [m("span", me, [m("button", {
|
|
197
|
+
type: "button",
|
|
198
|
+
tabindex: "-1",
|
|
199
|
+
class: "v-field-action v-number-input-step",
|
|
200
|
+
"aria-label": M.value,
|
|
201
|
+
disabled: !X.value || Q.value,
|
|
202
|
+
onMousedown: t[4] ||= T(() => {}, ["prevent"]),
|
|
203
|
+
onClick: t[5] ||= (e) => $(1)
|
|
204
|
+
}, [h(n, { name: x(ne) }, null, 8, ["name"])], 40, he), m("button", {
|
|
205
|
+
type: "button",
|
|
206
|
+
tabindex: "-1",
|
|
207
|
+
class: "v-field-action v-number-input-step",
|
|
208
|
+
"aria-label": N.value,
|
|
209
|
+
disabled: !X.value || Z.value,
|
|
210
|
+
onMousedown: t[6] ||= T(() => {}, ["prevent"]),
|
|
211
|
+
onClick: t[7] ||= (e) => $(-1)
|
|
212
|
+
}, [h(n, { name: x(te) }, null, 8, ["name"])], 40, ge)])]),
|
|
213
|
+
key: "2"
|
|
214
|
+
} : void 0]), 1040, [
|
|
215
|
+
"modelValue",
|
|
216
|
+
"aria-valuenow",
|
|
217
|
+
"aria-valuemin",
|
|
218
|
+
"aria-valuemax",
|
|
219
|
+
"aria-valuetext",
|
|
220
|
+
"data-controls",
|
|
221
|
+
"size",
|
|
222
|
+
"compact",
|
|
223
|
+
"label",
|
|
224
|
+
"hint",
|
|
225
|
+
"error",
|
|
226
|
+
"required",
|
|
227
|
+
"hide-label",
|
|
228
|
+
"label-position",
|
|
229
|
+
"invalid",
|
|
230
|
+
"disabled",
|
|
231
|
+
"readonly",
|
|
232
|
+
"clearable",
|
|
233
|
+
"clear-label",
|
|
234
|
+
"loading",
|
|
235
|
+
"loading-text"
|
|
236
|
+
]), L.value ? (y(), p("input", {
|
|
237
|
+
key: 0,
|
|
238
|
+
ref_key: "hiddenEl",
|
|
239
|
+
ref: W,
|
|
240
|
+
type: "hidden",
|
|
241
|
+
name: L.value,
|
|
242
|
+
form: ye.value,
|
|
243
|
+
value: k.value ?? "",
|
|
244
|
+
disabled: x(P)
|
|
245
|
+
}, null, 8, _e)) : f("", !0)], 64));
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
//#endregion
|
|
249
|
+
export { E as default };
|
|
250
|
+
|
|
251
|
+
//# sourceMappingURL=VNumberInput.vue_vue_type_script_setup_true_lang.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VNumberInput.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/VNumberInput/VNumberInput.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @a11y @core\n/**\n * A text field announced as a spinbutton rather than a native number input: only a text field\n * can show a number formatted for its locale (separators, currency, unit, percent), which\n * `type=\"number\"` refuses. The keyboard of a spinbutton, the parsing and the stepping are\n * therefore rebuilt here; the typed value is committed on blur and on Enter, so that a minimum\n * never interrupts the typing of a number that would have reached it.\n */\nimport { computed, inject, ref, useAttrs, watch } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { add as addIcon } from '../VIcon/icons/add'\nimport { expand_less as expandLessIcon } from '../VIcon/icons/expand_less'\nimport { expand_more as expandMoreIcon } from '../VIcon/icons/expand_more'\nimport { remove as removeIcon } from '../VIcon/icons/remove'\nimport type { FieldLabelPosition } from '../VField/VField.vue'\nimport VInput from '../VInput/VInput.vue'\nimport type { InputSize } from '../VInput/VInput.vue'\nimport { inputGroupKey } from '../VInput/context'\nimport VSeparator from '../VSeparator/VSeparator.vue'\n\nimport { canClear } from '../../composables/useClearable'\nimport { partitionAttrs } from '../../utils/attrs'\nimport { useControlShape } from '../../composables/useControlShape'\nimport { useMessages, useResolvedLocale } from '../../i18n/state'\n\nimport { clamp, numberSeparators, parseNumber, scale, stepValue } from './number'\n\n/**\n * Where the step buttons sit: a minus at the start and a plus at the end, both stacked at the\n * end, or none.\n */\nexport type NumberInputControls = 'split' | 'stacked' | 'none'\n\ninterface NumberInputProps {\n /** The smallest value. A typed value below it is raised to it when committed. */\n min?: number\n /** The largest value. A typed value above it is lowered to it when committed. */\n max?: number\n /**\n * How far the arrow keys and the buttons move the value, on a grid that starts at `min`, or at\n * 0 without one. Page Up and Page Down move it ten steps.\n */\n step?: number\n /**\n * How the value is shown while the field is not being edited: the options of\n * `Intl.NumberFormat`, for a currency, a unit, a percentage or a number of decimals. With\n * `style: 'percent'`, the value 0.25 shows and is typed as 25.\n */\n formatOptions?: Intl.NumberFormatOptions\n /** The locale the number is written and read in. It defaults to the design system's. */\n locale?: string\n /** Where the step buttons sit. Whatever their place, they stay out of the tab order. */\n controls?: NumberInputControls\n /** What the plus button does, in words. It falls back to the design system dictionary. */\n incrementLabel?: string\n /** What the minus button does, in words. It falls back to the design system dictionary. */\n decrementLabel?: string\n /** The height of the field: 32, 40 or 48 pixels. */\n size?: InputSize\n /** Takes 4px off the height. */\n compact?: boolean\n /** The label above the field, tied to it. */\n label?: string\n /** A line of help under the field, read out along with the label. */\n hint?: string\n /**\n * A message saying what is wrong with the value, shown in place of the hint. It marks the\n * field invalid and is announced when it appears or changes.\n */\n error?: string\n /** Marks the field as required: an asterisk follows the label, and the field is `required`. */\n required?: boolean\n /** Hides the label visually. It still names the field for assistive technology. */\n hideLabel?: boolean\n /**\n * Where the label sits: above the field (`top`, the default), or at its start, in a column of\n * its own, moving back above when there is not room for both.\n */\n labelPosition?: FieldLabelPosition\n /** Marks the field as invalid whatever the browser thinks. */\n invalid?: boolean\n /** Makes the field unusable, greyed out through the colour tokens. */\n disabled?: boolean\n /** Shows the value without allowing it to be changed, by typing or by stepping. */\n readonly?: boolean\n /** Offers a cross that empties the field, setting the value to `null`. */\n clearable?: boolean\n /** What the clear button does, in words. It falls back to the design system dictionary. */\n clearLabel?: string\n /** Shows a spinner at the end of the field. */\n loading?: boolean\n /** What screen readers announce while the spinner turns. */\n loadingText?: string\n}\n\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<NumberInputProps>(), {\n min: undefined,\n max: undefined,\n step: 1,\n formatOptions: undefined,\n locale: undefined,\n controls: 'split',\n incrementLabel: undefined,\n decrementLabel: undefined,\n size: 'md',\n compact: false,\n label: undefined,\n hint: undefined,\n error: undefined,\n required: false,\n hideLabel: false,\n labelPosition: 'top',\n invalid: false,\n disabled: false,\n readonly: false,\n clearable: false,\n clearLabel: undefined,\n loading: false,\n loadingText: undefined,\n})\n\nconst emit = defineEmits<{\n /** The clear button was pressed. The value is already `null`. */\n clear: []\n}>()\n\n/** The value, `null` while the field is empty. */\nconst model = defineModel<number | null>({ default: null })\n\nconst m = useMessages()\nconst resolvedLocale = useResolvedLocale(() => props.locale)\nconst incrementText = computed(() => props.incrementLabel ?? m.value.numberInput.increment)\nconst decrementText = computed(() => props.decrementLabel ?? m.value.numberInput.decrement)\n\nconst group = inject(inputGroupKey, null)\nconst { disabled: resolvedDisabled } = useControlShape(props, group)\n\n// @a11y\n// Everything goes down to VInput, which keeps `class` and `style` on its wrapper; except `name`\n// and `form`, which move to a hidden input carrying the bare number: the visible field holds\n// formatted text (\"1 234,50 €\"), which is not what a form should submit.\nconst attrs = useAttrs()\nconst split = computed(() => partitionAttrs(attrs, ['name', 'form']))\nconst fieldAttrs = computed(() => split.value.rest)\nconst formName = computed(() => split.value.picked.name as string | undefined)\nconst formOwner = computed(() => split.value.picked.form as string | undefined)\n\nconst percent = computed(() => props.formatOptions?.style === 'percent')\nconst separators = computed(() => numberSeparators(resolvedLocale.value))\nconst displayFormat = computed(\n () => new Intl.NumberFormat(resolvedLocale.value, props.formatOptions),\n)\n// The value as it is edited: no grouping, no symbol, every decimal it has.\nconst editFormat = computed(\n () =>\n new Intl.NumberFormat(resolvedLocale.value, {\n useGrouping: false,\n maximumFractionDigits: 20,\n }),\n)\n\nconst display = (value: number | null) => (value === null ? '' : displayFormat.value.format(value))\nconst editable = (value: number | null) =>\n value === null ? '' : editFormat.value.format(percent.value ? scale(value, 100) : value)\n\n/** What was typed, read as a value: `null` when empty, `NaN` when not a number. */\nfunction typedValue(): number | null {\n const value = parseNumber(text.value, separators.value)\n return value === null || Number.isNaN(value) || !percent.value ? value : scale(value, 0.01)\n}\n\nconst inputRef = ref<InstanceType<typeof VInput> | null>(null)\nconst hiddenEl = ref<HTMLInputElement | null>(null)\nconst focused = ref(false)\nconst text = ref(display(model.value))\n\nfunction syncText() {\n text.value = focused.value ? editable(model.value) : display(model.value)\n}\n\nwatch([model, displayFormat, editFormat], syncText)\n\nfunction setValue(value: number | null) {\n model.value = value\n syncText()\n // @core\n // Enter submits a form as the default action of the very keydown that commits the value,\n // before Vue renders: the hidden input is written now, or the previous number is submitted.\n if (hiddenEl.value) hiddenEl.value.value = value === null ? '' : String(value)\n}\n\n/** Commits what was typed: empty is `null`, a number is kept within bounds, text is undone. */\nfunction commit() {\n const value = typedValue()\n if (Number.isNaN(value)) syncText()\n else setValue(value === null ? null : clamp(value, props.min, props.max))\n}\n\nconst editableField = computed(() => !resolvedDisabled.value && !props.readonly)\n/**\n * Whether the field's own controls follow the plus button: the clear cross, which VInput shows by\n * the same rule, or the spinner. A rule then sets the plus apart from them.\n */\nconst endControls = computed(\n () => props.loading || canClear(props, resolvedDisabled.value, text.value !== ''),\n)\nconst atMin = computed(\n () => model.value !== null && props.min !== undefined && model.value <= props.min,\n)\nconst atMax = computed(\n () => model.value !== null && props.max !== undefined && model.value >= props.max,\n)\n\n/**\n * Moves the value by a number of steps, from what is typed when it reads as a number. An empty\n * field starts from 0, or from the nearest bound when 0 is out of range.\n */\nfunction stepBy(steps: number) {\n if (!editableField.value) return\n const typed = focused.value ? typedValue() : model.value\n const current = typed === null || Number.isNaN(typed) ? model.value : typed\n if (current === null) return setValue(clamp(0, props.min, props.max))\n const step = props.step > 0 ? props.step : 1\n setValue(clamp(stepValue(current, steps, step, props.min ?? 0), props.min, props.max))\n}\n\n// @keyboard\n// The keys of the APG spinbutton. Home and End only take a value when there is a bound to go\n// to; otherwise they keep moving the caret, as in any text field.\nfunction onKeydown(event: KeyboardEvent) {\n if (event.altKey || event.ctrlKey || event.metaKey) return\n const steps: Record<string, number> = { ArrowUp: 1, ArrowDown: -1, PageUp: 10, PageDown: -10 }\n if (event.key in steps) {\n event.preventDefault()\n stepBy(steps[event.key]!)\n } else if (event.key === 'Home' && props.min !== undefined && editableField.value) {\n event.preventDefault()\n setValue(props.min)\n } else if (event.key === 'End' && props.max !== undefined && editableField.value) {\n event.preventDefault()\n setValue(props.max)\n } else if (event.key === 'Enter') {\n commit()\n }\n}\n\nfunction onFocus() {\n focused.value = true\n syncText()\n}\n\nfunction onBlur() {\n focused.value = false\n commit()\n}\n\nfunction onClear() {\n setValue(null)\n emit('clear')\n}\n\ndefineExpose({\n /** Moves the focus to the real input. */\n focus: (options?: FocusOptions) => inputRef.value?.focus(options),\n /** Selects everything in the field. */\n select: () => inputRef.value?.select(),\n /** The real `<input>`. */\n el: computed(() => inputRef.value?.el ?? null),\n})\n</script>\n\n<template>\n <VInput\n ref=\"inputRef\"\n v-model=\"text\"\n class=\"v-number-input\"\n role=\"spinbutton\"\n inputmode=\"decimal\"\n autocomplete=\"off\"\n :aria-valuenow=\"model ?? undefined\"\n :aria-valuemin=\"min\"\n :aria-valuemax=\"max\"\n :aria-valuetext=\"model === null ? undefined : display(model)\"\n :data-controls=\"controls\"\n v-bind=\"fieldAttrs\"\n :size=\"size\"\n :compact=\"compact\"\n :label=\"label\"\n :hint=\"hint\"\n :error=\"error\"\n :required=\"required\"\n :hide-label=\"hideLabel\"\n :label-position=\"labelPosition\"\n :invalid=\"invalid\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :clearable=\"clearable\"\n :clear-label=\"clearLabel\"\n :loading=\"loading\"\n :loading-text=\"loadingText\"\n @focus=\"onFocus\"\n @blur=\"onBlur\"\n @keydown=\"onKeydown\"\n @clear=\"onClear\"\n >\n <!--\n The buttons stay out of the tab order: the arrow keys do what they do, from the field. A\n press does not take the focus either, so the field keeps it while the value moves.\n -->\n <template v-if=\"controls === 'split'\" #start>\n <button\n type=\"button\"\n tabindex=\"-1\"\n class=\"v-field-action v-number-input-step\"\n :aria-label=\"decrementText\"\n :disabled=\"!editableField || atMin\"\n @mousedown.prevent\n @click=\"stepBy(-1)\"\n >\n <VIcon :name=\"removeIcon\" />\n </button>\n </template>\n <template v-if=\"controls === 'split'\" #value-end>\n <button\n type=\"button\"\n tabindex=\"-1\"\n class=\"v-field-action v-number-input-step\"\n :aria-label=\"incrementText\"\n :disabled=\"!editableField || atMax\"\n @mousedown.prevent\n @click=\"stepBy(1)\"\n >\n <VIcon :name=\"addIcon\" />\n </button>\n <VSeparator v-if=\"endControls\" orientation=\"vertical\" class=\"v-number-input-divider\" />\n </template>\n <template v-else-if=\"controls === 'stacked'\" #value-end>\n <span class=\"v-number-input-stack\">\n <button\n type=\"button\"\n tabindex=\"-1\"\n class=\"v-field-action v-number-input-step\"\n :aria-label=\"incrementText\"\n :disabled=\"!editableField || atMax\"\n @mousedown.prevent\n @click=\"stepBy(1)\"\n >\n <VIcon :name=\"expandLessIcon\" />\n </button>\n <button\n type=\"button\"\n tabindex=\"-1\"\n class=\"v-field-action v-number-input-step\"\n :aria-label=\"decrementText\"\n :disabled=\"!editableField || atMin\"\n @mousedown.prevent\n @click=\"stepBy(-1)\"\n >\n <VIcon :name=\"expandMoreIcon\" />\n </button>\n </span>\n </template>\n </VInput>\n <input\n v-if=\"formName\"\n ref=\"hiddenEl\"\n type=\"hidden\"\n :name=\"formName\"\n :form=\"formOwner\"\n :value=\"model ?? ''\"\n :disabled=\"resolvedDisabled\"\n />\n</template>\n\n<style>\n@layer vectis.components {\n .v-number-input .v-input-control {\n font-variant-numeric: tabular-nums;\n }\n\n /* Between a minus and a plus, the number reads as the thing they act on. */\n .v-number-input .v-input-control[data-controls='split'] {\n text-align: center;\n }\n\n /*\n * The rule between the plus button and the field's own controls, as VTimeInput draws after\n * AM/PM: icon height rather than the full height a vertical VSeparator stretches to, which\n * would read as a division of the box rather than a break in the row.\n */\n .v-separator[data-orientation='vertical'].v-number-input-divider {\n align-self: center;\n block-size: var(--control-action-size);\n }\n\n .v-number-input-step:disabled {\n color: var(--vectis-color-text-subtle);\n cursor: not-allowed;\n }\n\n /*\n * The stacked pair fills the field's height, set apart from the value by a divider. Each half\n * takes its icon size from the height it has: the field's, less its two 1px borders.\n */\n .v-number-input-stack {\n --vectis-icon-size: calc((var(--control-height) - 2px) / 2);\n\n display: flex;\n flex-direction: column;\n align-self: stretch;\n border-inline-start: 1px solid var(--vectis-color-border);\n }\n\n /*\n * Last in the field, the pair reaches over the field's padding to its end edge. Followed by the\n * clear cross or the spinner, it stays in the flow and a second divider sets it apart from them.\n */\n .v-number-input-stack:last-child {\n margin-inline-end: calc(-1 * var(--control-padding-inline-field));\n }\n\n .v-number-input-stack:not(:last-child) {\n border-inline-end: 1px solid var(--vectis-color-border);\n }\n\n .v-number-input-stack > .v-number-input-step {\n flex: 1 1 0;\n block-size: auto;\n inline-size: var(--control-action-size);\n margin: 0;\n border-radius: 0;\n }\n\n .v-number-input-stack > .v-number-input-step + .v-number-input-step {\n border-block-start: 1px solid var(--vectis-color-border);\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmGA,IAAM,IAAQ,GA0BR,IAAO,GAMP,IAAQ,EAA0B,GAAA,YAAkB,GAEpD,IAAI,EAAY,GAChB,IAAiB,QAAwB,EAAM,MAAM,GACrD,IAAgB,QAAe,EAAM,kBAAkB,EAAE,MAAM,YAAY,SAAS,GACpF,IAAgB,QAAe,EAAM,kBAAkB,EAAE,MAAM,YAAY,SAAS,GAGpF,EAAE,UAAU,MAAqB,EAAgB,GADzC,GAAO,IAAe,IAC0B,CAAK,GAM7D,IAAQ,EAAS,GACjB,IAAQ,QAAe,GAAe,GAAO,CAAC,QAAQ,MAAM,CAAC,CAAC,GAC9D,KAAa,QAAe,EAAM,MAAM,IAAI,GAC5C,IAAW,QAAe,EAAM,MAAM,OAAO,IAA0B,GACvE,KAAY,QAAe,EAAM,MAAM,OAAO,IAA0B,GAExE,IAAU,QAAe,EAAM,eAAe,UAAU,SAAS,GACjE,KAAa,QAAe,GAAiB,EAAe,KAAK,CAAC,GAClE,IAAgB,QACd,IAAI,KAAK,aAAa,EAAe,OAAO,EAAM,aAAa,CACvE,GAEM,IAAa,QAEf,IAAI,KAAK,aAAa,EAAe,OAAO;GAC1C,aAAa;GACb,uBAAuB;EACzB,CAAC,CACL,GAEM,KAAW,MAA0B,MAAU,OAAO,KAAK,EAAc,MAAM,OAAO,CAAK,GAC3F,MAAY,MAChB,MAAU,OAAO,KAAK,EAAW,MAAM,OAAO,EAAQ,QAAQ,EAAM,GAAO,GAAG,IAAI,CAAK;EAGzF,SAAS,IAA4B;GACnC,IAAM,IAAQ,EAAY,EAAK,OAAO,GAAW,KAAK;GACtD,OAAO,MAAU,QAAQ,OAAO,MAAM,CAAK,KAAK,CAAC,EAAQ,QAAQ,IAAQ,EAAM,GAAO,GAAI;EAC5F;EAEA,IAAM,IAAW,EAAwC,IAAI,GACvD,IAAW,EAA6B,IAAI,GAC5C,IAAU,EAAI,EAAK,GACnB,IAAO,EAAI,EAAQ,EAAM,KAAK,CAAC;EAErC,SAAS,IAAW;GAClB,EAAK,QAAQ,EAAQ,QAAQ,GAAS,EAAM,KAAK,IAAI,EAAQ,EAAM,KAAK;EAC1E;EAEA,GAAM;GAAC;GAAO;GAAe;EAAU,GAAG,CAAQ;EAElD,SAAS,EAAS,GAAsB;GAMtC,AALA,EAAM,QAAQ,GACd,EAAS,GAIL,EAAS,UAAO,EAAS,MAAM,QAAQ,MAAU,OAAO,KAAK,OAAO,CAAK;EAC/E;EAGA,SAAS,IAAS;GAChB,IAAM,IAAQ,EAAW;GACzB,AAAI,OAAO,MAAM,CAAK,IAAG,EAAS,IAC7B,EAAS,MAAU,OAAO,OAAO,EAAM,GAAO,EAAM,KAAK,EAAM,GAAG,CAAC;EAC1E;EAEA,IAAM,IAAgB,QAAe,CAAC,EAAiB,SAAS,CAAC,EAAM,QAAQ,GAKzE,KAAc,QACZ,EAAM,WAAW,GAAS,GAAO,EAAiB,OAAO,EAAK,UAAU,EAAE,CAClF,GACM,IAAQ,QACN,EAAM,UAAU,QAAQ,EAAM,QAAQ,KAAA,KAAa,EAAM,SAAS,EAAM,GAChF,GACM,IAAQ,QACN,EAAM,UAAU,QAAQ,EAAM,QAAQ,KAAA,KAAa,EAAM,SAAS,EAAM,GAChF;EAMA,SAAS,EAAO,GAAe;GAC7B,IAAI,CAAC,EAAc,OAAO;GAC1B,IAAM,IAAQ,EAAQ,QAAQ,EAAW,IAAI,EAAM,OAC7C,IAAU,MAAU,QAAQ,OAAO,MAAM,CAAK,IAAI,EAAM,QAAQ;GACtE,IAAI,MAAY,MAAM,OAAO,EAAS,EAAM,GAAG,EAAM,KAAK,EAAM,GAAG,CAAC;GAEpE,EAAS,EAAM,EAAU,GAAS,GADrB,EAAM,OAAO,IAAI,EAAM,OAAO,GACI,EAAM,OAAO,CAAC,GAAG,EAAM,KAAK,EAAM,GAAG,CAAC;EACvF;EAKA,SAAS,GAAU,GAAsB;GACvC,IAAI,EAAM,UAAU,EAAM,WAAW,EAAM,SAAS;GACpD,IAAM,IAAgC;IAAE,SAAS;IAAG,WAAW;IAAI,QAAQ;IAAI,UAAU;GAAI;GAC7F,AAAI,EAAM,OAAO,KACf,EAAM,eAAe,GACrB,EAAO,EAAM,EAAM,IAAK,KACf,EAAM,QAAQ,UAAU,EAAM,QAAQ,KAAA,KAAa,EAAc,SAC1E,EAAM,eAAe,GACrB,EAAS,EAAM,GAAG,KACT,EAAM,QAAQ,SAAS,EAAM,QAAQ,KAAA,KAAa,EAAc,SACzE,EAAM,eAAe,GACrB,EAAS,EAAM,GAAG,KACT,EAAM,QAAQ,WACvB,EAAO;EAEX;EAEA,SAAS,KAAU;GAEjB,AADA,EAAQ,QAAQ,IAChB,EAAS;EACX;EAEA,SAAS,KAAS;GAEhB,AADA,EAAQ,QAAQ,IAChB,EAAO;EACT;EAEA,SAAS,KAAU;GAEjB,AADA,EAAS,IAAI,GACb,EAAK,OAAO;EACd;SAEA,EAAa;GAEX,QAAQ,MAA2B,EAAS,OAAO,MAAM,CAAO;GAEhE,cAAc,EAAS,OAAO,OAAO;GAErC,IAAI,QAAe,EAAS,OAAO,MAAM,IAAI;EAC/C,CAAC,+BAIC,EA0FS,IA1FT,EA0FS;YAzFH;GAAJ,KAAI;eACK,EAAA;4CAAI,QAAA;GACb,OAAM;GACN,MAAK;GACL,WAAU;GACV,cAAa;GACZ,iBAAe,EAAA,SAAS,KAAA;GACxB,iBAAe,EAAA;GACf,iBAAe,EAAA;GACf,kBAAgB,EAAA,UAAK,OAAY,KAAA,IAAY,EAAQ,EAAA,KAAK;GAC1D,iBAAe,EAAA;KACR,GAAA,OAAU;GACjB,MAAM,EAAA;GACN,SAAS,EAAA;GACT,OAAO,EAAA;GACP,MAAM,EAAA;GACN,OAAO,EAAA;GACP,UAAU,EAAA;GACV,cAAY,EAAA;GACZ,kBAAgB,EAAA;GAChB,SAAS,EAAA;GACT,UAAU,EAAA;GACV,UAAU,EAAA;GACV,WAAW,EAAA;GACX,eAAa,EAAA;GACb,SAAS,EAAA;GACT,gBAAc,EAAA;GACP;GACD;GACG;GACF;oBAMQ,EAAA,aAAQ,UAAA;SAAe;eAW5B,CAVT,EAUS,UAAA;IATP,MAAK;IACL,UAAS;IACT,OAAM;IACL,cAAY,EAAA;IACZ,UAAQ,CAAG,EAAA,SAAiB,EAAA;IAC5B,aAAS,AAAA,EAAA,OAAA,QAAV,CAAA,GAAkB,CAAA,SAAA,CAAA;IACjB,SAAK,AAAA,EAAA,QAAA,MAAE,EAAM,EAAA;OAEd,EAA4B,GAAA,EAApB,MAAM,EAAA,CAAA,EAAU,GAAA,MAAA,GAAA,CAAA,MAAA,CAAA,CAAA,GAAA,IAAA,EAAA,CAAA,CAAA;;cAGZ,EAAA,aAAQ,UAAA;SAAe;eAW5B,CAVT,EAUS,UAAA;IATP,MAAK;IACL,UAAS;IACT,OAAM;IACL,cAAY,EAAA;IACZ,UAAQ,CAAG,EAAA,SAAiB,EAAA;IAC5B,aAAS,AAAA,EAAA,OAAA,QAAV,CAAA,GAAkB,CAAA,SAAA,CAAA;IACjB,SAAK,AAAA,EAAA,QAAA,MAAE,EAAM,CAAA;OAEd,EAAyB,GAAA,EAAjB,MAAM,EAAA,CAAA,EAAO,GAAA,MAAA,GAAA,CAAA,MAAA,CAAA,CAAA,GAAA,IAAA,EAAA,GAEL,GAAA,SAAA,EAAA,GAAlB,GAAuF,IAAA;;IAAxD,aAAY;IAAW,OAAM;;;MAEzC,EAAA,aAAQ,YAAA;SAAiB;eAwBrC,CAvBP,EAuBO,QAvBP,IAuBO,CAtBL,EAUS,UAAA;IATP,MAAK;IACL,UAAS;IACT,OAAM;IACL,cAAY,EAAA;IACZ,UAAQ,CAAG,EAAA,SAAiB,EAAA;IAC5B,aAAS,AAAA,EAAA,OAAA,QAAV,CAAA,GAAkB,CAAA,SAAA,CAAA;IACjB,SAAK,AAAA,EAAA,QAAA,MAAE,EAAM,CAAA;OAEd,EAAgC,GAAA,EAAxB,MAAM,EAAA,EAAA,EAAc,GAAA,MAAA,GAAA,CAAA,MAAA,CAAA,CAAA,GAAA,IAAA,EAAA,GAE9B,EAUS,UAAA;IATP,MAAK;IACL,UAAS;IACT,OAAM;IACL,cAAY,EAAA;IACZ,UAAQ,CAAG,EAAA,SAAiB,EAAA;IAC5B,aAAS,AAAA,EAAA,OAAA,QAAV,CAAA,GAAkB,CAAA,SAAA,CAAA;IACjB,SAAK,AAAA,EAAA,QAAA,MAAE,EAAM,EAAA;OAEd,EAAgC,GAAA,EAAxB,MAAM,EAAA,EAAA,EAAc,GAAA,MAAA,GAAA,CAAA,MAAA,CAAA,CAAA,GAAA,IAAA,EAAA,CAAA,CAAA,CAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;MAM5B,EAAA,SAAA,EAAA,GADR,EAQE,SAAA;;YANI;GAAJ,KAAI;GACJ,MAAK;GACJ,MAAM,EAAA;GACN,MAAM,GAAA;GACN,OAAO,EAAA,SAAK;GACZ,UAAU,EAAA,CAAA"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The arithmetic and the locale handling of VNumberInput, kept free of Vue: reading what was
|
|
3
|
+
* typed, writing a value back for editing, and stepping on a grid without floating-point drift.
|
|
4
|
+
*/
|
|
5
|
+
/** The two separators a locale writes numbers with: "1 234,5" in French, "1,234.5" in English. */
|
|
6
|
+
export interface NumberSeparators {
|
|
7
|
+
group: string;
|
|
8
|
+
decimal: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function numberSeparators(locale: string): NumberSeparators;
|
|
11
|
+
/**
|
|
12
|
+
* Reads a typed number: `null` for an empty field, `NaN` for text that is not a number.
|
|
13
|
+
*
|
|
14
|
+
* Group separators and any space are dropped, the locale's decimal separator becomes a point,
|
|
15
|
+
* and a point is also accepted as the decimal separator where the locale does not group with
|
|
16
|
+
* it. Currency, unit and percent symbols around the number are ignored, so a formatted value
|
|
17
|
+
* pasted back in reads as the number it shows.
|
|
18
|
+
*/
|
|
19
|
+
export declare function parseNumber(text: string, separators: NumberSeparators): number | null;
|
|
20
|
+
/** The number of decimals a value is written with: 0.25 has two, 1e-7 has seven. */
|
|
21
|
+
export declare function decimalsOf(value: number): number;
|
|
22
|
+
/** Multiplies by a power of ten without picking up drift: 0.07 × 100 is 7, not 7.000000000000001. */
|
|
23
|
+
export declare function scale(value: number, factor: number): number;
|
|
24
|
+
export declare function clamp(value: number, min: number | undefined, max: number | undefined): number;
|
|
25
|
+
/**
|
|
26
|
+
* Moves a value by a number of steps on the grid that starts at `base`. A value off the grid
|
|
27
|
+
* lands on the next grid line in the direction of travel first, as a native number input does:
|
|
28
|
+
* up from 1.5 by a step of 1 gives 2, not 2.5.
|
|
29
|
+
*/
|
|
30
|
+
export declare function stepValue(value: number, steps: number, step: number, base: number): number;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
//#region src/components/VNumberInput/number.ts
|
|
2
|
+
function e(e) {
|
|
3
|
+
let t = new Intl.NumberFormat(e).formatToParts(12345.6);
|
|
4
|
+
return {
|
|
5
|
+
group: t.find((e) => e.type === "group")?.value ?? "",
|
|
6
|
+
decimal: t.find((e) => e.type === "decimal")?.value ?? "."
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
var t = /[−‒–﹣-]/g, n = /^-?(\d+\.?\d*|\.\d+)$/;
|
|
10
|
+
function r(e, r) {
|
|
11
|
+
let i = e.trim();
|
|
12
|
+
if (!i) return null;
|
|
13
|
+
let a = i.replace(t, "-");
|
|
14
|
+
return r.group && (a = a.split(r.group).join("")), a = a.replace(/\s/g, ""), r.decimal !== "." && (a = a.split(r.decimal).join(".")), a = a.replace(/^(-?)[^\d.-]+/, "$1").replace(/[^\d.]+$/, ""), n.test(a) ? Number(a) : NaN;
|
|
15
|
+
}
|
|
16
|
+
function i(e) {
|
|
17
|
+
let t = String(e), n = t.indexOf("e-");
|
|
18
|
+
if (n >= 0) return Number(t.slice(n + 2)) + i(Number(t.slice(0, n)));
|
|
19
|
+
let r = t.indexOf(".");
|
|
20
|
+
return r < 0 ? 0 : t.length - r - 1;
|
|
21
|
+
}
|
|
22
|
+
function a(e, t) {
|
|
23
|
+
return Number(e.toFixed(Math.min(t, 100)));
|
|
24
|
+
}
|
|
25
|
+
function o(e, t) {
|
|
26
|
+
return Number((e * t).toPrecision(15));
|
|
27
|
+
}
|
|
28
|
+
function s(e, t, n) {
|
|
29
|
+
return n !== void 0 && e > n && (e = n), t !== void 0 && e < t && (e = t), e;
|
|
30
|
+
}
|
|
31
|
+
function c(e, t, n, r) {
|
|
32
|
+
let o = Math.max(i(n), i(r)), s = a((e - r) / n, 10);
|
|
33
|
+
return a(r + ((Number.isInteger(s) ? s : t > 0 ? Math.floor(s) : Math.ceil(s)) + t) * n, o);
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
export { s as clamp, i as decimalsOf, e as numberSeparators, r as parseNumber, o as scale, c as stepValue };
|
|
37
|
+
|
|
38
|
+
//# sourceMappingURL=number.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"number.js","names":[],"sources":["../../../src/components/VNumberInput/number.ts"],"sourcesContent":["// @core\n/**\n * The arithmetic and the locale handling of VNumberInput, kept free of Vue: reading what was\n * typed, writing a value back for editing, and stepping on a grid without floating-point drift.\n */\n\n/** The two separators a locale writes numbers with: \"1 234,5\" in French, \"1,234.5\" in English. */\nexport interface NumberSeparators {\n group: string\n decimal: string\n}\n\nexport function numberSeparators(locale: string): NumberSeparators {\n const parts = new Intl.NumberFormat(locale).formatToParts(12345.6)\n return {\n group: parts.find((part) => part.type === 'group')?.value ?? '',\n decimal: parts.find((part) => part.type === 'decimal')?.value ?? '.',\n }\n}\n\n/** The minus signs a keyboard or a paste can bring, besides the hyphen. */\nconst MINUS = /[−‒–﹣-]/g\n\n/** What a number may look like once separators and symbols are gone: \"-12\", \"3.\", \".5\". */\nconst PLAIN = /^-?(\\d+\\.?\\d*|\\.\\d+)$/\n\n/**\n * Reads a typed number: `null` for an empty field, `NaN` for text that is not a number.\n *\n * Group separators and any space are dropped, the locale's decimal separator becomes a point,\n * and a point is also accepted as the decimal separator where the locale does not group with\n * it. Currency, unit and percent symbols around the number are ignored, so a formatted value\n * pasted back in reads as the number it shows.\n */\nexport function parseNumber(text: string, separators: NumberSeparators): number | null {\n const trimmed = text.trim()\n if (!trimmed) return null\n let plain = trimmed.replace(MINUS, '-')\n if (separators.group) plain = plain.split(separators.group).join('')\n plain = plain.replace(/\\s/g, '')\n if (separators.decimal !== '.') plain = plain.split(separators.decimal).join('.')\n // Symbols are only stripped at either end, the minus kept before a leading one (\"-$5.00\"): a\n // letter between digits is a typo, and \"1o0\" read as 10 would be committed silently.\n plain = plain.replace(/^(-?)[^\\d.-]+/, '$1').replace(/[^\\d.]+$/, '')\n return PLAIN.test(plain) ? Number(plain) : Number.NaN\n}\n\n/** The number of decimals a value is written with: 0.25 has two, 1e-7 has seven. */\nexport function decimalsOf(value: number): number {\n const text = String(value)\n const exponent = text.indexOf('e-')\n if (exponent >= 0)\n return Number(text.slice(exponent + 2)) + decimalsOf(Number(text.slice(0, exponent)))\n const point = text.indexOf('.')\n return point < 0 ? 0 : text.length - point - 1\n}\n\n/** Rounds to a number of decimals, which is what removes the drift of 0.1 + 0.2. */\nfunction roundTo(value: number, decimals: number): number {\n return Number(value.toFixed(Math.min(decimals, 100)))\n}\n\n/** Multiplies by a power of ten without picking up drift: 0.07 × 100 is 7, not 7.000000000000001. */\nexport function scale(value: number, factor: number): number {\n return Number((value * factor).toPrecision(15))\n}\n\nexport function clamp(value: number, min: number | undefined, max: number | undefined): number {\n if (max !== undefined && value > max) value = max\n if (min !== undefined && value < min) value = min\n return value\n}\n\n/**\n * Moves a value by a number of steps on the grid that starts at `base`. A value off the grid\n * lands on the next grid line in the direction of travel first, as a native number input does:\n * up from 1.5 by a step of 1 gives 2, not 2.5.\n */\nexport function stepValue(value: number, steps: number, step: number, base: number): number {\n const decimals = Math.max(decimalsOf(step), decimalsOf(base))\n const position = roundTo((value - base) / step, 10)\n const onGrid = Number.isInteger(position)\n const from = onGrid ? position : steps > 0 ? Math.floor(position) : Math.ceil(position)\n return roundTo(base + (from + steps) * step, decimals)\n}\n"],"mappings":";AAYA,SAAgB,EAAiB,GAAkC;CACjE,IAAM,IAAQ,IAAI,KAAK,aAAa,CAAM,CAAC,CAAC,cAAc,OAAO;CACjE,OAAO;EACL,OAAO,EAAM,MAAM,MAAS,EAAK,SAAS,OAAO,CAAC,EAAE,SAAS;EAC7D,SAAS,EAAM,MAAM,MAAS,EAAK,SAAS,SAAS,CAAC,EAAE,SAAS;CACnE;AACF;AAGA,IAAM,IAAQ,YAGR,IAAQ;AAUd,SAAgB,EAAY,GAAc,GAA6C;CACrF,IAAM,IAAU,EAAK,KAAK;CAC1B,IAAI,CAAC,GAAS,OAAO;CACrB,IAAI,IAAQ,EAAQ,QAAQ,GAAO,GAAG;CAOtC,OANI,EAAW,UAAO,IAAQ,EAAM,MAAM,EAAW,KAAK,CAAC,CAAC,KAAK,EAAE,IACnE,IAAQ,EAAM,QAAQ,OAAO,EAAE,GAC3B,EAAW,YAAY,QAAK,IAAQ,EAAM,MAAM,EAAW,OAAO,CAAC,CAAC,KAAK,GAAG,IAGhF,IAAQ,EAAM,QAAQ,iBAAiB,IAAI,CAAC,CAAC,QAAQ,YAAY,EAAE,GAC5D,EAAM,KAAK,CAAK,IAAI,OAAO,CAAK,IAAI;AAC7C;AAGA,SAAgB,EAAW,GAAuB;CAChD,IAAM,IAAO,OAAO,CAAK,GACnB,IAAW,EAAK,QAAQ,IAAI;CAClC,IAAI,KAAY,GACd,OAAO,OAAO,EAAK,MAAM,IAAW,CAAC,CAAC,IAAI,EAAW,OAAO,EAAK,MAAM,GAAG,CAAQ,CAAC,CAAC;CACtF,IAAM,IAAQ,EAAK,QAAQ,GAAG;CAC9B,OAAO,IAAQ,IAAI,IAAI,EAAK,SAAS,IAAQ;AAC/C;AAGA,SAAS,EAAQ,GAAe,GAA0B;CACxD,OAAO,OAAO,EAAM,QAAQ,KAAK,IAAI,GAAU,GAAG,CAAC,CAAC;AACtD;AAGA,SAAgB,EAAM,GAAe,GAAwB;CAC3D,OAAO,QAAQ,IAAQ,EAAA,CAAQ,YAAY,EAAE,CAAC;AAChD;AAEA,SAAgB,EAAM,GAAe,GAAyB,GAAiC;CAG7F,OAFI,MAAQ,KAAA,KAAa,IAAQ,MAAK,IAAQ,IAC1C,MAAQ,KAAA,KAAa,IAAQ,MAAK,IAAQ,IACvC;AACT;AAOA,SAAgB,EAAU,GAAe,GAAe,GAAc,GAAsB;CAC1F,IAAM,IAAW,KAAK,IAAI,EAAW,CAAI,GAAG,EAAW,CAAI,CAAC,GACtD,IAAW,GAAS,IAAQ,KAAQ,GAAM,EAAE;CAGlD,OAAO,EAAQ,MAFA,OAAO,UAAU,CACnB,IAAS,IAAW,IAAQ,IAAI,KAAK,MAAM,CAAQ,IAAI,KAAK,KAAK,CAAQ,KACxD,KAAS,GAAM,CAAQ;AACvD"}
|
|
@@ -141,10 +141,10 @@ declare const __VLS_export: import('vue').DefineComponent<__VLS_PublicProps, {
|
|
|
141
141
|
size: PaginationSize;
|
|
142
142
|
length: number;
|
|
143
143
|
tone: PaginationTone;
|
|
144
|
-
elevated: boolean;
|
|
145
144
|
compact: boolean;
|
|
146
145
|
href: (page: number) => string;
|
|
147
146
|
disabled: boolean;
|
|
147
|
+
elevated: boolean;
|
|
148
148
|
detached: boolean;
|
|
149
149
|
bordered: boolean;
|
|
150
150
|
totalVisible: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VPagination.js","names":[],"sources":["../../../src/components/VPagination/VPagination.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @keyboard @core\n/**\n * Native buttons activate pages. JavaScript builds bounded page windows and provides roving\n * keyboard navigation.\n */\nimport { computed, h, nextTick, ref } from 'vue'\nimport type { FunctionalComponent } from 'vue'\n\nimport VButton from '../VButton/VButton.vue'\nimport VButtonGroup from '../VButton/VButtonGroup.vue'\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport { chevron_left as chevronLeftIcon } from '../VIcon/icons/chevron_left'\nimport { chevron_right as chevronRightIcon } from '../VIcon/icons/chevron_right'\nimport { first_page as firstPageIcon } from '../VIcon/icons/first_page'\nimport { last_page as lastPageIcon } from '../VIcon/icons/last_page'\nimport { more_horiz as moreHorizIcon } from '../VIcon/icons/more_horiz'\nimport type { IconSource } from '../VIcon/types'\nimport VIconButton from '../VIconButton/VIconButton.vue'\n\nimport { arrowNavigate, navigableItems } from '../../utils/arrowNav'\nimport { clamp } from '../../utils/number'\nimport { resolveMatcher } from '../../utils/matcher'\n\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useMessages } from '../../i18n/state'\n\n/** How the pages that are not the current one are drawn. */\nexport type PaginationItemVariant = 'ghost' | 'outline'\n\n/** How the current page is drawn. */\nexport type PaginationSelectedVariant = 'solid' | 'soft' | 'ghost'\n\n/** The colour of the current page. */\nexport type PaginationTone = 'accent' | 'neutral' | 'danger'\n\n/** The height of the pills, from the scale every control shares. */\nexport type PaginationSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'\n\n/** Where the row sits in the width it is given. */\nexport type PaginationAlign = 'start' | 'center' | 'end'\n\n/** Whether the previous and next controls are rendered, and what they show. */\nexport type PaginationControls = false | 'icon' | 'text' | 'both'\n\n/**\n * Which pages cannot be reached, given either as a list of page numbers or as a function\n * answering that question for a page.\n */\nexport type PaginationMatcher = number[] | ((page: number) => boolean)\n\ninterface PaginationProps {\n /**\n * How many pages there are in all. It is 1 by default, which renders a single page: the\n * real count almost always has to be given.\n */\n length?: number\n /**\n * How many slots to render, ellipses counted among them, so the row keeps exactly the same\n * width whichever page is current. Below 5, the row drops the bounds and the ellipses and\n * shows that many consecutive pages around the current one. At 0, no page is rendered and the\n * controls alone remain. Left out, every page is rendered.\n */\n totalVisible?: number\n\n /**\n * Separates the buttons instead of joining them into one segmented control. It is the\n * word VButtonGroup and VToggle use for the same question, in the same direction.\n */\n detached?: boolean\n /**\n * Draws a line between the joined buttons, so the row reads as segments rather than as one\n * frame, on the terms of VButtonGroup's own `bordered`. It has no effect under `detached`.\n */\n bordered?: boolean\n /**\n * How the pages OTHER than the current one, and the controls, are drawn. It is named for the\n * ITEMS because that is what it paints: on VTabs and VDataTable `variant` names the\n * decoration of the frame instead.\n */\n itemVariant?: PaginationItemVariant\n /**\n * How the current page is drawn, in the row's tone: filled, tinted, or the colour of its\n * text alone. The same choice as VToggle's `selectedVariant`.\n */\n selectedVariant?: PaginationSelectedVariant\n /** The colour the current page takes. The other pages and the controls stay neutral. */\n tone?: PaginationTone\n /** The height of the buttons, from the scale shared by every control. */\n size?: PaginationSize\n /** Takes 4px off the height of every button. */\n compact?: boolean\n /** Raises the row off the page, on the terms of VButton's own `elevated`. */\n elevated?: boolean\n /** Where the row sits in the width it is given. */\n align?: PaginationAlign\n\n /**\n * The previous and next buttons on either side of the pages: what they show, or `false` to\n * leave them out.\n */\n controls?: PaginationControls\n /** The icon of the previous control: an icon name, or an explicit render. */\n prevIcon?: IconSource\n /** The icon of the next control: an icon name, or an explicit render. */\n nextIcon?: IconSource\n /**\n * The wording of the previous control, used both as its visible text and as what\n * screen readers announce. It falls back to the design system dictionary.\n */\n prevText?: string\n /**\n * The wording of the next control, used both as its visible text and as what screen\n * readers announce. It falls back to the design system dictionary.\n */\n nextText?: string\n /**\n * Adds first and last page controls outside the previous and next ones, drawn the way\n * `controls` draws those. It has no effect when `controls` is `false`.\n */\n edgeControls?: boolean\n /** The icon of the first page control: an icon name, or an explicit render. */\n firstIcon?: IconSource\n /** The icon of the last page control: an icon name, or an explicit render. */\n lastIcon?: IconSource\n /**\n * The wording of the first page control, used both as its visible text and as what\n * screen readers announce. It falls back to the design system dictionary.\n */\n firstText?: string\n /**\n * The wording of the last page control, used both as its visible text and as what\n * screen readers announce. It falls back to the design system dictionary.\n */\n lastText?: string\n\n /** Makes the whole component unusable. */\n disabled?: boolean\n /**\n * Which pages cannot be reached, as a list or as a function. The previous and next\n * controls step OVER them rather than stopping at one.\n */\n disabledPages?: PaginationMatcher\n\n /**\n * What screen readers announce for the navigation itself. It falls back to the\n * design system dictionary.\n */\n label?: string\n /**\n * How a page is announced. A pill shows a bare number, which alone means nothing to\n * a screen reader: this is what turns it into \"Page 3\". It falls back to the design\n * system dictionary.\n */\n pageLabel?: (page: number) => string\n /** The address of a page. Left out, they are buttons. */\n href?: (page: number) => string\n}\n\nconst props = withDefaults(defineProps<PaginationProps>(), {\n length: 1,\n totalVisible: undefined,\n detached: false,\n bordered: false,\n itemVariant: 'ghost',\n selectedVariant: 'solid',\n tone: 'accent',\n size: 'md',\n compact: false,\n elevated: false,\n align: 'start',\n controls: 'icon',\n prevIcon: () => chevronLeftIcon,\n nextIcon: () => chevronRightIcon,\n prevText: undefined,\n nextText: undefined,\n edgeControls: false,\n firstIcon: () => firstPageIcon,\n lastIcon: () => lastPageIcon,\n firstText: undefined,\n lastText: undefined,\n disabled: false,\n disabledPages: undefined,\n label: undefined,\n pageLabel: undefined,\n href: undefined,\n})\n\nconst emit = defineEmits<{\n /**\n * A page was chosen from the row, a pill or a control, with the click that chose it. It comes\n * before the model changes, so under `href` a single-page application calls\n * `preventDefault()` on the event and hands the address to its router instead of letting the\n * browser load it.\n */\n navigate: [page: number, event: MouseEvent]\n}>()\n\n// The prop wins over the dictionary, and above both, a consumer's own aria-label or\n// aria-labelledby still wins; that arbitration is what `useAriaLabel` is for.\nconst m = useMessages()\nconst ariaLabel = useAriaLabel(() => props.label ?? m.value.pagination.label)\nconst resolvedPrevText = computed(() => props.prevText ?? m.value.pagination.previous)\nconst resolvedNextText = computed(() => props.nextText ?? m.value.pagination.next)\nconst resolvedFirstText = computed(() => props.firstText ?? m.value.pagination.first)\nconst resolvedLastText = computed(() => props.lastText ?? m.value.pagination.last)\n\n/** The page being shown, counted from 1. It starts on the first. */\nconst page = defineModel<number>({ default: 1 })\n\n/** One slot in the row: either a page, or the ellipsis standing for those left out. */\ntype PaginationItem = { kind: 'page'; key: string; page: number } | { kind: 'gap'; key: string }\n\n// A length or a model that is not a whole number (`NaN` while a page size is still loading,\n// a computed `2.5`) is brought back to a page that exists, or no pill would ever match it.\nconst total = computed(() => Math.max(Math.trunc(props.length) || 1, 1))\nconst currentPage = computed(() => clamp(Math.round(page.value) || 1, 1, total.value))\n\nconst isPageDisabled = computed(() => resolveMatcher(props.disabledPages))\n\n// @a11y\n// A pill shows nothing but a number, which on its own tells a screen reader\n// nothing at all; this is what has it announced as \"Page 3\".\nfunction pageLabelFor(n: number): string {\n return props.pageLabel ? props.pageLabel(n) : m.value.pagination.page(n)\n}\n\n/** Works out which slots the row holds. */\nconst items = computed<PaginationItem[]>(() => {\n const count = total.value\n const current = currentPage.value\n\n const pageItem = (n: number): PaginationItem => ({ kind: 'page', key: `page-${n}`, page: n })\n const pages = (from: number, to: number): PaginationItem[] => {\n const out: PaginationItem[] = []\n for (let n = from; n <= to; n++) out.push(pageItem(n))\n return out\n }\n // Keyed by the side it stands on, never by the page it follows: there is at most one\n // ellipsis per side, and the left one always comes after the first page while the right\n // one always comes before the last. A key derived from the window would change on every\n // navigation, so the right-hand ellipsis would be destroyed and rebuilt each time the\n // window slid, for a node that never changes.\n const gap = (side: 'start' | 'end'): PaginationItem => ({ kind: 'gap', key: `gap-${side}` })\n\n // With no limit given, nothing is left out. At 0 the row holds the controls alone.\n const limit = Math.trunc(props.totalVisible ?? count)\n const visible = Number.isNaN(limit) ? count : Math.max(limit, 0)\n if (visible === 0) return []\n if (visible >= count) return pages(1, count)\n\n // Below five slots there is no room for the first page, an ellipsis, the current page,\n // another ellipsis and the last: the row is a plain window of consecutive pages, held\n // against the bounds so it keeps the same number of slots.\n if (visible < 5) {\n const from = clamp(current - Math.floor((visible - 1) / 2), 1, count - visible + 1)\n return pages(from, from + visible - 1)\n }\n\n const start = current - Math.floor((visible - 5) / 2)\n const end = start + (visible - 5)\n\n // The window is stretched to the bound instead, which both avoids that and keeps the number\n // of slots exactly the same.\n if (start <= 3) return [...pages(1, visible - 2), gap('end'), pageItem(count)]\n if (end >= count - 2) return [pageItem(1), gap('start'), ...pages(count - visible + 3, count)]\n return [pageItem(1), gap('start'), ...pages(start, end), gap('end'), pageItem(count)]\n})\n\n/**\n * Where a control leads: the nearest page in that direction that can actually be reached,\n * disabled ones being stepped over rather than stopped at. Answering `undefined` means there is\n * none left, which disables the control; and that single answer also covers being on the first\n * or the last page, with no separate test for the ends.\n */\nfunction step(direction: -1 | 1): number | undefined {\n for (let n = currentPage.value + direction; n >= 1 && n <= total.value; n += direction) {\n if (!isPageDisabled.value(n)) return n\n }\n return undefined\n}\n\n/**\n * Where a first or last control leads: the reachable page farthest in that direction. It is\n * `undefined` exactly when `step` is, so each edge control disables itself with its neighbour.\n */\nfunction leap(direction: -1 | 1): number | undefined {\n const end = direction < 0 ? 1 : total.value\n for (let n = end; n !== currentPage.value; n -= direction) {\n if (!isPageDisabled.value(n)) return n\n }\n return undefined\n}\n\nconst firstTarget = computed(() => leap(-1))\nconst prevTarget = computed(() => step(-1))\nconst nextTarget = computed(() => step(1))\nconst lastTarget = computed(() => leap(1))\n\nfunction goTo(n: number | undefined) {\n if (n === undefined) return\n page.value = clamp(n, 1, total.value)\n}\n\n/** The address a pill or a control links to, or `undefined` when the row is made of buttons. */\nfunction hrefFor(n: number): string | undefined {\n return props.href?.(n)\n}\n\n// @core\n/*\n * A link clicked with a modifier held (Ctrl or Cmd for a new tab, Shift for a window, Alt for a\n * download) opens somewhere ELSE: the page on screen stays where it is, so the model must not\n * move. The test the routers themselves make before taking a click over.\n */\nfunction opensElsewhere(event: MouseEvent): boolean {\n return (\n props.href !== undefined &&\n (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey)\n )\n}\n\nfunction choose(event: MouseEvent, n: number | undefined) {\n if (n === undefined || opensElsewhere(event)) return\n emit('navigate', n, event)\n goTo(n)\n}\n\nfunction isUnusable(el: HTMLElement): boolean {\n return el.matches(':disabled, [aria-disabled=\"true\"]')\n}\n\n// @a11y\n/*\n * The previous and next controls disable themselves once no page is left in their direction,\n * and a focused button that becomes disabled hands the focus to <body>: a keyboard reader\n * pressing \"Next page\" on the second to last page would be sent back to the top of the document\n * by the next Tab. The focus goes to the page just reached instead, the current page being\n * always rendered. A row without pages hands it to the nearest control still usable, the one\n * before it first.\n */\nasync function goFromControl(event: MouseEvent, n: number | undefined) {\n const control = event.currentTarget as HTMLElement\n const hadFocus = control === document.activeElement\n choose(event, n)\n if (!hadFocus) return\n await nextTick()\n const nav = navEl.value\n if (!nav || !isUnusable(control)) return\n const current = nav.querySelector<HTMLElement>('[aria-current=\"page\"]')\n if (current) return current.focus()\n const usable = [...nav.querySelectorAll<HTMLElement>(':is(button, a[href]):not(:disabled)')]\n const before = usable.filter(\n (el) => control.compareDocumentPosition(el) & Node.DOCUMENT_POSITION_PRECEDING,\n )\n ;(before.at(-1) ?? usable[0])?.focus()\n}\n\ntype ControlSide = 'first' | 'prev' | 'next' | 'last'\n\n/*\n * The four controls, written once: they differ only by their direction and reach, and template\n * blocks drifting apart on the next change is exactly what this avoids. A functional component\n * because they sit at either end of the row, with the pages in between, where a `v-for` over\n * descriptors could not put them.\n */\nconst PageControl: FunctionalComponent<{ side: ControlSide }> = ({ side }) => {\n const { label, icon, target } = {\n first: { label: resolvedFirstText.value, icon: props.firstIcon, target: firstTarget.value },\n prev: { label: resolvedPrevText.value, icon: props.prevIcon, target: prevTarget.value },\n next: { label: resolvedNextText.value, icon: props.nextIcon, target: nextTarget.value },\n last: { label: resolvedLastText.value, icon: props.lastIcon, target: lastTarget.value },\n }[side]\n const disabled = props.disabled || target === undefined\n const common = {\n class: 'v-pagination-control',\n 'data-side': side,\n variant: props.itemVariant,\n disabled,\n href: hrefFor(target ?? currentPage.value),\n rel: props.href && !disabled ? side : undefined,\n onClick: (event: MouseEvent) => goFromControl(event, target),\n }\n const glyph = () => h(VIcon, { ...iconProps(icon), mirrored: true })\n if (props.controls === 'icon') return h(VIconButton, { ...common, label }, glyph)\n const backward = side === 'first' || side === 'prev'\n return h(\n VButton,\n { ...common, tone: 'neutral' },\n {\n ...(props.controls === 'both' ? { [backward ? 'start' : 'end']: glyph } : {}),\n default: () => h('span', { class: 'v-pagination-control-label' }, label),\n },\n )\n}\n\nconst navEl = ref<HTMLElement | null>(null)\n\n// @keyboard @a11y\n/** The arrow keys, through the shared implementation in `utils/arrowNav`. */\nfunction onKeydown(event: KeyboardEvent) {\n const nav = navEl.value\n if (!nav) return\n arrowNavigate(event, nav, () =>\n navigableItems(nav, '.v-pagination-page:not(:disabled, [aria-disabled=\"true\"])'),\n )\n}\n\n// The pills are rendered by a VButtonGroup inside the nav, so a template ref reaches none of\n// them. `focus` goes to the current page.\ndefineExpose({\n // Two queries, not one selector list: a list matches in DOM order, which would hand the\n // focus to the previous control ahead of the current page. `a[href]` because an inert link\n // has lost its address, and with it the ability to take the focus.\n /** Moves the focus to the current page, or to the first control that can take it. */\n focus: (options?: FocusOptions) =>\n (\n navEl.value?.querySelector<HTMLElement>(\n '[aria-current=\"page\"]:is(button, a[href]):not(:disabled)',\n ) ?? navEl.value?.querySelector<HTMLElement>(':is(button, a[href]):not(:disabled)')\n )?.focus(options),\n /** The `<nav>` element, which is also where the consumer's attributes land. */\n el: navEl,\n})\n</script>\n\n<template>\n <nav\n ref=\"navEl\"\n class=\"v-pagination\"\n :aria-label=\"ariaLabel\"\n :data-align=\"align\"\n :data-item-variant=\"itemVariant\"\n @keydown=\"onKeydown\"\n >\n <!-- The row is a VButtonGroup either way: joined it merges the borders of its DIRECT\n button children, and detached it spaces them, which is all this prop asks of it.\n That is why there is no list markup wrapping the pills, and why the ellipsis is\n itself an inert button rather than a plain span: anything else between two pills\n would break the seam. -->\n <!--\n `|| undefined` keeps the group opinion-free when the row does not ask, `undefined` being\n what means \"no opinion\" there where `false` is an order. The size is always an opinion,\n the pagination having a default of its own.\n -->\n <VButtonGroup\n class=\"v-pagination-items\"\n :detached=\"detached\"\n :bordered=\"bordered\"\n :size=\"size\"\n :compact=\"compact || undefined\"\n :elevated=\"elevated || undefined\"\n >\n <PageControl v-if=\"controls && edgeControls\" side=\"first\" />\n <PageControl v-if=\"controls\" side=\"prev\" />\n\n <template v-for=\"item in items\" :key=\"item.key\">\n <VButton\n v-if=\"item.kind === 'page'\"\n class=\"v-pagination-page\"\n :variant=\"item.page === currentPage ? selectedVariant : itemVariant\"\n :tone=\"item.page === currentPage ? tone : 'neutral'\"\n :disabled=\"disabled || isPageDisabled(item.page)\"\n :aria-label=\"pageLabelFor(item.page)\"\n :aria-current=\"item.page === currentPage ? 'page' : undefined\"\n :href=\"hrefFor(item.page)\"\n @click=\"choose($event, item.page)\"\n >\n {{ item.page }}\n </VButton>\n <!--\n The ellipsis is a disabled icon-only button rather than a span: being a button, it\n keeps the joined row's seam continuous and follows the size and density like\n everything else. Disabling it takes it out of the tab order, and it is hidden from\n screen readers, which have the page numbers themselves; which is also why it is a\n VButton and not a VIconButton, whose required label would name something nobody can\n reach.\n -->\n <VButton\n v-else\n class=\"v-pagination-ellipsis\"\n aria-hidden=\"true\"\n data-icon-only\n :variant=\"itemVariant\"\n tone=\"neutral\"\n disabled\n >\n <template #start>\n <VIcon :name=\"moreHorizIcon\" />\n </template>\n </VButton>\n </template>\n\n <PageControl v-if=\"controls\" side=\"next\" />\n <PageControl v-if=\"controls && edgeControls\" side=\"last\" />\n </VButtonGroup>\n </nav>\n</template>\n\n<style>\n@layer vectis.components {\n .v-pagination {\n display: flex;\n }\n\n .v-pagination[data-align='center'] {\n justify-content: center;\n }\n\n .v-pagination[data-align='end'] {\n justify-content: flex-end;\n }\n\n /*\n * Qualified by an attribute VButton always renders, which makes both of these beat that\n * button's own padding and its own transition whatever order the two sheets end up in; the\n * VIconButton idiom.\n */\n .v-pagination-page[data-size] {\n /* A one-digit pill is square, and widens by itself past that. The height variable\n is set by the shared size class on this very element, so this single rule covers\n all five sizes and their compact forms. */\n min-inline-size: var(--control-height);\n padding-inline: var(--vectis-space-2);\n\n /*\n * The highlight changes instantly, and this must not be \"restored for consistency\". VButton\n * fades `background-color` over `--vectis-duration-fast`, which is right for a button that\n * stays put and wrong here: truncation SHIFTS its window, so from one page to the next the\n * highlight keeps its slot but changes ELEMENT, and the outgoing and incoming pills are\n * both half-tinted for a few frames; read as a flicker, with nothing in the console.\n */\n transition: none;\n }\n\n /* The ellipsis is a disabled button only as a technical device; to the reader it is\n not a control that has been turned off, so it does not take the forbidden\n cursor. Qualified like the pills: VButton's disabled cursor weighs (0,2,0), and a bare\n class loses to it whatever the sheet order. */\n .v-pagination-ellipsis[data-size] {\n cursor: default;\n }\n\n /*\n * A disabled page or control greys its outline to a different token, hence a variable the\n * second rule changes. VToggle's `--toggle-frame` is the same device.\n */\n .v-pagination[data-item-variant='outline'] {\n --pagination-frame: var(--vectis-color-border-strong);\n }\n\n .v-pagination[data-item-variant='outline'] > * > :is(:disabled, [aria-disabled='true']) {\n --pagination-frame: var(--vectis-color-border);\n }\n\n .v-pagination[data-item-variant='outline']\n > *\n > .v-pagination-page[aria-current='page']:is([data-variant='soft'], [data-variant='ghost']) {\n border-color: var(--pagination-frame);\n }\n\n /*\n * The class is repeated to reach (0,6,0). The variant, hover and active rules reach (0,5,0),\n * and with the forcing turned off any of them that still won would paint its tone over the\n * selection, with HighlightText on top of it.\n */\n @media (forced-colors: active) {\n .v-pagination-page.v-pagination-page.v-pagination-page.v-pagination-page[aria-current='page']:not(\n :disabled,\n [aria-disabled='true']\n ) {\n forced-color-adjust: none;\n background-color: Highlight;\n color: HighlightText;\n border-color: Highlight;\n outline-color: CanvasText;\n }\n }\n}\n</style>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"VPagination.js","names":[],"sources":["../../../src/components/VPagination/VPagination.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @keyboard @core\n/**\n * Native buttons activate pages. JavaScript builds bounded page windows and provides roving\n * keyboard navigation.\n */\nimport { computed, h, nextTick, ref } from 'vue'\nimport type { FunctionalComponent } from 'vue'\n\nimport VButton from '../VButton/VButton.vue'\nimport VButtonGroup from '../VButton/VButtonGroup.vue'\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport { chevron_left as chevronLeftIcon } from '../VIcon/icons/chevron_left'\nimport { chevron_right as chevronRightIcon } from '../VIcon/icons/chevron_right'\nimport { first_page as firstPageIcon } from '../VIcon/icons/first_page'\nimport { last_page as lastPageIcon } from '../VIcon/icons/last_page'\nimport { more_horiz as moreHorizIcon } from '../VIcon/icons/more_horiz'\nimport type { IconSource } from '../VIcon/types'\nimport VIconButton from '../VIconButton/VIconButton.vue'\n\nimport { arrowNavigate, navigableItems } from '../../utils/arrowNav'\nimport { clamp } from '../../utils/number'\nimport { resolveMatcher } from '../../utils/matcher'\n\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useMessages } from '../../i18n/state'\n\n/** How the pages that are not the current one are drawn. */\nexport type PaginationItemVariant = 'ghost' | 'outline'\n\n/** How the current page is drawn. */\nexport type PaginationSelectedVariant = 'solid' | 'soft' | 'ghost'\n\n/** The colour of the current page. */\nexport type PaginationTone = 'accent' | 'neutral' | 'danger'\n\n/** The height of the pills, from the scale every control shares. */\nexport type PaginationSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'\n\n/** Where the row sits in the width it is given. */\nexport type PaginationAlign = 'start' | 'center' | 'end'\n\n/** Whether the previous and next controls are rendered, and what they show. */\nexport type PaginationControls = false | 'icon' | 'text' | 'both'\n\n/**\n * Which pages cannot be reached, given either as a list of page numbers or as a function\n * answering that question for a page.\n */\nexport type PaginationMatcher = number[] | ((page: number) => boolean)\n\ninterface PaginationProps {\n /**\n * How many pages there are in all. It is 1 by default, which renders a single page: the\n * real count almost always has to be given.\n */\n length?: number\n /**\n * How many slots to render, ellipses counted among them, so the row keeps exactly the same\n * width whichever page is current. Below 5, the row drops the bounds and the ellipses and\n * shows that many consecutive pages around the current one. At 0, no page is rendered and the\n * controls alone remain. Left out, every page is rendered.\n */\n totalVisible?: number\n\n /**\n * Separates the buttons instead of joining them into one segmented control. It is the\n * word VButtonGroup and VToggle use for the same question, in the same direction.\n */\n detached?: boolean\n /**\n * Draws a line between the joined buttons, so the row reads as segments rather than as one\n * frame, on the terms of VButtonGroup's own `bordered`. It has no effect under `detached`.\n */\n bordered?: boolean\n /**\n * How the pages OTHER than the current one, and the controls, are drawn. It is named for the\n * ITEMS because that is what it paints: on VTabs and VDataTable `variant` names the\n * decoration of the frame instead.\n */\n itemVariant?: PaginationItemVariant\n /**\n * How the current page is drawn, in the row's tone: filled, tinted, or the colour of its\n * text alone. The same choice as VToggle's `selectedVariant`.\n */\n selectedVariant?: PaginationSelectedVariant\n /** The colour the current page takes. The other pages and the controls stay neutral. */\n tone?: PaginationTone\n /** The height of the buttons, from the scale shared by every control. */\n size?: PaginationSize\n /** Takes 4px off the height of every button. */\n compact?: boolean\n /** Raises the row off the page, on the terms of VButton's own `elevated`. */\n elevated?: boolean\n /** Where the row sits in the width it is given. */\n align?: PaginationAlign\n\n /**\n * The previous and next buttons on either side of the pages: what they show, or `false` to\n * leave them out.\n */\n controls?: PaginationControls\n /** The icon of the previous control: an icon name, or an explicit render. */\n prevIcon?: IconSource\n /** The icon of the next control: an icon name, or an explicit render. */\n nextIcon?: IconSource\n /**\n * The wording of the previous control, used both as its visible text and as what\n * screen readers announce. It falls back to the design system dictionary.\n */\n prevText?: string\n /**\n * The wording of the next control, used both as its visible text and as what screen\n * readers announce. It falls back to the design system dictionary.\n */\n nextText?: string\n /**\n * Adds first and last page controls outside the previous and next ones, drawn the way\n * `controls` draws those. It has no effect when `controls` is `false`.\n */\n edgeControls?: boolean\n /** The icon of the first page control: an icon name, or an explicit render. */\n firstIcon?: IconSource\n /** The icon of the last page control: an icon name, or an explicit render. */\n lastIcon?: IconSource\n /**\n * The wording of the first page control, used both as its visible text and as what\n * screen readers announce. It falls back to the design system dictionary.\n */\n firstText?: string\n /**\n * The wording of the last page control, used both as its visible text and as what\n * screen readers announce. It falls back to the design system dictionary.\n */\n lastText?: string\n\n /** Makes the whole component unusable. */\n disabled?: boolean\n /**\n * Which pages cannot be reached, as a list or as a function. The previous and next\n * controls step OVER them rather than stopping at one.\n */\n disabledPages?: PaginationMatcher\n\n /**\n * What screen readers announce for the navigation itself. It falls back to the\n * design system dictionary.\n */\n label?: string\n /**\n * How a page is announced. A pill shows a bare number, which alone means nothing to\n * a screen reader: this is what turns it into \"Page 3\". It falls back to the design\n * system dictionary.\n */\n pageLabel?: (page: number) => string\n /** The address of a page. Left out, they are buttons. */\n href?: (page: number) => string\n}\n\nconst props = withDefaults(defineProps<PaginationProps>(), {\n length: 1,\n totalVisible: undefined,\n detached: false,\n bordered: false,\n itemVariant: 'outline',\n selectedVariant: 'solid',\n tone: 'accent',\n size: 'md',\n compact: false,\n elevated: false,\n align: 'start',\n controls: 'icon',\n prevIcon: () => chevronLeftIcon,\n nextIcon: () => chevronRightIcon,\n prevText: undefined,\n nextText: undefined,\n edgeControls: false,\n firstIcon: () => firstPageIcon,\n lastIcon: () => lastPageIcon,\n firstText: undefined,\n lastText: undefined,\n disabled: false,\n disabledPages: undefined,\n label: undefined,\n pageLabel: undefined,\n href: undefined,\n})\n\nconst emit = defineEmits<{\n /**\n * A page was chosen from the row, a pill or a control, with the click that chose it. It comes\n * before the model changes, so under `href` a single-page application calls\n * `preventDefault()` on the event and hands the address to its router instead of letting the\n * browser load it.\n */\n navigate: [page: number, event: MouseEvent]\n}>()\n\n// The prop wins over the dictionary, and above both, a consumer's own aria-label or\n// aria-labelledby still wins; that arbitration is what `useAriaLabel` is for.\nconst m = useMessages()\nconst ariaLabel = useAriaLabel(() => props.label ?? m.value.pagination.label)\nconst resolvedPrevText = computed(() => props.prevText ?? m.value.pagination.previous)\nconst resolvedNextText = computed(() => props.nextText ?? m.value.pagination.next)\nconst resolvedFirstText = computed(() => props.firstText ?? m.value.pagination.first)\nconst resolvedLastText = computed(() => props.lastText ?? m.value.pagination.last)\n\n/** The page being shown, counted from 1. It starts on the first. */\nconst page = defineModel<number>({ default: 1 })\n\n/** One slot in the row: either a page, or the ellipsis standing for those left out. */\ntype PaginationItem = { kind: 'page'; key: string; page: number } | { kind: 'gap'; key: string }\n\n// A length or a model that is not a whole number (`NaN` while a page size is still loading,\n// a computed `2.5`) is brought back to a page that exists, or no pill would ever match it.\nconst total = computed(() => Math.max(Math.trunc(props.length) || 1, 1))\nconst currentPage = computed(() => clamp(Math.round(page.value) || 1, 1, total.value))\n\nconst isPageDisabled = computed(() => resolveMatcher(props.disabledPages))\n\n// @a11y\n// A pill shows nothing but a number, which on its own tells a screen reader\n// nothing at all; this is what has it announced as \"Page 3\".\nfunction pageLabelFor(n: number): string {\n return props.pageLabel ? props.pageLabel(n) : m.value.pagination.page(n)\n}\n\n/** Works out which slots the row holds. */\nconst items = computed<PaginationItem[]>(() => {\n const count = total.value\n const current = currentPage.value\n\n const pageItem = (n: number): PaginationItem => ({ kind: 'page', key: `page-${n}`, page: n })\n const pages = (from: number, to: number): PaginationItem[] => {\n const out: PaginationItem[] = []\n for (let n = from; n <= to; n++) out.push(pageItem(n))\n return out\n }\n // Keyed by the side it stands on, never by the page it follows: there is at most one\n // ellipsis per side, and the left one always comes after the first page while the right\n // one always comes before the last. A key derived from the window would change on every\n // navigation, so the right-hand ellipsis would be destroyed and rebuilt each time the\n // window slid, for a node that never changes.\n const gap = (side: 'start' | 'end'): PaginationItem => ({ kind: 'gap', key: `gap-${side}` })\n\n // With no limit given, nothing is left out. At 0 the row holds the controls alone.\n const limit = Math.trunc(props.totalVisible ?? count)\n const visible = Number.isNaN(limit) ? count : Math.max(limit, 0)\n if (visible === 0) return []\n if (visible >= count) return pages(1, count)\n\n // Below five slots there is no room for the first page, an ellipsis, the current page,\n // another ellipsis and the last: the row is a plain window of consecutive pages, held\n // against the bounds so it keeps the same number of slots.\n if (visible < 5) {\n const from = clamp(current - Math.floor((visible - 1) / 2), 1, count - visible + 1)\n return pages(from, from + visible - 1)\n }\n\n const start = current - Math.floor((visible - 5) / 2)\n const end = start + (visible - 5)\n\n // The window is stretched to the bound instead, which both avoids that and keeps the number\n // of slots exactly the same.\n if (start <= 3) return [...pages(1, visible - 2), gap('end'), pageItem(count)]\n if (end >= count - 2) return [pageItem(1), gap('start'), ...pages(count - visible + 3, count)]\n return [pageItem(1), gap('start'), ...pages(start, end), gap('end'), pageItem(count)]\n})\n\n/**\n * Where a control leads: the nearest page in that direction that can actually be reached,\n * disabled ones being stepped over rather than stopped at. Answering `undefined` means there is\n * none left, which disables the control; and that single answer also covers being on the first\n * or the last page, with no separate test for the ends.\n */\nfunction step(direction: -1 | 1): number | undefined {\n for (let n = currentPage.value + direction; n >= 1 && n <= total.value; n += direction) {\n if (!isPageDisabled.value(n)) return n\n }\n return undefined\n}\n\n/**\n * Where a first or last control leads: the reachable page farthest in that direction. It is\n * `undefined` exactly when `step` is, so each edge control disables itself with its neighbour.\n */\nfunction leap(direction: -1 | 1): number | undefined {\n const end = direction < 0 ? 1 : total.value\n for (let n = end; n !== currentPage.value; n -= direction) {\n if (!isPageDisabled.value(n)) return n\n }\n return undefined\n}\n\nconst firstTarget = computed(() => leap(-1))\nconst prevTarget = computed(() => step(-1))\nconst nextTarget = computed(() => step(1))\nconst lastTarget = computed(() => leap(1))\n\nfunction goTo(n: number | undefined) {\n if (n === undefined) return\n page.value = clamp(n, 1, total.value)\n}\n\n/** The address a pill or a control links to, or `undefined` when the row is made of buttons. */\nfunction hrefFor(n: number): string | undefined {\n return props.href?.(n)\n}\n\n// @core\n/*\n * A link clicked with a modifier held (Ctrl or Cmd for a new tab, Shift for a window, Alt for a\n * download) opens somewhere ELSE: the page on screen stays where it is, so the model must not\n * move. The test the routers themselves make before taking a click over.\n */\nfunction opensElsewhere(event: MouseEvent): boolean {\n return (\n props.href !== undefined &&\n (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey)\n )\n}\n\nfunction choose(event: MouseEvent, n: number | undefined) {\n if (n === undefined || opensElsewhere(event)) return\n emit('navigate', n, event)\n goTo(n)\n}\n\nfunction isUnusable(el: HTMLElement): boolean {\n return el.matches(':disabled, [aria-disabled=\"true\"]')\n}\n\n// @a11y\n/*\n * The previous and next controls disable themselves once no page is left in their direction,\n * and a focused button that becomes disabled hands the focus to <body>: a keyboard reader\n * pressing \"Next page\" on the second to last page would be sent back to the top of the document\n * by the next Tab. The focus goes to the page just reached instead, the current page being\n * always rendered. A row without pages hands it to the nearest control still usable, the one\n * before it first.\n */\nasync function goFromControl(event: MouseEvent, n: number | undefined) {\n const control = event.currentTarget as HTMLElement\n const hadFocus = control === document.activeElement\n choose(event, n)\n if (!hadFocus) return\n await nextTick()\n const nav = navEl.value\n if (!nav || !isUnusable(control)) return\n const current = nav.querySelector<HTMLElement>('[aria-current=\"page\"]')\n if (current) return current.focus()\n const usable = [...nav.querySelectorAll<HTMLElement>(':is(button, a[href]):not(:disabled)')]\n const before = usable.filter(\n (el) => control.compareDocumentPosition(el) & Node.DOCUMENT_POSITION_PRECEDING,\n )\n ;(before.at(-1) ?? usable[0])?.focus()\n}\n\ntype ControlSide = 'first' | 'prev' | 'next' | 'last'\n\n/*\n * The four controls, written once: they differ only by their direction and reach, and template\n * blocks drifting apart on the next change is exactly what this avoids. A functional component\n * because they sit at either end of the row, with the pages in between, where a `v-for` over\n * descriptors could not put them.\n */\nconst PageControl: FunctionalComponent<{ side: ControlSide }> = ({ side }) => {\n const { label, icon, target } = {\n first: { label: resolvedFirstText.value, icon: props.firstIcon, target: firstTarget.value },\n prev: { label: resolvedPrevText.value, icon: props.prevIcon, target: prevTarget.value },\n next: { label: resolvedNextText.value, icon: props.nextIcon, target: nextTarget.value },\n last: { label: resolvedLastText.value, icon: props.lastIcon, target: lastTarget.value },\n }[side]\n const disabled = props.disabled || target === undefined\n const common = {\n class: 'v-pagination-control',\n 'data-side': side,\n variant: props.itemVariant,\n disabled,\n href: hrefFor(target ?? currentPage.value),\n rel: props.href && !disabled ? side : undefined,\n onClick: (event: MouseEvent) => goFromControl(event, target),\n }\n const glyph = () => h(VIcon, { ...iconProps(icon), mirrored: true })\n if (props.controls === 'icon') return h(VIconButton, { ...common, label }, glyph)\n const backward = side === 'first' || side === 'prev'\n return h(\n VButton,\n { ...common, tone: 'neutral' },\n {\n ...(props.controls === 'both' ? { [backward ? 'start' : 'end']: glyph } : {}),\n default: () => h('span', { class: 'v-pagination-control-label' }, label),\n },\n )\n}\n\nconst navEl = ref<HTMLElement | null>(null)\n\n// @keyboard @a11y\n/** The arrow keys, through the shared implementation in `utils/arrowNav`. */\nfunction onKeydown(event: KeyboardEvent) {\n const nav = navEl.value\n if (!nav) return\n arrowNavigate(event, nav, () =>\n navigableItems(nav, '.v-pagination-page:not(:disabled, [aria-disabled=\"true\"])'),\n )\n}\n\n// The pills are rendered by a VButtonGroup inside the nav, so a template ref reaches none of\n// them. `focus` goes to the current page.\ndefineExpose({\n // Two queries, not one selector list: a list matches in DOM order, which would hand the\n // focus to the previous control ahead of the current page. `a[href]` because an inert link\n // has lost its address, and with it the ability to take the focus.\n /** Moves the focus to the current page, or to the first control that can take it. */\n focus: (options?: FocusOptions) =>\n (\n navEl.value?.querySelector<HTMLElement>(\n '[aria-current=\"page\"]:is(button, a[href]):not(:disabled)',\n ) ?? navEl.value?.querySelector<HTMLElement>(':is(button, a[href]):not(:disabled)')\n )?.focus(options),\n /** The `<nav>` element, which is also where the consumer's attributes land. */\n el: navEl,\n})\n</script>\n\n<template>\n <nav\n ref=\"navEl\"\n class=\"v-pagination\"\n :aria-label=\"ariaLabel\"\n :data-align=\"align\"\n :data-item-variant=\"itemVariant\"\n @keydown=\"onKeydown\"\n >\n <!-- The row is a VButtonGroup either way: joined it merges the borders of its DIRECT\n button children, and detached it spaces them, which is all this prop asks of it.\n That is why there is no list markup wrapping the pills, and why the ellipsis is\n itself an inert button rather than a plain span: anything else between two pills\n would break the seam. -->\n <!--\n `|| undefined` keeps the group opinion-free when the row does not ask, `undefined` being\n what means \"no opinion\" there where `false` is an order. The size is always an opinion,\n the pagination having a default of its own.\n -->\n <VButtonGroup\n class=\"v-pagination-items\"\n :detached=\"detached\"\n :bordered=\"bordered\"\n :size=\"size\"\n :compact=\"compact || undefined\"\n :elevated=\"elevated || undefined\"\n >\n <PageControl v-if=\"controls && edgeControls\" side=\"first\" />\n <PageControl v-if=\"controls\" side=\"prev\" />\n\n <template v-for=\"item in items\" :key=\"item.key\">\n <VButton\n v-if=\"item.kind === 'page'\"\n class=\"v-pagination-page\"\n :variant=\"item.page === currentPage ? selectedVariant : itemVariant\"\n :tone=\"item.page === currentPage ? tone : 'neutral'\"\n :disabled=\"disabled || isPageDisabled(item.page)\"\n :aria-label=\"pageLabelFor(item.page)\"\n :aria-current=\"item.page === currentPage ? 'page' : undefined\"\n :href=\"hrefFor(item.page)\"\n @click=\"choose($event, item.page)\"\n >\n {{ item.page }}\n </VButton>\n <!--\n The ellipsis is a disabled icon-only button rather than a span: being a button, it\n keeps the joined row's seam continuous and follows the size and density like\n everything else. Disabling it takes it out of the tab order, and it is hidden from\n screen readers, which have the page numbers themselves; which is also why it is a\n VButton and not a VIconButton, whose required label would name something nobody can\n reach.\n -->\n <VButton\n v-else\n class=\"v-pagination-ellipsis\"\n aria-hidden=\"true\"\n data-icon-only\n :variant=\"itemVariant\"\n tone=\"neutral\"\n disabled\n >\n <template #start>\n <VIcon :name=\"moreHorizIcon\" />\n </template>\n </VButton>\n </template>\n\n <PageControl v-if=\"controls\" side=\"next\" />\n <PageControl v-if=\"controls && edgeControls\" side=\"last\" />\n </VButtonGroup>\n </nav>\n</template>\n\n<style>\n@layer vectis.components {\n .v-pagination {\n display: flex;\n }\n\n .v-pagination[data-align='center'] {\n justify-content: center;\n }\n\n .v-pagination[data-align='end'] {\n justify-content: flex-end;\n }\n\n /*\n * Qualified by an attribute VButton always renders, which makes both of these beat that\n * button's own padding and its own transition whatever order the two sheets end up in; the\n * VIconButton idiom.\n */\n .v-pagination-page[data-size] {\n /* A one-digit pill is square, and widens by itself past that. The height variable\n is set by the shared size class on this very element, so this single rule covers\n all five sizes and their compact forms. */\n min-inline-size: var(--control-height);\n padding-inline: var(--vectis-space-2);\n\n /*\n * The highlight changes instantly, and this must not be \"restored for consistency\". VButton\n * fades `background-color` over `--vectis-duration-fast`, which is right for a button that\n * stays put and wrong here: truncation SHIFTS its window, so from one page to the next the\n * highlight keeps its slot but changes ELEMENT, and the outgoing and incoming pills are\n * both half-tinted for a few frames; read as a flicker, with nothing in the console.\n */\n transition: none;\n }\n\n /* The ellipsis is a disabled button only as a technical device; to the reader it is\n not a control that has been turned off, so it does not take the forbidden\n cursor. Qualified like the pills: VButton's disabled cursor weighs (0,2,0), and a bare\n class loses to it whatever the sheet order. */\n .v-pagination-ellipsis[data-size] {\n cursor: default;\n }\n\n /*\n * A disabled page or control greys its outline to a different token, hence a variable the\n * second rule changes. VToggle's `--toggle-frame` is the same device.\n */\n .v-pagination[data-item-variant='outline'] {\n --pagination-frame: var(--vectis-color-border-strong);\n }\n\n .v-pagination[data-item-variant='outline'] > * > :is(:disabled, [aria-disabled='true']) {\n --pagination-frame: var(--vectis-color-border);\n }\n\n .v-pagination[data-item-variant='outline']\n > *\n > .v-pagination-page[aria-current='page']:is([data-variant='soft'], [data-variant='ghost']) {\n border-color: var(--pagination-frame);\n }\n\n /*\n * The class is repeated to reach (0,6,0). The variant, hover and active rules reach (0,5,0),\n * and with the forcing turned off any of them that still won would paint its tone over the\n * selection, with HighlightText on top of it.\n */\n @media (forced-colors: active) {\n .v-pagination-page.v-pagination-page.v-pagination-page.v-pagination-page[aria-current='page']:not(\n :disabled,\n [aria-disabled='true']\n ) {\n forced-color-adjust: none;\n background-color: Highlight;\n color: HighlightText;\n border-color: Highlight;\n outline-color: CanvasText;\n }\n }\n}\n</style>\n"],"mappings":""}
|