vectis-ui 0.8.1 → 0.9.1
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/README.md +3 -3
- package/dist/components/VAccordion/VAccordionItem.d.ts +4 -6
- package/dist/components/VAccordion/VAccordionItem.js.map +1 -1
- package/dist/components/VAccordion/VAccordionItem.vue_vue_type_script_setup_true_lang.js +21 -19
- package/dist/components/VAccordion/VAccordionItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VAccordion/context.d.ts +6 -1
- package/dist/components/VAccordion/context.js.map +1 -1
- package/dist/components/VAvatar/VAvatar.css +1 -1
- package/dist/components/VAvatar/VAvatar.d.ts +5 -3
- package/dist/components/VAvatar/VAvatar.js.map +1 -1
- package/dist/components/VAvatar/VAvatar.vue_vue_type_script_setup_true_lang.js +53 -39
- package/dist/components/VAvatar/VAvatar.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VAvatar/VAvatarGroup.d.ts +12 -3
- package/dist/components/VAvatar/VAvatarGroup.js.map +1 -1
- package/dist/components/VAvatar/VAvatarGroup.vue_vue_type_script_setup_true_lang.js +27 -20
- package/dist/components/VAvatar/VAvatarGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VAvatar/context.d.ts +2 -2
- package/dist/components/VAvatar/context.js.map +1 -1
- package/dist/components/VBadge/VBadge.css +1 -1
- package/dist/components/VBadge/VBadge.d.ts +8 -4
- package/dist/components/VBadge/VBadge.js.map +1 -1
- package/dist/components/VBadge/VBadge.vue_vue_type_script_setup_true_lang.js +6 -3
- package/dist/components/VBadge/VBadge.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VBreadcrumb/VBreadcrumb.d.ts +5 -4
- package/dist/components/VBreadcrumb/VBreadcrumb.js.map +1 -1
- package/dist/components/VBreadcrumb/VBreadcrumb.vue_vue_type_script_setup_true_lang.js +8 -3
- package/dist/components/VBreadcrumb/VBreadcrumb.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VButton/VButton.css +1 -1
- package/dist/components/VButton/VButton.d.ts +4 -1
- package/dist/components/VButton/VButton.js.map +1 -1
- package/dist/components/VButton/VButton.vue_vue_type_script_setup_true_lang.js +8 -7
- package/dist/components/VButton/VButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VButton/VButtonGroup.js.map +1 -1
- package/dist/components/VButton/VButtonGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCalendar/VCalendar.css +1 -1
- package/dist/components/VCalendar/VCalendar.d.ts +15 -6
- package/dist/components/VCalendar/VCalendar.js.map +1 -1
- package/dist/components/VCalendar/VCalendar.vue_vue_type_script_setup_true_lang.js +144 -126
- package/dist/components/VCalendar/VCalendar.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCalendar/VCalendarEvent.css +1 -1
- package/dist/components/VCalendar/VCalendarEvent.d.ts +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 +1 -1
- package/dist/components/VCalendar/VCalendarMonth.js.map +1 -1
- package/dist/components/VCalendar/VCalendarMonth.vue_vue_type_script_setup_true_lang.js +99 -90
- 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 +256 -246
- 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.d.ts +8 -1
- package/dist/components/VCalendar/VCalendarYear.js.map +1 -1
- package/dist/components/VCalendar/VCalendarYear.vue_vue_type_script_setup_true_lang.js +39 -32
- package/dist/components/VCalendar/VCalendarYear.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCalendar/color.d.ts +1 -1
- package/dist/components/VCalendar/color.js.map +1 -1
- package/dist/components/VCalendar/edgeStep.d.ts +3 -3
- package/dist/components/VCalendar/edgeStep.js +5 -0
- package/dist/components/VCalendar/edgeStep.js.map +1 -1
- package/dist/components/VCalendar/gesture.d.ts +10 -9
- package/dist/components/VCalendar/gesture.js +60 -45
- package/dist/components/VCalendar/gesture.js.map +1 -1
- package/dist/components/VCalendar/keyboard.d.ts +22 -5
- package/dist/components/VCalendar/keyboard.js +17 -16
- package/dist/components/VCalendar/keyboard.js.map +1 -1
- package/dist/components/VCalendar/layout.d.ts +47 -37
- package/dist/components/VCalendar/layout.js +47 -37
- package/dist/components/VCalendar/layout.js.map +1 -1
- package/dist/components/VCalendar/timeGrid.d.ts +4 -4
- package/dist/components/VCalendar/timeGrid.js +6 -6
- package/dist/components/VCalendar/timeGrid.js.map +1 -1
- package/dist/components/VCalendar/types.d.ts +5 -5
- package/dist/components/VCarousel/VCarousel.css +1 -1
- package/dist/components/VCarousel/VCarousel.d.ts +59 -38
- package/dist/components/VCarousel/VCarousel.js.map +1 -1
- package/dist/components/VCarousel/VCarousel.vue_vue_type_script_setup_true_lang.js +161 -132
- package/dist/components/VCarousel/VCarousel.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCarousel/VCarouselItem.d.ts +1 -1
- package/dist/components/VCarousel/VCarouselItem.js.map +1 -1
- package/dist/components/VCarousel/VCarouselItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCarousel/context.d.ts +1 -1
- package/dist/components/VCarousel/context.js.map +1 -1
- package/dist/components/VCheckbox/VCheckbox.css +1 -1
- package/dist/components/VCheckbox/VCheckbox.d.ts +2 -2
- package/dist/components/VCheckbox/VCheckbox.js.map +1 -1
- package/dist/components/VCheckbox/VCheckbox.vue_vue_type_script_setup_true_lang.js +10 -8
- package/dist/components/VCheckbox/VCheckbox.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VChip/VChip.css +1 -1
- package/dist/components/VChip/VChip.d.ts +7 -2
- package/dist/components/VChip/VChip.js.map +1 -1
- package/dist/components/VChip/VChip.vue_vue_type_script_setup_true_lang.js +69 -55
- package/dist/components/VChip/VChip.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCombobox/VCombobox.css +1 -1
- package/dist/components/VCombobox/VCombobox.d.ts +50 -36
- package/dist/components/VCombobox/VCombobox.js.map +1 -1
- package/dist/components/VCombobox/VCombobox.vue_vue_type_script_setup_true_lang.js +167 -161
- package/dist/components/VCombobox/VCombobox.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCombobox/VComboboxGroup.css +1 -1
- package/dist/components/VCombobox/VComboboxGroup.js.map +1 -1
- package/dist/components/VCombobox/VComboboxGroup.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/VCombobox/VComboboxGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VCombobox/infiniteScroll.d.ts +12 -3
- package/dist/components/VCombobox/infiniteScroll.js +18 -12
- package/dist/components/VCombobox/infiniteScroll.js.map +1 -1
- package/dist/components/VDataTable/VDataTable.css +1 -1
- package/dist/components/VDataTable/VDataTable.d.ts +55 -24
- package/dist/components/VDataTable/VDataTable.js.map +1 -1
- package/dist/components/VDataTable/VDataTable.vue_vue_type_script_setup_true_lang.js +192 -155
- package/dist/components/VDataTable/VDataTable.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VDateInput/VDateInput.css +1 -1
- package/dist/components/VDateInput/VDateInput.d.ts +15 -12
- package/dist/components/VDateInput/VDateInput.js.map +1 -1
- package/dist/components/VDateInput/VDateInput.vue_vue_type_script_setup_true_lang.js +180 -160
- package/dist/components/VDateInput/VDateInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VDateInput/mask.d.ts +95 -0
- package/dist/components/VDateInput/mask.js +118 -0
- package/dist/components/VDateInput/mask.js.map +1 -0
- package/dist/components/VDatePicker/VDatePicker.css +1 -1
- package/dist/components/VDatePicker/VDatePicker.d.ts +6 -5
- package/dist/components/VDatePicker/VDatePicker.js.map +1 -1
- package/dist/components/VDatePicker/VDatePicker.vue_vue_type_script_setup_true_lang.js +204 -173
- package/dist/components/VDatePicker/VDatePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VDatePicker/keyboard.d.ts +3 -3
- package/dist/components/VDatePicker/keyboard.js.map +1 -1
- package/dist/components/VDatePicker/names.d.ts +34 -0
- package/dist/components/VDatePicker/names.js +42 -0
- package/dist/components/VDatePicker/names.js.map +1 -0
- package/dist/components/VDialog/VDialog.css +1 -1
- package/dist/components/VDialog/VDialog.d.ts +2 -2
- package/dist/components/VDialog/VDialog.js.map +1 -1
- package/dist/components/VDialog/VDialog.vue_vue_type_script_setup_true_lang.js +63 -41
- package/dist/components/VDialog/VDialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VFileInput/VFileInput.d.ts +38 -25
- package/dist/components/VFileInput/VFileInput.js.map +1 -1
- package/dist/components/VFileInput/VFileInput.vue_vue_type_script_setup_true_lang.js +74 -71
- package/dist/components/VFileInput/VFileInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VFileInput/truncate.d.ts +4 -4
- package/dist/components/VFileInput/truncate.js.map +1 -1
- package/dist/components/VFilePicker/VFilePicker.css +1 -1
- package/dist/components/VFilePicker/VFilePicker.d.ts +54 -37
- package/dist/components/VFilePicker/VFilePicker.js.map +1 -1
- package/dist/components/VFilePicker/VFilePicker.vue_vue_type_script_setup_true_lang.js +152 -135
- package/dist/components/VFilePicker/VFilePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VFilePicker/fileKind.d.ts +2 -2
- package/dist/components/VFilePicker/fileKind.js.map +1 -1
- package/dist/components/VHotkeys/VHotkeys.css +1 -1
- package/dist/components/VHotkeys/VHotkeys.d.ts +10 -8
- package/dist/components/VHotkeys/VHotkeys.js.map +1 -1
- package/dist/components/VHotkeys/VHotkeys.vue_vue_type_script_setup_true_lang.js +22 -20
- package/dist/components/VHotkeys/VHotkeys.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VHotkeys/platform.d.ts +9 -7
- package/dist/components/VHotkeys/platform.js +41 -30
- package/dist/components/VHotkeys/platform.js.map +1 -1
- package/dist/components/VIcon/VIcon.css +1 -1
- package/dist/components/VIcon/VIcon.d.ts +6 -6
- package/dist/components/VIcon/VIcon.js.map +1 -1
- package/dist/components/VIcon/VIcon.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VIcon/iconProps.d.ts +4 -4
- package/dist/components/VIcon/iconProps.js.map +1 -1
- package/dist/components/VIcon/icons/index.d.ts +1 -1
- package/dist/components/VIcon/icons/index.js.map +1 -1
- package/dist/components/VIcon/icons/names.d.ts +1 -1
- package/dist/components/VIcon/icons/names.js.map +1 -1
- package/dist/components/VIcon/resolver.d.ts +3 -3
- package/dist/components/VIcon/resolver.js +23 -20
- package/dist/components/VIcon/resolver.js.map +1 -1
- package/dist/components/VIcon/types.d.ts +4 -4
- package/dist/components/VIconButton/VIconButton.d.ts +4 -4
- package/dist/components/VIconButton/VIconButton.js.map +1 -1
- package/dist/components/VIconButton/VIconButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VInput/VInput.d.ts +16 -8
- package/dist/components/VInput/VInput.js.map +1 -1
- package/dist/components/VInput/VInput.vue_vue_type_script_setup_true_lang.js +22 -16
- 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.js.map +1 -1
- package/dist/components/VInput/VInputGroup.vue_vue_type_script_setup_true_lang.js +43 -28
- 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 +3 -3
- package/dist/components/VInputOTP/VInputOTP.js.map +1 -1
- package/dist/components/VInputOTP/VInputOTP.vue_vue_type_script_setup_true_lang.js +152 -85
- package/dist/components/VInputOTP/VInputOTP.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VMenu/VMenu.d.ts +4 -4
- package/dist/components/VMenu/VMenu.js.map +1 -1
- package/dist/components/VMenu/VMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VMenu/VMenuGroup.css +1 -1
- package/dist/components/VMenu/VMenuGroup.js.map +1 -1
- package/dist/components/VMenu/VMenuGroup.vue_vue_type_script_setup_true_lang.js +18 -11
- package/dist/components/VMenu/VMenuGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VMenu/VMenuItem.css +1 -1
- package/dist/components/VMenu/VMenuItem.d.ts +6 -6
- package/dist/components/VMenu/VMenuItem.js.map +1 -1
- package/dist/components/VMenu/VMenuItem.vue_vue_type_script_setup_true_lang.js +83 -69
- package/dist/components/VMenu/VMenuItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VMenu/VMenuPanel.css +1 -1
- 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 +56 -55
- package/dist/components/VMenu/VMenuPanel.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VMenu/context.d.ts +2 -2
- package/dist/components/VMenu/context.js.map +1 -1
- package/dist/components/VPagination/VPagination.css +1 -1
- package/dist/components/VPagination/VPagination.d.ts +31 -9
- package/dist/components/VPagination/VPagination.js.map +1 -1
- package/dist/components/VPagination/VPagination.vue_vue_type_script_setup_true_lang.js +82 -52
- package/dist/components/VPagination/VPagination.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VPopover/VPopover.css +1 -1
- package/dist/components/VPopover/VPopover.d.ts +1 -1
- package/dist/components/VPopover/VPopover.js.map +1 -1
- package/dist/components/VPopover/VPopover.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VProgressCircular/VProgressCircular.css +1 -1
- package/dist/components/VProgressCircular/VProgressCircular.d.ts +12 -7
- package/dist/components/VProgressCircular/VProgressCircular.js.map +1 -1
- package/dist/components/VProgressCircular/VProgressCircular.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VProgressLinear/VProgressLinear.css +1 -1
- package/dist/components/VProgressLinear/VProgressLinear.d.ts +15 -10
- package/dist/components/VProgressLinear/VProgressLinear.js.map +1 -1
- package/dist/components/VProgressLinear/VProgressLinear.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VRadio/VRadio.css +1 -1
- package/dist/components/VRadio/VRadio.js.map +1 -1
- package/dist/components/VRadio/VRadio.vue_vue_type_script_setup_true_lang.js +3 -3
- package/dist/components/VRadio/VRadio.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSeparator/VSeparator.d.ts +1 -1
- package/dist/components/VSeparator/VSeparator.js.map +1 -1
- package/dist/components/VSeparator/VSeparator.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSideNavigation/VSideNavigation.d.ts +2 -2
- package/dist/components/VSideNavigation/VSideNavigation.js.map +1 -1
- package/dist/components/VSideNavigation/VSideNavigation.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/VSideNavigation/VSideNavigation.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSideNavigation/VSideNavigationGroup.css +1 -1
- package/dist/components/VSideNavigation/VSideNavigationGroup.js.map +1 -1
- package/dist/components/VSideNavigation/VSideNavigationGroup.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/VSideNavigation/VSideNavigationGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSideNavigation/VSideNavigationItem.css +1 -1
- package/dist/components/VSideNavigation/VSideNavigationItem.d.ts +12 -13
- package/dist/components/VSideNavigation/VSideNavigationItem.js.map +1 -1
- package/dist/components/VSideNavigation/VSideNavigationItem.vue_vue_type_script_setup_true_lang.js +87 -68
- package/dist/components/VSideNavigation/VSideNavigationItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSkeletonLoader/VSkeletonLoader.css +1 -1
- package/dist/components/VSkeletonLoader/VSkeletonLoader.d.ts +10 -7
- package/dist/components/VSkeletonLoader/VSkeletonLoader.js.map +1 -1
- package/dist/components/VSkeletonLoader/VSkeletonLoader.vue_vue_type_script_setup_true_lang.js +5 -5
- package/dist/components/VSkeletonLoader/VSkeletonLoader.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSlider/VSlider.css +1 -1
- package/dist/components/VSlider/VSlider.d.ts +21 -7
- package/dist/components/VSlider/VSlider.js.map +1 -1
- package/dist/components/VSlider/VSlider.vue_vue_type_script_setup_true_lang.js +159 -140
- package/dist/components/VSlider/VSlider.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSnackbar/VSnackbar.css +1 -1
- package/dist/components/VSnackbar/VSnackbar.d.ts +4 -4
- package/dist/components/VSnackbar/VSnackbar.js.map +1 -1
- package/dist/components/VSnackbar/VSnackbar.vue_vue_type_script_setup_true_lang.js +85 -59
- package/dist/components/VSnackbar/VSnackbar.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSnackbar/state.d.ts +7 -7
- package/dist/components/VSnackbar/state.js +13 -11
- package/dist/components/VSnackbar/state.js.map +1 -1
- package/dist/components/VSpinner/VSpinner.css +1 -1
- package/dist/components/VSpinner/VSpinner.js.map +1 -1
- package/dist/components/VSpinner/VSpinner.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VSwitch/VSwitch.css +1 -1
- package/dist/components/VSwitch/VSwitch.d.ts +1 -1
- package/dist/components/VSwitch/VSwitch.js.map +1 -1
- package/dist/components/VSwitch/VSwitch.vue_vue_type_script_setup_true_lang.js +4 -4
- 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 +4 -0
- package/dist/components/VTabs/VTab.js.map +1 -1
- package/dist/components/VTabs/VTab.vue_vue_type_script_setup_true_lang.js +9 -8
- 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 +17 -7
- package/dist/components/VTabs/VTabs.js.map +1 -1
- package/dist/components/VTabs/VTabs.vue_vue_type_script_setup_true_lang.js +84 -77
- package/dist/components/VTabs/VTabs.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTextarea/VTextarea.d.ts +8 -8
- package/dist/components/VTextarea/VTextarea.js.map +1 -1
- package/dist/components/VTextarea/VTextarea.vue_vue_type_script_setup_true_lang.js +71 -69
- package/dist/components/VTextarea/VTextarea.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTimeInput/VTimeInput.css +1 -1
- package/dist/components/VTimeInput/VTimeInput.d.ts +21 -12
- package/dist/components/VTimeInput/VTimeInput.js.map +1 -1
- package/dist/components/VTimeInput/VTimeInput.vue_vue_type_script_setup_true_lang.js +230 -206
- package/dist/components/VTimeInput/VTimeInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTimeInput/search.d.ts +17 -2
- package/dist/components/VTimeInput/search.js +19 -9
- package/dist/components/VTimeInput/search.js.map +1 -1
- package/dist/components/VTimePicker/VTimePicker.css +1 -1
- package/dist/components/VTimePicker/VTimePicker.d.ts +8 -7
- package/dist/components/VTimePicker/VTimePicker.js.map +1 -1
- package/dist/components/VTimePicker/VTimePicker.vue_vue_type_script_setup_true_lang.js +128 -106
- package/dist/components/VTimePicker/VTimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTimePicker/limits.d.ts +11 -4
- package/dist/components/VTimePicker/limits.js +3 -2
- package/dist/components/VTimePicker/limits.js.map +1 -1
- package/dist/components/VToast/VToast.css +1 -1
- package/dist/components/VToast/VToast.js.map +1 -1
- package/dist/components/VToast/VToast.vue_vue_type_script_setup_true_lang.js +33 -37
- package/dist/components/VToast/VToast.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VToast/VToaster.js.map +1 -1
- package/dist/components/VToast/VToaster.vue_vue_type_script_setup_true_lang.js +91 -61
- package/dist/components/VToast/VToaster.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VToast/state.d.ts +8 -6
- package/dist/components/VToast/state.js +15 -13
- package/dist/components/VToast/state.js.map +1 -1
- package/dist/components/VToggle/VToggle.css +1 -1
- package/dist/components/VToggle/VToggle.d.ts +9 -4
- package/dist/components/VToggle/VToggle.js.map +1 -1
- package/dist/components/VToggle/VToggle.vue_vue_type_script_setup_true_lang.js +2 -1
- package/dist/components/VToggle/VToggle.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VToggle/VToggleItem.d.ts +4 -0
- package/dist/components/VToggle/VToggleItem.js.map +1 -1
- package/dist/components/VToggle/VToggleItem.vue_vue_type_script_setup_true_lang.js +5 -5
- package/dist/components/VToggle/VToggleItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTooltip/VTooltip.css +1 -1
- package/dist/components/VTooltip/VTooltip.d.ts +17 -10
- package/dist/components/VTooltip/VTooltip.js.map +1 -1
- package/dist/components/VTooltip/VTooltip.vue_vue_type_script_setup_true_lang.js +46 -26
- package/dist/components/VTooltip/VTooltip.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/VTypography/VTypography.css +1 -1
- package/dist/components/VTypography/VTypography.d.ts +6 -4
- package/dist/components/VTypography/VTypography.js.map +1 -1
- package/dist/components/VTypography/VTypography.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/composables/useAriaLabel.js +1 -1
- package/dist/composables/useAriaLabel.js.map +1 -1
- package/dist/composables/useClearable.d.ts +2 -2
- package/dist/composables/useClearable.js.map +1 -1
- package/dist/composables/useDetailsOpen.d.ts +3 -3
- package/dist/composables/useDetailsOpen.js +14 -12
- package/dist/composables/useDetailsOpen.js.map +1 -1
- package/dist/composables/useFieldIds.d.ts +2 -1
- package/dist/composables/useFieldIds.js +6 -5
- package/dist/composables/useFieldIds.js.map +1 -1
- package/dist/composables/useFieldPanel.d.ts +2 -2
- package/dist/composables/useFieldPanel.js +47 -37
- package/dist/composables/useFieldPanel.js.map +1 -1
- package/dist/composables/useFileDrop.js +3 -3
- package/dist/composables/useFileDrop.js.map +1 -1
- package/dist/composables/useFileField.d.ts +1 -1
- package/dist/composables/useFileField.js +62 -41
- package/dist/composables/useFileField.js.map +1 -1
- package/dist/composables/useIconClickHandlers.d.ts +3 -3
- package/dist/composables/useIconClickHandlers.js +14 -13
- package/dist/composables/useIconClickHandlers.js.map +1 -1
- package/dist/composables/useInertLink.js +12 -10
- package/dist/composables/useInertLink.js.map +1 -1
- package/dist/composables/useLiveAnnouncer.d.ts +5 -0
- package/dist/composables/useLiveAnnouncer.js +23 -0
- package/dist/composables/useLiveAnnouncer.js.map +1 -0
- package/dist/composables/useMaskedField.d.ts +5 -5
- package/dist/composables/useMaskedField.js.map +1 -1
- package/dist/composables/usePopover.d.ts +3 -3
- package/dist/composables/usePopover.js +6 -4
- package/dist/composables/usePopover.js.map +1 -1
- package/dist/composables/useProgressValue.js +11 -2
- package/dist/composables/useProgressValue.js.map +1 -1
- package/dist/composables/useRootAttrs.d.ts +1 -1
- package/dist/composables/useRootAttrs.js.map +1 -1
- package/dist/composables/useSlotNodes.d.ts +18 -0
- package/dist/composables/useSlotNodes.js +13 -0
- package/dist/composables/useSlotNodes.js.map +1 -0
- package/dist/composables/useTextLimit.d.ts +2 -1
- package/dist/composables/useTextLimit.js +2 -2
- package/dist/composables/useTextLimit.js.map +1 -1
- package/dist/composables/useTimer.d.ts +5 -0
- package/dist/composables/useTimer.js +22 -11
- package/dist/composables/useTimer.js.map +1 -1
- package/dist/i18n/en.js +1 -1
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/fr.js +14 -14
- package/dist/i18n/fr.js.map +1 -1
- package/dist/i18n/state.d.ts +7 -7
- package/dist/i18n/state.js +37 -28
- package/dist/i18n/state.js.map +1 -1
- package/dist/i18n/types.d.ts +12 -12
- package/dist/icons.d.ts +2 -2
- package/dist/index.d.ts +12 -11
- package/dist/styles.css +1 -1
- package/dist/tokens/css.d.ts +1 -1
- package/dist/tokens/css.js.map +1 -1
- package/dist/tokens/index.d.ts +6 -0
- package/dist/tokens/semantic.d.ts +6 -0
- package/dist/tokens/semantic.js +66 -60
- package/dist/tokens/semantic.js.map +1 -1
- package/dist/tokens/themes/dark.js +3 -3
- package/dist/tokens/themes/dark.js.map +1 -1
- package/dist/tokens.json +130 -66
- package/dist/types.d.ts +1 -1
- package/dist/utils/arrowNav.d.ts +4 -1
- package/dist/utils/arrowNav.js +7 -7
- package/dist/utils/arrowNav.js.map +1 -1
- package/dist/utils/chip.d.ts +1 -1
- package/dist/utils/chip.js.map +1 -1
- package/dist/utils/clock.d.ts +113 -0
- package/dist/utils/clock.js +84 -0
- package/dist/utils/clock.js.map +1 -0
- package/dist/utils/css.d.ts +6 -4
- package/dist/utils/css.js +2 -2
- package/dist/utils/css.js.map +1 -1
- package/dist/utils/date.d.ts +7 -102
- package/dist/utils/date.js +33 -160
- package/dist/utils/date.js.map +1 -1
- package/dist/utils/direction.d.ts +1 -1
- package/dist/utils/direction.js.map +1 -1
- package/dist/utils/env.d.ts +12 -3
- package/dist/utils/env.js +6 -0
- package/dist/utils/env.js.map +1 -0
- package/dist/utils/file.d.ts +3 -3
- package/dist/utils/file.js +1 -1
- package/dist/utils/file.js.map +1 -1
- package/dist/utils/focus.d.ts +1 -1
- package/dist/utils/focus.js.map +1 -1
- package/dist/utils/hostWarns.d.ts +1 -1
- package/dist/utils/hostWarns.js.map +1 -1
- package/dist/utils/ids.d.ts +1 -1
- package/dist/utils/ids.js.map +1 -1
- package/dist/utils/matcher.d.ts +2 -2
- package/dist/utils/matcher.js.map +1 -1
- package/dist/utils/memo.d.ts +1 -1
- package/dist/utils/memo.js.map +1 -1
- package/dist/utils/text.d.ts +3 -3
- package/dist/utils/text.js.map +1 -1
- package/dist/utils/time.d.ts +2 -101
- package/dist/utils/time.js +22 -98
- package/dist/utils/time.js.map +1 -1
- package/dist/utils/vnode.d.ts +5 -3
- package/dist/utils/vnode.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,37 +1,38 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import r from "../VIcon/
|
|
4
|
-
import i from "../
|
|
5
|
-
import a from "../
|
|
6
|
-
import ee from "../
|
|
7
|
-
import te from "../
|
|
1
|
+
import { isDev as e } from "../../utils/env.js";
|
|
2
|
+
import { useLocale as t, useMessages as n } from "../../i18n/state.js";
|
|
3
|
+
import { iconProps as r } from "../VIcon/iconProps.js";
|
|
4
|
+
import i from "../VIcon/VIcon.js";
|
|
5
|
+
import a from "../VTypography/VTypography.js";
|
|
6
|
+
import ee from "../VSpinner/VSpinner.js";
|
|
7
|
+
import te from "../VButton/VButton.js";
|
|
8
|
+
import o from "../VIconButton/VIconButton.js";
|
|
8
9
|
import { useRootAttrs as ne } from "../../composables/useRootAttrs.js";
|
|
9
|
-
import { close as
|
|
10
|
-
import { useFileDrop as
|
|
11
|
-
import { fileKey as
|
|
12
|
-
import { useFileField as
|
|
13
|
-
import { audio_file as
|
|
10
|
+
import { close as s } from "../VIcon/icons/close.js";
|
|
11
|
+
import { useFileDrop as re } from "../../composables/useFileDrop.js";
|
|
12
|
+
import { fileKey as ie, formatBytes as ae } from "../../utils/file.js";
|
|
13
|
+
import { useFileField as oe } from "../../composables/useFileField.js";
|
|
14
|
+
import { audio_file as se } from "../VIcon/icons/audio_file.js";
|
|
14
15
|
import { cloud_upload as c } from "../VIcon/icons/cloud_upload.js";
|
|
15
16
|
import { code as l } from "../VIcon/icons/code.js";
|
|
16
17
|
import { description as u } from "../VIcon/icons/description.js";
|
|
17
18
|
import { folder_zip as d } from "../VIcon/icons/folder_zip.js";
|
|
18
|
-
import { image as
|
|
19
|
-
import { picture_as_pdf as
|
|
20
|
-
import { table_chart as
|
|
21
|
-
import { video_file as
|
|
22
|
-
import { fileKind as
|
|
23
|
-
import { Fragment as
|
|
19
|
+
import { image as ce } from "../VIcon/icons/image.js";
|
|
20
|
+
import { picture_as_pdf as le } from "../VIcon/icons/picture_as_pdf.js";
|
|
21
|
+
import { table_chart as ue } from "../VIcon/icons/table_chart.js";
|
|
22
|
+
import { video_file as de } from "../VIcon/icons/video_file.js";
|
|
23
|
+
import { fileKind as fe } from "./fileKind.js";
|
|
24
|
+
import { Fragment as f, computed as p, createBlock as m, createCommentVNode as h, createElementBlock as g, createElementVNode as _, createTextVNode as v, createVNode as y, defineComponent as b, mergeModels as x, mergeProps as S, nextTick as pe, normalizeClass as me, normalizeProps as he, normalizeStyle as ge, onBeforeUnmount as _e, onMounted as ve, openBlock as C, reactive as ye, ref as w, renderList as T, renderSlot as E, resolveDynamicComponent as D, toDisplayString as O, unref as k, useModel as A, watch as j, withCtx as M } from "vue";
|
|
24
25
|
//#region src/components/VFilePicker/VFilePicker.vue?vue&type=script&setup=true&lang.ts
|
|
25
|
-
var
|
|
26
|
+
var N = [
|
|
26
27
|
"data-preview",
|
|
27
28
|
"data-disabled",
|
|
28
29
|
"data-readonly",
|
|
29
30
|
"data-invalid",
|
|
30
31
|
"data-dragging"
|
|
31
|
-
],
|
|
32
|
+
], P = { class: "v-file-picker-body" }, be = { class: "v-file-picker-icon" }, xe = { class: "v-file-picker-separator" }, Se = ["aria-label"], Ce = { class: "v-file-picker-thumb" }, we = ["src", "onError"], Te = { class: "v-file-picker-info" }, Ee = ["title"], De = { class: "v-file-picker-size" }, F = /*@__PURE__*/ b({
|
|
32
33
|
inheritAttrs: !1,
|
|
33
34
|
__name: "VFilePicker",
|
|
34
|
-
props: /*@__PURE__*/
|
|
35
|
+
props: /*@__PURE__*/ x({
|
|
35
36
|
title: {},
|
|
36
37
|
subtitle: { default: void 0 },
|
|
37
38
|
icon: { default: () => c },
|
|
@@ -39,7 +40,7 @@ var P = [
|
|
|
39
40
|
type: Boolean,
|
|
40
41
|
default: !1
|
|
41
42
|
},
|
|
42
|
-
|
|
43
|
+
browseText: { default: void 0 },
|
|
43
44
|
preview: {
|
|
44
45
|
type: [Boolean, String],
|
|
45
46
|
default: !1
|
|
@@ -49,7 +50,7 @@ var P = [
|
|
|
49
50
|
default: !1
|
|
50
51
|
},
|
|
51
52
|
typeIcons: { default: void 0 },
|
|
52
|
-
removeIcon: { default: () =>
|
|
53
|
+
removeIcon: { default: () => s },
|
|
53
54
|
multiple: {
|
|
54
55
|
type: Boolean,
|
|
55
56
|
default: !1
|
|
@@ -74,196 +75,212 @@ var P = [
|
|
|
74
75
|
type: Boolean,
|
|
75
76
|
default: !1
|
|
76
77
|
},
|
|
77
|
-
|
|
78
|
+
loadingText: { default: void 0 }
|
|
78
79
|
}, {
|
|
79
80
|
modelValue: { default: () => [] },
|
|
80
81
|
modelModifiers: {}
|
|
81
82
|
}),
|
|
82
|
-
emits: /*@__PURE__*/
|
|
83
|
+
emits: /*@__PURE__*/ x([
|
|
83
84
|
"change",
|
|
84
85
|
"reject",
|
|
85
86
|
"remove"
|
|
86
87
|
], ["update:modelValue"]),
|
|
87
|
-
setup(
|
|
88
|
-
let
|
|
89
|
-
model:
|
|
90
|
-
props:
|
|
91
|
-
emit:
|
|
92
|
-
forwardedAttrs:
|
|
93
|
-
warnings: void 0
|
|
94
|
-
}),
|
|
95
|
-
image:
|
|
96
|
-
pdf:
|
|
97
|
-
audio:
|
|
98
|
-
video:
|
|
88
|
+
setup(s, { expose: c, emit: b }) {
|
|
89
|
+
let x = s, F = b, I = A(s, "modelValue", { get: (e) => e ?? [] }), { attrs: L, rootClass: Oe, rootStyle: ke, forwardedAttrs: R } = ne(), z = n(), Ae = t(), { fileEl: je, enabled: B, nativeInputAttrs: Me, controlAttrs: Ne, acceptFiles: Pe, openPicker: V, removeAt: Fe } = oe({
|
|
90
|
+
model: I,
|
|
91
|
+
props: x,
|
|
92
|
+
emit: F,
|
|
93
|
+
forwardedAttrs: R,
|
|
94
|
+
warnings: e ? () => [!x.hideBrowse && (L["aria-label"] !== void 0 || L["aria-labelledby"] !== void 0) && "an aria-label on the zone is inert while the browse button is shown: the zone is a plain container then, and axe reports aria-prohibited-attr. Name the zone through `title`, or set `hide-browse` to make the zone itself the control."] : void 0
|
|
95
|
+
}), H = w(null), U = w(null), W = p(() => x.preview !== !1 && I.value.length > 0), Ie = {
|
|
96
|
+
image: ce,
|
|
97
|
+
pdf: le,
|
|
98
|
+
audio: se,
|
|
99
|
+
video: de,
|
|
99
100
|
archive: d,
|
|
100
|
-
spreadsheet:
|
|
101
|
+
spreadsheet: ue,
|
|
101
102
|
code: l,
|
|
102
103
|
file: u
|
|
103
|
-
},
|
|
104
|
-
function
|
|
105
|
-
!
|
|
104
|
+
}, Le = (e) => x.typeIcons?.[e] ?? Ie[e];
|
|
105
|
+
function Re(e) {
|
|
106
|
+
!x.hideBrowse && e.target.closest("button") || V();
|
|
106
107
|
}
|
|
107
|
-
let { dragging:
|
|
108
|
-
function
|
|
109
|
-
let e =
|
|
108
|
+
let { dragging: ze, onDragEnter: G, onDragOver: K, onDragLeave: q, onDrop: J } = re(() => B.value, Pe), Y = w(null);
|
|
109
|
+
function X() {
|
|
110
|
+
let e = H.value;
|
|
110
111
|
return e ? e.matches("button") ? e : e.querySelector("button") : null;
|
|
111
112
|
}
|
|
112
|
-
async function
|
|
113
|
-
if (!
|
|
114
|
-
await
|
|
115
|
-
let t =
|
|
116
|
-
(t[Math.min(e, t.length - 1)]?.querySelector("button") ??
|
|
113
|
+
async function Be(e) {
|
|
114
|
+
if (!Fe(e)) return;
|
|
115
|
+
await pe();
|
|
116
|
+
let t = U.value?.querySelectorAll(".v-file-picker-item") ?? [];
|
|
117
|
+
(t[Math.min(e, t.length - 1)]?.querySelector("button") ?? X())?.focus();
|
|
117
118
|
}
|
|
118
|
-
let
|
|
119
|
-
function
|
|
120
|
-
let e = new Set(!
|
|
121
|
-
for (let [t, n] of
|
|
122
|
-
for (let t of e)
|
|
119
|
+
let Z = ye(/* @__PURE__ */ new Map()), Ve = (e) => e.type.startsWith("image/");
|
|
120
|
+
function Q() {
|
|
121
|
+
let e = new Set(!x.hideThumbnails && x.preview !== !1 ? I.value.filter((e) => Ve(e) && !$.has(e)) : []);
|
|
122
|
+
for (let [t, n] of Z) e.has(t) || (URL.revokeObjectURL(n), Z.delete(t));
|
|
123
|
+
for (let t of e) Z.has(t) || Z.set(t, URL.createObjectURL(t));
|
|
123
124
|
}
|
|
124
|
-
function
|
|
125
|
-
let t =
|
|
126
|
-
t && (URL.revokeObjectURL(t),
|
|
125
|
+
function He(e) {
|
|
126
|
+
let t = Z.get(e);
|
|
127
|
+
t && (URL.revokeObjectURL(t), Z.delete(e), $.add(e));
|
|
127
128
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
() =>
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
129
|
+
let $ = /* @__PURE__ */ new WeakSet();
|
|
130
|
+
ve(Q), j([
|
|
131
|
+
I,
|
|
132
|
+
() => x.hideThumbnails,
|
|
133
|
+
() => x.preview
|
|
134
|
+
], Q, { deep: !0 }), _e(() => {
|
|
135
|
+
for (let e of Z.values()) URL.revokeObjectURL(e);
|
|
136
|
+
Z.clear();
|
|
135
137
|
});
|
|
136
|
-
let
|
|
137
|
-
let n =
|
|
138
|
+
let Ue = p(() => W.value ? I.value.map((e, t) => {
|
|
139
|
+
let n = fe(e);
|
|
138
140
|
return {
|
|
139
|
-
key:
|
|
141
|
+
key: ie(e),
|
|
140
142
|
row: {
|
|
141
143
|
file: e,
|
|
142
144
|
index: t,
|
|
143
145
|
kind: n,
|
|
144
|
-
thumbnail:
|
|
145
|
-
icon:
|
|
146
|
-
sizeText:
|
|
147
|
-
remove: () =>
|
|
146
|
+
thumbnail: Z.get(e),
|
|
147
|
+
icon: Le(n),
|
|
148
|
+
sizeText: ae(e.size, Ae.value),
|
|
149
|
+
remove: () => Be(t)
|
|
148
150
|
},
|
|
149
|
-
removeLabel:
|
|
151
|
+
removeLabel: z.value.common.remove(e.name)
|
|
150
152
|
};
|
|
151
153
|
}) : []);
|
|
152
154
|
return c({
|
|
153
|
-
focus: (e) =>
|
|
154
|
-
open:
|
|
155
|
-
el:
|
|
156
|
-
}), (e, t) => (
|
|
155
|
+
focus: (e) => X()?.focus(e),
|
|
156
|
+
open: V,
|
|
157
|
+
el: Y
|
|
158
|
+
}), (e, t) => (C(), g("div", {
|
|
157
159
|
ref_key: "rootEl",
|
|
158
|
-
ref:
|
|
159
|
-
class:
|
|
160
|
-
style:
|
|
161
|
-
"data-preview":
|
|
162
|
-
"data-disabled":
|
|
163
|
-
"data-readonly":
|
|
164
|
-
"data-invalid":
|
|
165
|
-
"data-dragging":
|
|
166
|
-
onDragenter: t[0] ||= (...e) =>
|
|
167
|
-
onDragover: t[1] ||= (...e) =>
|
|
168
|
-
onDragleave: t[2] ||= (...e) =>
|
|
169
|
-
onDrop: t[3] ||= (...e) =>
|
|
170
|
-
}, [
|
|
160
|
+
ref: Y,
|
|
161
|
+
class: me(["v-file-picker", k(Oe)]),
|
|
162
|
+
style: ge(k(ke)),
|
|
163
|
+
"data-preview": s.preview || void 0,
|
|
164
|
+
"data-disabled": s.disabled ? "" : void 0,
|
|
165
|
+
"data-readonly": s.readonly ? "" : void 0,
|
|
166
|
+
"data-invalid": s.invalid ? "" : void 0,
|
|
167
|
+
"data-dragging": k(ze) ? "" : void 0,
|
|
168
|
+
onDragenter: t[0] ||= (...e) => k(G) && k(G)(...e),
|
|
169
|
+
onDragover: t[1] ||= (...e) => k(K) && k(K)(...e),
|
|
170
|
+
onDragleave: t[2] ||= (...e) => k(q) && k(q)(...e),
|
|
171
|
+
onDrop: t[3] ||= (...e) => k(J) && k(J)(...e)
|
|
172
|
+
}, [_("input", S(k(Me), {
|
|
171
173
|
ref_key: "fileEl",
|
|
172
|
-
ref:
|
|
174
|
+
ref: je,
|
|
173
175
|
class: "v-file-picker-native v-hidden-input"
|
|
174
|
-
}), null, 16),
|
|
176
|
+
}), null, 16), _("div", P, [(C(), m(D(s.hideBrowse ? "button" : "div"), S({
|
|
175
177
|
ref_key: "zoneEl",
|
|
176
|
-
ref:
|
|
178
|
+
ref: H,
|
|
179
|
+
"aria-invalid": s.hideBrowse && s.invalid ? "true" : void 0,
|
|
180
|
+
"aria-disabled": s.hideBrowse && s.readonly ? "true" : void 0
|
|
181
|
+
}, k(Ne), {
|
|
177
182
|
class: "v-file-picker-zone",
|
|
178
|
-
type:
|
|
179
|
-
disabled:
|
|
180
|
-
onClick:
|
|
183
|
+
type: s.hideBrowse ? "button" : void 0,
|
|
184
|
+
disabled: s.hideBrowse && s.disabled ? !0 : void 0,
|
|
185
|
+
onClick: Re
|
|
181
186
|
}), {
|
|
182
|
-
default:
|
|
183
|
-
|
|
187
|
+
default: M(() => [
|
|
188
|
+
_("span", be, [E(e.$slots, "icon", {}, () => [s.loading ? (C(), m(ee, {
|
|
184
189
|
key: 0,
|
|
185
|
-
label:
|
|
186
|
-
}, null, 8, ["label"])) : (
|
|
187
|
-
|
|
190
|
+
label: s.loadingText
|
|
191
|
+
}, null, 8, ["label"])) : (C(), m(i, he(S({ key: 1 }, k(r)(s.icon))), null, 16))])]),
|
|
192
|
+
y(a, {
|
|
188
193
|
as: "span",
|
|
189
194
|
variant: "subtitle",
|
|
190
195
|
class: "v-file-picker-title"
|
|
191
196
|
}, {
|
|
192
|
-
default:
|
|
197
|
+
default: M(() => [E(e.$slots, "title", {}, () => [v(O(s.title), 1)])]),
|
|
193
198
|
_: 3
|
|
194
199
|
}),
|
|
195
|
-
|
|
200
|
+
s.subtitle || e.$slots.subtitle ? (C(), m(a, {
|
|
196
201
|
key: 0,
|
|
197
202
|
as: "span",
|
|
198
203
|
variant: "body-sm",
|
|
199
204
|
class: "v-file-picker-subtitle"
|
|
200
205
|
}, {
|
|
201
|
-
default:
|
|
206
|
+
default: M(() => [E(e.$slots, "subtitle", {}, () => [v(O(s.subtitle), 1)])]),
|
|
202
207
|
_: 3
|
|
203
|
-
})) :
|
|
204
|
-
|
|
205
|
-
open:
|
|
206
|
-
disabled: !
|
|
207
|
-
}, () => [
|
|
208
|
+
})) : h("", !0),
|
|
209
|
+
s.hideBrowse ? h("", !0) : (C(), g(f, { key: 1 }, [_("span", xe, O(k(z).filePicker.or), 1), E(e.$slots, "browse", {
|
|
210
|
+
open: k(V),
|
|
211
|
+
disabled: !k(B)
|
|
212
|
+
}, () => [y(te, {
|
|
208
213
|
class: "v-file-picker-browse",
|
|
209
214
|
variant: "outline",
|
|
210
215
|
tone: "neutral",
|
|
211
|
-
disabled:
|
|
212
|
-
|
|
216
|
+
disabled: s.disabled,
|
|
217
|
+
"aria-disabled": s.readonly ? "true" : void 0,
|
|
218
|
+
"aria-invalid": s.invalid ? "true" : void 0,
|
|
219
|
+
onClick: k(V)
|
|
213
220
|
}, {
|
|
214
|
-
default:
|
|
221
|
+
default: M(() => [v(O(s.browseText ?? k(z).filePicker.browse), 1)]),
|
|
215
222
|
_: 1
|
|
216
|
-
}, 8, [
|
|
223
|
+
}, 8, [
|
|
224
|
+
"disabled",
|
|
225
|
+
"aria-disabled",
|
|
226
|
+
"aria-invalid",
|
|
227
|
+
"onClick"
|
|
228
|
+
])])], 64))
|
|
217
229
|
]),
|
|
218
230
|
_: 3
|
|
219
|
-
}, 16, [
|
|
231
|
+
}, 16, [
|
|
232
|
+
"aria-invalid",
|
|
233
|
+
"aria-disabled",
|
|
234
|
+
"type",
|
|
235
|
+
"disabled"
|
|
236
|
+
])), W.value ? (C(), g("ul", {
|
|
220
237
|
key: 0,
|
|
221
238
|
ref_key: "listEl",
|
|
222
|
-
ref:
|
|
239
|
+
ref: U,
|
|
223
240
|
class: "v-file-picker-list",
|
|
224
|
-
"aria-label":
|
|
225
|
-
}, [(
|
|
241
|
+
"aria-label": k(z).filePicker.list
|
|
242
|
+
}, [(C(!0), g(f, null, T(Ue.value, ({ key: t, row: n, removeLabel: a }) => (C(), g("li", {
|
|
226
243
|
key: t,
|
|
227
244
|
class: "v-file-picker-item"
|
|
228
|
-
}, [
|
|
229
|
-
|
|
245
|
+
}, [E(e.$slots, "item", S({ ref_for: !0 }, n), () => [
|
|
246
|
+
_("span", Ce, [E(e.$slots, "thumbnail", S({ ref_for: !0 }, n), () => [n.thumbnail ? (C(), g("img", {
|
|
230
247
|
key: 0,
|
|
231
248
|
class: "v-file-picker-image",
|
|
232
|
-
src:
|
|
249
|
+
src: n.thumbnail,
|
|
233
250
|
alt: "",
|
|
234
251
|
loading: "lazy",
|
|
235
252
|
decoding: "async",
|
|
236
|
-
onError: (e) =>
|
|
237
|
-
}, null, 40,
|
|
253
|
+
onError: (e) => He(n.file)
|
|
254
|
+
}, null, 40, we)) : (C(), m(i, S({
|
|
238
255
|
key: 1,
|
|
239
256
|
ref_for: !0
|
|
240
|
-
},
|
|
241
|
-
|
|
257
|
+
}, k(r)(n.icon)), null, 16))])]),
|
|
258
|
+
_("span", Te, [_("span", {
|
|
242
259
|
class: "v-file-picker-name",
|
|
243
|
-
title:
|
|
244
|
-
},
|
|
245
|
-
|
|
246
|
-
file:
|
|
247
|
-
index:
|
|
248
|
-
remove:
|
|
260
|
+
title: n.file.name
|
|
261
|
+
}, O(n.file.name), 9, Ee), _("span", De, O(n.sizeText), 1)]),
|
|
262
|
+
E(e.$slots, "remove", {
|
|
263
|
+
file: n.file,
|
|
264
|
+
index: n.index,
|
|
265
|
+
remove: n.remove,
|
|
249
266
|
removeLabel: a
|
|
250
|
-
}, () => [
|
|
267
|
+
}, () => [y(o, {
|
|
251
268
|
class: "v-file-picker-remove",
|
|
252
269
|
size: "sm",
|
|
253
|
-
icon:
|
|
270
|
+
icon: s.removeIcon,
|
|
254
271
|
label: a,
|
|
255
|
-
disabled: !
|
|
256
|
-
onClick:
|
|
272
|
+
disabled: !k(B),
|
|
273
|
+
onClick: n.remove
|
|
257
274
|
}, null, 8, [
|
|
258
275
|
"icon",
|
|
259
276
|
"label",
|
|
260
277
|
"disabled",
|
|
261
278
|
"onClick"
|
|
262
279
|
])])
|
|
263
|
-
])]))), 128))], 8,
|
|
280
|
+
])]))), 128))], 8, Se)) : h("", !0)])], 46, N));
|
|
264
281
|
}
|
|
265
282
|
});
|
|
266
283
|
//#endregion
|
|
267
|
-
export {
|
|
284
|
+
export { F as default };
|
|
268
285
|
|
|
269
286
|
//# sourceMappingURL=VFilePicker.vue_vue_type_script_setup_true_lang.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VFilePicker.vue_vue_type_script_setup_true_lang.js","names":["$slots"],"sources":["../../../src/components/VFilePicker/VFilePicker.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @core\n/**\n * A drop zone: a dashed rectangle taking files dragged onto it or chosen from a dialog, with\n * an optional list of what it holds. The v-model is a plain `File[]`, and the division of\n * labour matters — this component SHOWS and SCREENS, uploading is the parent's business.\n *\n * Four things need JS, each forced by the platform. A dialog opens ONLY from a real click on\n * a file input, and a `FileList` cannot be written from a template, so the input is a SOURCE\n * of files rather than a mirror of the value. `accept` has no say over a DROP. The input has\n * to be reset after every change, or the same file cannot be chosen twice running. And a\n * thumbnail needs an object URL, which then has to be released.\n *\n * The KEYBOARD is deliberately not among them: with the browse button hidden the zone\n * becomes a real `<button>`, so Enter, Space, focus, role and a disabled control's inertness\n * all come from the browser. The other incarnation, a plain container, exists for one reason\n * — a button inside a button is invalid markup and unusable by keyboard. The drag highlight,\n * the \"or\" separator and the side-by-side layout are CSS too.\n */\nimport { computed, nextTick, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue'\n\nimport VButton from '../VButton/VButton.vue'\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport { audio_file as audioFileIcon } from '../VIcon/icons/audio_file'\nimport { close as closeIcon } from '../VIcon/icons/close'\nimport { cloud_upload as cloudUploadIcon } from '../VIcon/icons/cloud_upload'\nimport { code as codeIcon } from '../VIcon/icons/code'\nimport { description as descriptionIcon } from '../VIcon/icons/description'\nimport { folder_zip as folderZipIcon } from '../VIcon/icons/folder_zip'\nimport { image as imageIcon } from '../VIcon/icons/image'\nimport { picture_as_pdf as pictureAsPdfIcon } from '../VIcon/icons/picture_as_pdf'\nimport { table_chart as tableChartIcon } from '../VIcon/icons/table_chart'\nimport { video_file as videoFileIcon } from '../VIcon/icons/video_file'\nimport type { IconSource } from '../VIcon/types'\nimport VIconButton from '../VIconButton/VIconButton.vue'\nimport VSpinner from '../VSpinner/VSpinner.vue'\nimport VTypography from '../VTypography/VTypography.vue'\n\nimport { useFileDrop } from '../../composables/useFileDrop'\nimport { useFileField } from '../../composables/useFileField'\nimport { useRootAttrs } from '../../composables/useRootAttrs'\nimport { useLocale, useMessages } from '../../i18n/state'\nimport { isDev } from '../../utils/env'\nimport { fileKey, formatBytes, type FileRejection } from '../../utils/file'\nimport { fileKind, type FileKind } from './fileKind'\n\n/** Where the files taken are listed — under the zone, beside it, or nowhere. */\nexport type FilePickerPreview = false | 'bottom' | 'end'\n\n/**\n * Everything known about one row of the list. The same object is handed to both slots\n * that can replace part of a row, so the two can never be given different information.\n */\nexport interface FilePickerRow {\n /** The file itself. */\n file: File\n /** Its position in the list. */\n index: number\n /** What kind of file it is, as worked out from its type or its extension. */\n kind: FileKind\n /**\n * The address of its image thumbnail, when there is one.\n *\n * It is absent on the server AND on the browser's first render — those addresses only\n * exist in a browser, and creating them during the first render would make the two\n * markups differ — and absent as well for anything the browser fails to decode. Fall\n * back to the icon in that case.\n */\n thumbnail: string | undefined\n /** The icon standing for that kind of file, a consumer's override included. */\n icon: IconSource\n /** Its size, already written out in the reader's conventions. */\n sizeText: string\n /** Takes this file out of the list. */\n remove: () => void\n}\n\ninterface FilePickerProps {\n /**\n * What the reader is being asked to drop, in one line. It is REQUIRED: a drop zone\n * with no instruction is just a rectangle.\n *\n * Note that this prop shadows the HTML attribute of the same name on the component\n * itself, an accepted trade-off — a tooltip on a drop zone would be redundant anyway.\n */\n title: string\n /** A second line under it, for the constraints in plain words: kinds, sizes, how many. */\n subtitle?: string\n /** The large icon at the top of the zone. */\n icon?: IconSource\n /**\n * Hides the separator and the browse button under the instruction. That changes the\n * zone's nature: it then becomes the control ITSELF, a real button, so Enter, Space\n * and the focus come from the platform rather than from a container that merely\n * reacts to clicks.\n */\n hideBrowse?: boolean\n /** The wording of the browse button. It falls back to the design system dictionary. */\n browseLabel?: string\n /**\n * Where the files taken are listed: under the zone, or beside it — beside folds back\n * underneath when the COMPONENT is narrow, following the width it was given rather\n * than the width of the window.\n *\n * By default nothing is listed at all: the value is there for a parent that wants to\n * present it its own way.\n */\n preview?: FilePickerPreview\n /**\n * Shows the kind icon for every file in that list, images included — the way out when\n * a list holds many images, or very large ones.\n *\n * Left out, an image is shown as a thumbnail: it is given a temporary address, created\n * in the browser only and released as soon as the file leaves the list or the\n * component goes away.\n */\n hideThumbnails?: boolean\n /** Replaces the icon of one or more kinds of file. */\n typeIcons?: Partial<Record<FileKind, IconSource>>\n /** The icon of the button removing a file from the list. */\n removeIcon?: IconSource\n /** Allows several files to be taken. With one only, every extra file is turned away. */\n multiple?: boolean\n /**\n * Which kinds of file are accepted, in the browser's own syntax (`image/*,.pdf`).\n *\n * It is applied TWICE, and it has to be: as an attribute, which is what filters the\n * system's file dialog, and again in code, which is the only thing that can filter a\n * DROPPED file — the attribute has no say over a drop.\n */\n accept?: string\n /** The largest ONE file may be, in bytes. */\n maxSize?: number\n /** The largest the whole selection may be, in bytes. */\n maxTotalSize?: number\n /** How many files may be taken at most. */\n maxFiles?: number\n /** Makes the zone unusable, greyed out through the colour tokens. */\n disabled?: boolean\n /** Shows what was taken without allowing it to change: no dialog, no drop, no removal. */\n readonly?: boolean\n /**\n * Marks the zone as invalid, which colours its outline. It is for a rule of your own:\n * nothing here is checked by the browser, the real input being hidden.\n */\n invalid?: boolean\n /**\n * Shows a spinner in place of the zone icon — while an upload is under way, typically.\n * It says that something is happening and changes nothing else: files can still be\n * dropped and the dialog still opens. `disabled` and `readonly` are the props that cut\n * those off.\n */\n loading?: boolean\n /**\n * What screen readers announce while the spinner turns. It falls back to the design\n * system dictionary.\n */\n loadingLabel?: string\n}\n\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<FilePickerProps>(), {\n subtitle: undefined,\n icon: () => cloudUploadIcon,\n hideBrowse: false,\n browseLabel: undefined,\n preview: false,\n hideThumbnails: false,\n typeIcons: undefined,\n removeIcon: () => closeIcon,\n multiple: false,\n accept: undefined,\n maxSize: undefined,\n maxTotalSize: undefined,\n maxFiles: undefined,\n disabled: false,\n readonly: false,\n invalid: false,\n loading: false,\n loadingLabel: undefined,\n})\n\nconst emit = defineEmits<{\n /** The reader changed the selection, by adding or removing something. */\n change: [files: File[]]\n /**\n * A file was turned away and never joined the selection. It is emitted once PER file,\n * so a batch drop can be reported precisely.\n */\n reject: [rejection: FileRejection]\n /**\n * One file was taken out, and which one. It exists alongside `change`, which only says\n * what is LEFT: an upload already in flight is aborted from here, without having to\n * compare two lists to find out what went.\n */\n remove: [file: File, index: number]\n}>()\n\ndefineSlots<{\n /**\n * The large icon, for an illustration the icon props cannot express.\n *\n * It must stay non-interactive, and so must the two below: with the browse button\n * hidden, the zone IS a button, and nothing interactive may sit inside one.\n */\n icon?(): unknown\n /** The instruction. Text and inline elements only, for the same reason. */\n title?(): unknown\n /** The second line. Same contract as the instruction. */\n subtitle?(): unknown\n /**\n * The browse button. Call the `open` it receives: without it a button of your own\n * could no longer open the file dialog at all.\n */\n browse?(props: { open: () => void; disabled: boolean }): unknown\n /**\n * A WHOLE row of the list — the way out for a row showing its own upload progress. It\n * receives everything the standard row was given, so nothing has to be worked out\n * again.\n */\n item?(props: FilePickerRow): unknown\n /**\n * The square at the start of a row alone: for a thumbnail produced by your server, a\n * video's poster frame, or a format the browser cannot decode.\n */\n thumbnail?(props: FilePickerRow): unknown\n /**\n * The control that removes a row. Two of the values it receives are not optional in\n * practice: `remove` is the only thing that can take the file out, and `removeLabel` is\n * the ready-made accessible name — including the file's own — without which the button\n * would be announced as nothing at all.\n */\n remove?(props: { file: File; index: number; remove: () => void; removeLabel: string }): unknown\n}>()\n\n/**\n * Always a LIST of files, whether or not several are allowed — never a file on its own.\n * The shape of the value does not depend on a prop, so a consumer never has to narrow a\n * union TypeScript has no way of discriminating. With a single file it is simply a list\n * of at most one.\n */\nconst model = defineModel<File[]>({ default: () => [] })\n\nconst { attrs, rootClass, rootStyle, forwardedAttrs } = useRootAttrs()\n\nconst m = useMessages()\nconst locale = useLocale()\n\n/*\n * The hidden input, the sorting of the consumer's attributes, the single entry point into\n * the value and the removal of a file live in `useFileField`, shared with VFileInput.\n *\n * Here, the bucket meant for \"the control the user deals with\" goes to the ZONE: that is\n * what they see, and what takes the focus once the browse button is hidden. Nothing is\n * pulled out of it, unlike in VFileInput — this component assembles no description of\n * its own.\n *\n * The zone becomes the control exactly when there is no browse button inside to be one,\n * which is what `hideBrowse` decides.\n */\nconst {\n fileEl,\n enabled: interactive,\n nativeInputAttrs,\n controlAttrs: zoneAttrs,\n acceptFiles,\n openPicker,\n removeAt: removeFile,\n} = useFileField({\n model,\n props,\n emit,\n forwardedAttrs,\n // @a11y @devwarn — the name a consumer gives a plain container is ignored by assistive\n // technology, and axe reports it, so this one fails SILENTLY at runtime too. Behind\n // `isDev`, which a production build folds to false, so the message is dropped.\n warnings: isDev\n ? () => [\n !props.hideBrowse &&\n (attrs['aria-label'] !== undefined || attrs['aria-labelledby'] !== undefined) &&\n 'an aria-label on the zone is inert while the browse button is shown: the zone is a plain container then, and axe reports aria-prohibited-attr. Name the zone through `title`, or set `hide-browse` to make the zone itself the control.',\n ]\n : undefined,\n})\n\nconst zoneEl = ref<HTMLElement | null>(null)\nconst listEl = ref<HTMLUListElement | null>(null)\nconst showList = computed(() => props.preview !== false && model.value.length > 0)\n\n/**\n * Which icon stands for which kind of file. A consumer overrides it entry by entry, so\n * replacing one icon does not mean restating the other seven.\n */\nconst KIND_ICONS: Record<FileKind, IconSource> = {\n image: imageIcon,\n pdf: pictureAsPdfIcon,\n audio: audioFileIcon,\n video: videoFileIcon,\n archive: folderZipIcon,\n spreadsheet: tableChartIcon,\n code: codeIcon,\n file: descriptionIcon,\n}\n\nconst iconForKind = (kind: FileKind): IconSource => props.typeIcons?.[kind] ?? KIND_ICONS[kind]\n\nfunction onZoneClick(event: MouseEvent) {\n // The browse button already handles its own click, and that click also reaches the\n // zone: without this guard it would open the dialog twice. The test is inert when the\n // zone IS the button, there being nothing inside it to match.\n if (!props.hideBrowse && (event.target as HTMLElement).closest('button')) return\n openPicker()\n}\n\nconst { dragging, onDragEnter, onDragOver, onDragLeave, onDrop } = useFileDrop(\n () => interactive.value,\n acceptFiles,\n)\n\n// @a11y\n/**\n * What can be focused in the zone, whichever shape it has taken: the zone itself when it\n * is the button, and otherwise the first button inside it.\n *\n * It is found by searching the DOM rather than kept as a reference, because a consumer\n * may have replaced the browse button entirely — theirs is not ours to hold a reference\n * to, and it still has to be reachable.\n */\nconst rootEl = ref<HTMLElement | null>(null)\n\nfunction focusTarget(): HTMLElement | null {\n const zone = zoneEl.value\n if (!zone) return null\n return zone.matches('button') ? zone : zone.querySelector('button')\n}\n\n// @a11y @core\n/**\n * Takes a file out of the list, and catches the focus that was on its remove button.\n *\n * That button disappears with its row, so the focus would fall back to the page body.\n * It is moved instead to the row that takes its place, or to the browse control once\n * the list is empty. Waiting for the next tick is what makes the new row findable: the\n * page still shows the old one at the moment the value is written.\n */\nasync function removeAt(index: number) {\n if (!removeFile(index)) return\n\n await nextTick()\n const items = listEl.value?.querySelectorAll<HTMLElement>('.v-file-picker-item') ?? []\n const next = items[Math.min(index, items.length - 1)]?.querySelector('button')\n ;(next ?? focusTarget())?.focus()\n}\n\n/**\n * One temporary address per image, kept against THE FILE OBJECT ITSELF.\n *\n * Using the file as the key is safe, and that is worth knowing: Vue's reactivity only\n * wraps plain objects, arrays and collections, so a File travelling through the value\n * comes back with its identity intact — the exact opposite of VCombobox's option cache,\n * where comparing identities IS the bug. Keying by name would be wrong here: two files\n * picked from different folders can share one.\n *\n * The map is made reactive rather than held in a plain reference, which is what lets a\n * single row re-render when its address is ready, instead of replacing the whole map.\n */\nconst thumbUrls = reactive(new Map<File, string>())\n\n/**\n * Whether a thumbnail can be drawn at all, decided on the type the BROWSER reports and\n * not on the kind derived from the extension. A `.heic` file counts as an image and\n * deserves the image icon, but no engine will decode it.\n */\nconst isThumbable = (file: File) => file.type.startsWith('image/')\n\n// @ssr @core\n/**\n * Brings the map into line with the list: releases the addresses of files that have\n * gone, and creates them for files that have arrived.\n *\n * TRAP — it is never called from setup, from a derived value or during rendering, only\n * once mounted, from a watcher and from handlers. That is what keeps the component\n * renderable on a server: the server draws the kind icon, and so does the browser's\n * first render, the map being empty until then — the same reasoning as today's date in\n * VDatePicker.\n */\nfunction syncThumbnails() {\n // With no list rendered there is nothing to draw a thumbnail in, so no address is\n // created at all. This gate — and not a warning — is what makes the default\n // configuration cost strictly nothing.\n const wanted = new Set(\n !props.hideThumbnails && props.preview !== false ? model.value.filter(isThumbable) : [],\n )\n\n for (const [file, url] of thumbUrls) {\n if (wanted.has(file)) continue\n URL.revokeObjectURL(url)\n thumbUrls.delete(file)\n }\n for (const file of wanted) {\n if (!thumbUrls.has(file)) thumbUrls.set(file, URL.createObjectURL(file))\n }\n}\n\n// @fallback\n/**\n * The image failed to decode — a format the browser does not read, a corrupt file, a\n * type that lied about itself. The address is released and the kind icon takes over: a\n * failure to draw must never leave an empty square in the list.\n */\nfunction dropThumbnail(file: File) {\n const url = thumbUrls.get(file)\n if (!url) return\n URL.revokeObjectURL(url)\n thumbUrls.delete(file)\n}\n\n// @ssr — the addresses are created in the browser only; the server and the browser's\n// first render both show the kind icon, so the two markups agree.\nonMounted(syncThumbnails)\n/*\n * Watching deeply costs nothing here and covers a consumer who ADDS to the list rather\n * than replacing it: the walk stops at a File, which is neither a plain object nor a\n * collection, so it never descends past the array itself.\n */\nwatch([model, () => props.hideThumbnails, () => props.preview], syncThumbnails, { deep: true })\n// Released BEFORE the component is torn down and never after — the same rule `useTimer`\n// and VHotkeys follow.\nonBeforeUnmount(() => {\n for (const url of thumbUrls.values()) URL.revokeObjectURL(url)\n thumbUrls.clear()\n})\n\n/**\n * Everything each row of the list needs, assembled in one place and once per change of the\n * list, the language, the icons or a thumbnail — not once per render. A drag over the zone\n * re-renders the component at the pointer's rate, and the rows would otherwise work out\n * their kind and their size again every time, for every slot that reads them.\n *\n * A Vue template has no way of declaring a reusable fragment, so this is also what keeps\n * the slots that can replace part of a row fed from a single source.\n */\nconst rows = computed<{ key: number; row: FilePickerRow; removeLabel: string }[]>(() =>\n showList.value\n ? model.value.map((file, index) => {\n const kind = fileKind(file)\n return {\n key: fileKey(file),\n row: {\n file,\n index,\n kind,\n thumbnail: thumbUrls.get(file),\n icon: iconForKind(kind),\n sizeText: formatBytes(file.size, locale.value),\n remove: () => removeAt(index),\n },\n removeLabel: m.value.common.remove(file.name),\n }\n })\n : [],\n)\n\ndefineExpose({\n /** Moves the focus to the browse control — the button, or the zone when it is one. */\n focus: (options?: FocusOptions) => focusTarget()?.focus(options),\n /**\n * Opens the file dialog. It only works when called from something the reader did — a\n * click, a key press: browsers refuse to open a file dialog by themselves.\n */\n open: openPicker,\n /**\n * The zone's own box, for what neither of the two above covers. It is the wrapper and\n * not the hidden file input: that one is the FORM's element, this is the reader's.\n */\n el: rootEl,\n})\n</script>\n\n<template>\n <div\n ref=\"rootEl\"\n class=\"v-file-picker\"\n :class=\"rootClass\"\n :style=\"rootStyle\"\n :data-preview=\"preview || undefined\"\n :data-disabled=\"disabled ? '' : undefined\"\n :data-readonly=\"readonly ? '' : undefined\"\n :data-invalid=\"invalid ? '' : undefined\"\n :data-dragging=\"dragging ? '' : undefined\"\n @dragenter=\"onDragEnter\"\n @dragover=\"onDragOver\"\n @dragleave=\"onDragLeave\"\n @drop=\"onDrop\"\n >\n <input v-bind=\"nativeInputAttrs\" ref=\"fileEl\" class=\"v-file-picker-native v-hidden-input\" />\n\n <!-- TRAP — this wrapper is not decoration. The root is what the layout asks about\n its own width, and an element cannot ask about ITSELF: whatever flips has to be\n a descendant of it. Deleting this element makes the side-by-side layout\n silently stop folding, with no error anywhere. -->\n <div class=\"v-file-picker-body\">\n <!-- A real button as soon as the zone IS the control: the role, Enter, Space, the\n focus and the complete inertness of a disabled control then come from the\n platform. A plain container otherwise — a button inside a button is invalid\n markup, and unreachable by keyboard. -->\n <component\n :is=\"hideBrowse ? 'button' : 'div'\"\n v-bind=\"zoneAttrs\"\n ref=\"zoneEl\"\n class=\"v-file-picker-zone\"\n :type=\"hideBrowse ? 'button' : undefined\"\n :disabled=\"hideBrowse && !interactive ? true : undefined\"\n @click=\"onZoneClick\"\n >\n <span class=\"v-file-picker-icon\">\n <slot name=\"icon\">\n <VSpinner v-if=\"loading\" :label=\"loadingLabel\" />\n <VIcon v-else v-bind=\"iconProps(icon)\" />\n </slot>\n </span>\n\n <!-- Rendered as a span in BOTH shapes: a paragraph is not allowed inside a\n button, and the markup must not change form between the two — one shape\n means one set of CSS rules. -->\n <VTypography as=\"span\" variant=\"subtitle\" class=\"v-file-picker-title\">\n <slot name=\"title\">{{ title }}</slot>\n </VTypography>\n\n <VTypography\n v-if=\"subtitle || $slots.subtitle\"\n as=\"span\"\n variant=\"body-sm\"\n class=\"v-file-picker-subtitle\"\n >\n <slot name=\"subtitle\">{{ subtitle }}</slot>\n </VTypography>\n\n <template v-if=\"!hideBrowse\">\n <!-- Deliberately not hidden from screen readers: \"or\" is real text, and it\n reads naturally between the instruction and the button. The two rules on\n either side of it are pseudo-elements, and therefore decorative by\n construction. -->\n <span class=\"v-file-picker-separator\">{{ m.filePicker.or }}</span>\n\n <slot name=\"browse\" :open=\"openPicker\" :disabled=\"!interactive\">\n <VButton\n class=\"v-file-picker-browse\"\n variant=\"outline\"\n tone=\"neutral\"\n :disabled=\"!interactive\"\n @click=\"openPicker\"\n >\n {{ browseLabel ?? m.filePicker.browse }}\n </VButton>\n </slot>\n </template>\n </component>\n\n <ul v-if=\"showList\" ref=\"listEl\" class=\"v-file-picker-list\" :aria-label=\"m.filePicker.list\">\n <li v-for=\"{ key, row, removeLabel } in rows\" :key=\"key\" class=\"v-file-picker-item\">\n <slot name=\"item\" v-bind=\"row\">\n <span class=\"v-file-picker-thumb\">\n <slot name=\"thumbnail\" v-bind=\"row\">\n <img\n v-if=\"row.thumbnail\"\n class=\"v-file-picker-image\"\n :src=\"row.thumbnail\"\n alt=\"\"\n loading=\"lazy\"\n decoding=\"async\"\n @error=\"dropThumbnail(row.file)\"\n />\n <VIcon v-else v-bind=\"iconProps(row.icon)\" />\n </slot>\n </span>\n\n <span class=\"v-file-picker-info\">\n <span class=\"v-file-picker-name\" :title=\"row.file.name\">{{ row.file.name }}</span>\n <span class=\"v-file-picker-size\">{{ row.sizeText }}</span>\n </span>\n\n <slot\n name=\"remove\"\n :file=\"row.file\"\n :index=\"row.index\"\n :remove=\"row.remove\"\n :remove-label=\"removeLabel\"\n >\n <VIconButton\n class=\"v-file-picker-remove\"\n size=\"sm\"\n :icon=\"removeIcon\"\n :label=\"removeLabel\"\n :disabled=\"!interactive\"\n @click=\"row.remove\"\n />\n </slot>\n </slot>\n </li>\n </ul>\n </div>\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n /* These variables carry the component's name for a reason: they INHERIT, so a bare\n `--bg` or `--border-color` set by the host application on any ancestor would be\n picked up here instead — and nothing would catch it, since the unit tests evaluate\n no styles at all.\n\n They are declared on the ROOT so that the drag, disabled and read-only states each\n redefine them in ONE place, which is what makes those states structurally incapable\n of disagreeing with hover or focus. */\n .v-file-picker {\n --file-picker-border-color: var(--vectis-color-border-strong);\n --file-picker-bg: var(--vectis-color-surface-sunken);\n --file-picker-text: var(--vectis-color-text);\n --file-picker-text-muted: var(--vectis-color-text-muted);\n --file-picker-row-bg: var(--vectis-color-surface-raised);\n --file-picker-thumb-bg: var(--vectis-color-surface-muted);\n\n /* Positioned so the hidden file input, which has no size at all, has something to be\n placed against. */\n position: relative;\n display: block;\n inline-size: 100%;\n font-family: var(--vectis-text-family);\n }\n\n .v-file-picker-body {\n display: flex;\n flex-direction: column;\n gap: var(--vectis-space-4);\n }\n\n /* One set of rules serves both shapes the zone can take. All that has to be undone is\n what the browser gives a button — its own appearance, font and margin — since\n everything else is declared here regardless. The full width is part of that: a\n button shrinks to fit its content, where a container does not. */\n .v-file-picker-zone {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: var(--vectis-space-2);\n inline-size: 100%;\n min-block-size: var(--vectis-control-size-file-picker-min-block);\n margin: 0;\n padding: var(--vectis-space-6) var(--vectis-space-4);\n appearance: none;\n border: 1px dashed var(--file-picker-border-color);\n border-radius: var(--vectis-radius-surface);\n background: var(--file-picker-bg);\n color: var(--file-picker-text);\n font: inherit;\n text-align: center;\n transition:\n border-color var(--vectis-duration-fast) var(--vectis-ease-default),\n background-color var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n\n .v-file-picker:not([data-disabled]):not([data-readonly]) .v-file-picker-zone {\n cursor: pointer;\n }\n\n .v-file-picker:not([data-disabled]):not([data-readonly]) .v-file-picker-zone:hover {\n --file-picker-border-color: var(--vectis-color-accent);\n }\n\n /* Invalid redefines the variable the zone paints its outline with, the way the drag\n highlight does: the states can then never disagree about what colour the border is. */\n .v-file-picker[data-invalid] .v-file-picker-zone {\n --file-picker-border-color: var(--vectis-color-danger);\n }\n\n .v-file-picker-zone:focus-visible {\n outline: var(--vectis-focus-ring-width) solid var(--vectis-focus-ring-color);\n outline-offset: var(--vectis-focus-ring-offset);\n }\n\n /* While a file is being dragged over it, the zone is highlighted by redefining the\n very variables it paints itself with — so the highlight cannot disagree with the\n hover and focus states. */\n .v-file-picker[data-dragging] {\n --file-picker-border-color: var(--vectis-color-accent);\n --file-picker-bg: var(--vectis-color-accent-surface);\n }\n\n /* The large icon's size is set HERE, on its own wrapper, and never on the zone: set\n there it would inherit down and enlarge the browse button's icons as well. */\n .v-file-picker-icon {\n --vectis-icon-size: var(--vectis-control-size-file-picker-icon);\n\n /* The wrapper is floored at the icon's own size, whatever it holds. An illustration of\n your own in the `#icon` slot may be drawn smaller than the icon, and without that\n floor the zone would change height with it — the box has to be the icon's even when\n its content is not. A floor and not a fixed size, so a taller one still grows it\n rather than spilling out of it; the centring is what keeps a smaller content in the\n middle of the box instead of at its start. */\n min-inline-size: var(--vectis-control-size-file-picker-icon);\n min-block-size: var(--vectis-control-size-file-picker-icon);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: var(--file-picker-text-muted);\n }\n\n /* The spinner standing in for the icon while loading takes the icon's box, the way it\n does in every field: a spinner's size is the box it occupies, and the icon size is\n set on this wrapper. */\n .v-file-picker-icon > .v-spinner {\n font-size: var(--vectis-icon-size);\n }\n\n .v-file-picker-subtitle {\n /* Set through VTypography's own colour variable rather than with a plain colour:\n there is then a single source, and the disabled state below overrides that same\n one instead of introducing a second. */\n --typography-color: var(--file-picker-text-muted);\n }\n\n /* The word set between two rules, entirely in CSS: the two lines are pseudo-elements\n sharing the row with the text between them. No extra element is added to the markup,\n and nothing decorative reaches the accessibility tree. */\n .v-file-picker-separator {\n display: flex;\n align-items: center;\n gap: var(--vectis-space-3);\n inline-size: 100%;\n margin-block-start: var(--vectis-space-2);\n color: var(--file-picker-text-muted);\n font-size: var(--vectis-text-caption-size);\n }\n\n .v-file-picker-separator::before,\n .v-file-picker-separator::after {\n content: '';\n flex: 1 1 0;\n border-block-start: 1px solid var(--vectis-color-border);\n }\n\n .v-file-picker-list {\n display: flex;\n flex-direction: column;\n gap: var(--vectis-space-2);\n margin: 0;\n padding: 0;\n list-style: none;\n }\n\n .v-file-picker-item {\n display: flex;\n align-items: center;\n gap: var(--vectis-space-3);\n padding: var(--vectis-space-2);\n border: 1px solid var(--vectis-color-border);\n border-radius: var(--vectis-radius-interactive);\n background: var(--file-picker-row-bg);\n }\n\n .v-file-picker-thumb {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n inline-size: var(--vectis-control-size-file-picker-thumb);\n block-size: var(--vectis-control-size-file-picker-thumb);\n overflow: hidden;\n border-radius: var(--vectis-radius-interactive);\n background: var(--file-picker-thumb-bg);\n color: var(--file-picker-text-muted);\n }\n\n .v-file-picker-image {\n display: block;\n inline-size: 100%;\n block-size: 100%;\n object-fit: cover;\n }\n\n /* The zero minimum is what makes the ellipsis below possible at all: a flex item\n refuses by default to shrink below its own content, so without it a long file name\n would widen the row instead of being cut short. */\n .v-file-picker-info {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n min-inline-size: 0;\n color: var(--file-picker-text);\n }\n\n .v-file-picker-name {\n overflow: hidden;\n font-size: var(--vectis-text-body-sm-size);\n white-space: nowrap;\n text-overflow: ellipsis;\n }\n\n /* Figures of equal width, so the sizes line up down the column instead of wobbling.\n That is not a typographic role, so it stays a local rule — the same reasoning as\n VFileInput's counter. */\n .v-file-picker-size {\n color: var(--file-picker-text-muted);\n font-size: var(--vectis-text-caption-size);\n font-variant-numeric: tabular-nums;\n }\n\n /*\n * Making the component a query container is reserved for the side-by-side layout,\n * since only its rule below depends on it — and it is not free.\n *\n * A container of this kind computes its width WITHOUT looking at its content, so the\n * component would lose its natural width inside an automatically sized grid column or\n * an inline box. In the two other layouts it keeps it.\n */\n .v-file-picker[data-preview='end'] {\n container-type: inline-size;\n container-name: v-file-picker;\n }\n\n .v-file-picker[data-preview='end'] .v-file-picker-body {\n flex-direction: row;\n align-items: flex-start;\n }\n\n .v-file-picker[data-preview='end'] .v-file-picker-zone,\n .v-file-picker[data-preview='end'] .v-file-picker-list {\n flex: 1 1 0;\n min-inline-size: 0;\n }\n\n /*\n * The threshold is written as a literal length, a container query accepting no\n * variables. It is the width NEEDED to hold the two columns side by side, and not what\n * is left once they fold: the zone stops being readable below about 18rem — its\n * instruction wraps onto two lines and the button follows — a row needs about 15rem to\n * show a thumbnail, a name worth reading and its remove button, and there is a gutter\n * between them.\n */\n @container v-file-picker (max-width: 34rem) {\n .v-file-picker[data-preview='end'] .v-file-picker-body {\n flex-direction: column;\n }\n }\n\n /* A disabled zone greys out through the colour tokens and never through opacity.\n\n The pairing used is the design system's own for a disabled surface, exactly as\n VInput sets it: a lighter text would look more convincingly disabled, and would fall\n below the required contrast against that background — which the accessibility checks\n refuse.\n\n Both text variables take the SAME value here, so that the secondary line does not\n sink below the title on a surface that is already dimmed. */\n .v-file-picker[data-disabled] {\n --file-picker-border-color: var(--vectis-color-border);\n --file-picker-bg: var(--vectis-color-surface-muted);\n --file-picker-text: var(--vectis-color-text-muted);\n --file-picker-text-muted: var(--vectis-color-text-muted);\n --file-picker-row-bg: var(--vectis-color-surface-muted);\n }\n\n .v-file-picker[data-readonly] {\n --file-picker-border-color: var(--vectis-color-border);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-file-picker-zone {\n transition: none;\n }\n }\n\n /*\n * Under Windows forced colours the backgrounds are dropped and every border colour is\n * replaced, so the drag highlight — which is nothing but colour — would disappear\n * entirely. A change of border STYLE survives that: the dashed outline becomes solid\n * for as long as a file hovers over the zone.\n */\n @media (forced-colors: active) {\n .v-file-picker[data-dragging] .v-file-picker-zone {\n border-style: solid;\n }\n\n .v-file-picker-thumb {\n border: 1px solid;\n }\n }\n}\n</style>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"VFilePicker.vue_vue_type_script_setup_true_lang.js","names":["$slots"],"sources":["../../../src/components/VFilePicker/VFilePicker.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @core\n/**\n * A drop zone: a dashed rectangle taking files dragged onto it or chosen from a dialog, with\n * an optional list of what it holds. The v-model is a plain `File[]`, and the division of\n * labour matters — this component SHOWS and SCREENS, uploading is the parent's business.\n *\n * Four things need JS, each forced by the platform. A dialog opens ONLY from a real click on\n * a file input, and a `FileList` cannot be written from a template, so the input is a SOURCE\n * of files rather than a mirror of the value. `accept` has no say over a DROP. The input has\n * to be reset after every change, or the same file cannot be chosen twice running. And a\n * thumbnail needs an object URL, which then has to be released.\n *\n * The KEYBOARD is deliberately not among them: with the browse button hidden the zone\n * becomes a real `<button>`, so Enter, Space, focus, role and a disabled control's inertness\n * all come from the browser. The other incarnation, a plain container, exists for one reason\n * — a button inside a button is invalid markup and unusable by keyboard. The drag highlight,\n * the \"or\" separator and the side-by-side layout are CSS too.\n */\nimport { computed, nextTick, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue'\n\nimport VButton from '../VButton/VButton.vue'\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport { audio_file as audioFileIcon } from '../VIcon/icons/audio_file'\nimport { close as closeIcon } from '../VIcon/icons/close'\nimport { cloud_upload as cloudUploadIcon } from '../VIcon/icons/cloud_upload'\nimport { code as codeIcon } from '../VIcon/icons/code'\nimport { description as descriptionIcon } from '../VIcon/icons/description'\nimport { folder_zip as folderZipIcon } from '../VIcon/icons/folder_zip'\nimport { image as imageIcon } from '../VIcon/icons/image'\nimport { picture_as_pdf as pictureAsPdfIcon } from '../VIcon/icons/picture_as_pdf'\nimport { table_chart as tableChartIcon } from '../VIcon/icons/table_chart'\nimport { video_file as videoFileIcon } from '../VIcon/icons/video_file'\nimport type { IconSource } from '../VIcon/types'\nimport VIconButton from '../VIconButton/VIconButton.vue'\nimport VSpinner from '../VSpinner/VSpinner.vue'\nimport VTypography from '../VTypography/VTypography.vue'\n\nimport { useFileDrop } from '../../composables/useFileDrop'\nimport { useFileField } from '../../composables/useFileField'\nimport { useRootAttrs } from '../../composables/useRootAttrs'\nimport { useLocale, useMessages } from '../../i18n/state'\nimport { isDev } from '../../utils/env'\nimport { fileKey, formatBytes, type FileRejection } from '../../utils/file'\nimport { fileKind, type FilePickerKind } from './fileKind'\n\n/** What the `#browse` slot receives. */\nexport interface FilePickerBrowseSlotProps {\n /** Opens the file dialog; a button of your own has no other way to. */\n open: () => void\n /** Whether the picker is disabled, for your button to follow. */\n disabled: boolean\n}\n\n/** What the `#remove` slot receives. */\nexport interface FilePickerRemoveSlotProps {\n /** The file the row stands for. */\n file: File\n /** Its position in the selection. */\n index: number\n /** Takes the file out of the selection, the only way to. */\n remove: () => void\n /** The ready-made accessible name of the control, the file's name included. */\n removeLabel: string\n}\n\n/** Where the files taken are listed: under the zone, beside it, or nowhere. */\nexport type FilePickerPreview = false | 'bottom' | 'end'\n\n/**\n * Everything known about one row of the list. The same object is handed to both slots\n * that can replace part of a row, so the two can never be given different information.\n */\nexport interface FilePickerRow {\n /** The file itself. */\n file: File\n /** Its position in the list. */\n index: number\n /** What kind of file it is, as worked out from its type or its extension. */\n kind: FilePickerKind\n /**\n * The address of its image thumbnail, when there is one.\n *\n * It is absent on the server AND on the browser's first render, since those addresses\n * only exist in a browser and creating them during the first render would make the two\n * markups differ. It is absent as well for anything the browser fails to decode. Fall\n * back to the icon in that case.\n */\n thumbnail: string | undefined\n /** The icon standing for that kind of file, a consumer's override included. */\n icon: IconSource\n /** Its size, already written out in the reader's conventions. */\n sizeText: string\n /** Takes this file out of the list. */\n remove: () => void\n}\n\ninterface FilePickerProps {\n /**\n * What the reader is being asked to drop, in one line. It is REQUIRED: a drop zone\n * with no instruction is just a rectangle.\n *\n * Note that this prop shadows the HTML attribute of the same name on the component\n * itself, an accepted trade-off: a tooltip on a drop zone would be redundant anyway.\n */\n title: string\n /** A second line under it, for the constraints in plain words: kinds, sizes, how many. */\n subtitle?: string\n /** The large icon at the top of the zone. */\n icon?: IconSource\n /**\n * Hides the separator and the browse button under the instruction. That changes the\n * zone's nature: it then becomes the control ITSELF, a real button, so Enter, Space\n * and the focus come from the platform rather than from a container that merely\n * reacts to clicks.\n */\n hideBrowse?: boolean\n /**\n * The wording drawn on the browse button, which is also its accessible name. It falls\n * back to the design system dictionary.\n */\n browseText?: string\n /**\n * Where the files taken are listed: under the zone, or beside it. Beside folds back\n * underneath when the COMPONENT is narrow, following the width it was given rather\n * than the width of the window.\n *\n * By default nothing is listed at all: the value is there for a parent that wants to\n * present it its own way.\n */\n preview?: FilePickerPreview\n /**\n * Shows the kind icon for every file in that list, images included: the way out when\n * a list holds many images, or very large ones.\n *\n * Left out, an image is shown as a thumbnail: it is given a temporary address, created\n * in the browser only and released as soon as the file leaves the list or the\n * component goes away.\n */\n hideThumbnails?: boolean\n /** Replaces the icon of one or more kinds of file. */\n typeIcons?: Partial<Record<FilePickerKind, IconSource>>\n /** The icon of the button removing a file from the list. */\n removeIcon?: IconSource\n /** Allows several files to be taken. With one only, every extra file is turned away. */\n multiple?: boolean\n /**\n * Which kinds of file are accepted, in the browser's own syntax (`image/*,.pdf`).\n *\n * It is applied TWICE, and it has to be: as an attribute, which is what filters the\n * system's file dialog, and again in code, which is the only thing that can filter a\n * DROPPED file, the attribute having no say over a drop.\n */\n accept?: string\n /** The largest ONE file may be, in bytes. */\n maxSize?: number\n /** The largest the whole selection may be, in bytes. */\n maxTotalSize?: number\n /** How many files may be taken at most. */\n maxFiles?: number\n /** Makes the zone unusable, greyed out through the colour tokens. */\n disabled?: boolean\n /**\n * Shows what was taken without allowing it to change: no dialog, no drop, no removal. Its\n * buttons stay reachable from the keyboard, announced as unavailable.\n */\n readonly?: boolean\n /**\n * Marks the zone as invalid, which colours its outline and is announced on the control\n * the reader reaches. It is for a rule of your own: nothing here is checked by the browser,\n * the real input being hidden.\n */\n invalid?: boolean\n /**\n * Shows a spinner in place of the zone icon, typically while an upload is under way.\n * It says that something is happening and changes nothing else: files can still be\n * dropped and the dialog still opens. `disabled` and `readonly` are the props that cut\n * those off.\n */\n loading?: boolean\n /**\n * What screen readers announce while the spinner turns. It falls back to the design\n * system dictionary.\n */\n loadingText?: string\n}\n\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<FilePickerProps>(), {\n subtitle: undefined,\n icon: () => cloudUploadIcon,\n hideBrowse: false,\n browseText: undefined,\n preview: false,\n hideThumbnails: false,\n typeIcons: undefined,\n removeIcon: () => closeIcon,\n multiple: false,\n accept: undefined,\n maxSize: undefined,\n maxTotalSize: undefined,\n maxFiles: undefined,\n disabled: false,\n readonly: false,\n invalid: false,\n loading: false,\n loadingText: undefined,\n})\n\nconst emit = defineEmits<{\n /** The reader changed the selection, by adding or removing something. */\n change: [files: File[]]\n /**\n * A file was turned away and never joined the selection. It is emitted once PER file,\n * so a batch drop can be reported precisely.\n */\n reject: [rejection: FileRejection]\n /**\n * One file was taken out, and which one. It exists alongside `change`, which only says\n * what is LEFT: an upload already in flight is aborted from here, without having to\n * compare two lists to find out what went.\n */\n remove: [file: File, index: number]\n}>()\n\ndefineSlots<{\n /**\n * The large icon, for an illustration the icon props cannot express.\n *\n * It must stay non-interactive, and so must the two below: with the browse button\n * hidden, the zone IS a button, and nothing interactive may sit inside one.\n */\n icon?(): unknown\n /** The instruction. Text and inline elements only, for the same reason. */\n title?(): unknown\n /** The second line. Same contract as the instruction. */\n subtitle?(): unknown\n /**\n * The browse button. Call the `open` it receives: without it a button of your own\n * could no longer open the file dialog at all.\n */\n browse?(props: FilePickerBrowseSlotProps): unknown\n /**\n * A WHOLE row of the list, the way out for a row showing its own upload progress. It\n * receives everything the standard row was given, so nothing has to be worked out\n * again.\n */\n item?(props: FilePickerRow): unknown\n /**\n * The square at the start of a row alone: for a thumbnail produced by your server, a\n * video's poster frame, or a format the browser cannot decode.\n */\n thumbnail?(props: FilePickerRow): unknown\n /**\n * The control that removes a row. Two of the values it receives are not optional in\n * practice: `remove` is the only thing that can take the file out, and `removeLabel` is\n * the ready-made accessible name, the file's own included, without which the button\n * would be announced as nothing at all.\n */\n remove?(props: FilePickerRemoveSlotProps): unknown\n}>()\n\n// `get` reads an explicit `null` as the empty list: the default applies only to a model\n// that was never given, and `files = ref(null)` is a common start in untyped code.\n/**\n * Always a LIST of files, whether or not several are allowed, and never a file on its own.\n * The shape of the value does not depend on a prop, so a consumer never has to narrow a\n * union TypeScript has no way of discriminating. With a single file it is simply a list\n * of at most one.\n */\nconst model = defineModel<File[]>({ default: () => [], get: (files) => files ?? [] })\n\nconst { attrs, rootClass, rootStyle, forwardedAttrs } = useRootAttrs()\n\nconst m = useMessages()\nconst locale = useLocale()\n\n/*\n * The hidden input, the sorting of the consumer's attributes, the single entry point into\n * the value and the removal of a file live in `useFileField`, shared with VFileInput.\n *\n * Here, the bucket meant for \"the control the user deals with\" goes to the ZONE: that is\n * what they see, and what takes the focus once the browse button is hidden. Nothing is\n * pulled out of it, unlike in VFileInput — this component assembles no description of\n * its own.\n *\n * The zone becomes the control exactly when there is no browse button inside to be one,\n * which is what `hideBrowse` decides.\n */\nconst {\n fileEl,\n enabled: interactive,\n nativeInputAttrs,\n controlAttrs: zoneAttrs,\n acceptFiles,\n openPicker,\n removeAt: removeFile,\n} = useFileField({\n model,\n props,\n emit,\n forwardedAttrs,\n // @a11y @devwarn\n // The name a consumer gives a plain container is ignored by assistive\n // technology, and axe reports it, so this one fails SILENTLY at runtime too. Behind\n // `isDev`, which a production build folds to false, so the message is dropped.\n warnings: isDev\n ? () => [\n !props.hideBrowse &&\n (attrs['aria-label'] !== undefined || attrs['aria-labelledby'] !== undefined) &&\n 'an aria-label on the zone is inert while the browse button is shown: the zone is a plain container then, and axe reports aria-prohibited-attr. Name the zone through `title`, or set `hide-browse` to make the zone itself the control.',\n ]\n : undefined,\n})\n\nconst zoneEl = ref<HTMLElement | null>(null)\nconst listEl = ref<HTMLUListElement | null>(null)\nconst showList = computed(() => props.preview !== false && model.value.length > 0)\n\n/**\n * Which icon stands for which kind of file. A consumer overrides it entry by entry, so\n * replacing one icon does not mean restating the other seven.\n */\nconst KIND_ICONS: Record<FilePickerKind, IconSource> = {\n image: imageIcon,\n pdf: pictureAsPdfIcon,\n audio: audioFileIcon,\n video: videoFileIcon,\n archive: folderZipIcon,\n spreadsheet: tableChartIcon,\n code: codeIcon,\n file: descriptionIcon,\n}\n\nconst iconForKind = (kind: FilePickerKind): IconSource =>\n props.typeIcons?.[kind] ?? KIND_ICONS[kind]\n\nfunction onZoneClick(event: MouseEvent) {\n // The browse button already handles its own click, and that click also reaches the\n // zone: without this guard it would open the dialog twice. The test is inert when the\n // zone IS the button, there being nothing inside it to match.\n if (!props.hideBrowse && (event.target as HTMLElement).closest('button')) return\n openPicker()\n}\n\nconst { dragging, onDragEnter, onDragOver, onDragLeave, onDrop } = useFileDrop(\n () => interactive.value,\n acceptFiles,\n)\n\n// @a11y\n/**\n * What can be focused in the zone, whichever shape it has taken: the zone itself when it\n * is the button, and otherwise the first button inside it.\n *\n * It is found by searching the DOM rather than kept as a reference, because a consumer\n * may have replaced the browse button entirely — theirs is not ours to hold a reference\n * to, and it still has to be reachable.\n */\nconst rootEl = ref<HTMLElement | null>(null)\n\nfunction focusTarget(): HTMLElement | null {\n const zone = zoneEl.value\n if (!zone) return null\n return zone.matches('button') ? zone : zone.querySelector('button')\n}\n\n// @a11y @core\n/**\n * Takes a file out of the list, and catches the focus that was on its remove button.\n *\n * That button disappears with its row, so the focus would fall back to the page body.\n * It is moved instead to the row that takes its place, or to the browse control once\n * the list is empty. Waiting for the next tick is what makes the new row findable: the\n * page still shows the old one at the moment the value is written.\n */\nasync function removeAt(index: number) {\n if (!removeFile(index)) return\n\n await nextTick()\n const items = listEl.value?.querySelectorAll<HTMLElement>('.v-file-picker-item') ?? []\n const next = items[Math.min(index, items.length - 1)]?.querySelector('button')\n ;(next ?? focusTarget())?.focus()\n}\n\n/**\n * One temporary address per image, kept against THE FILE OBJECT ITSELF.\n *\n * Using the file as the key is safe, and that is worth knowing: Vue's reactivity only\n * wraps plain objects, arrays and collections, so a File travelling through the value\n * comes back with its identity intact — the exact opposite of VCombobox's option cache,\n * where comparing identities IS the bug. Keying by name would be wrong here: two files\n * picked from different folders can share one.\n *\n * The map is made reactive rather than held in a plain reference, which is what lets a\n * single row re-render when its address is ready, instead of replacing the whole map.\n */\nconst thumbUrls = reactive(new Map<File, string>())\n\n/**\n * Whether a thumbnail can be drawn at all, decided on the type the BROWSER reports and\n * not on the kind derived from the extension. A `.heic` file counts as an image and\n * deserves the image icon, but no engine will decode it.\n */\nconst isThumbable = (file: File) => file.type.startsWith('image/')\n\n// @ssr @core\n/**\n * Brings the map into line with the list: releases the addresses of files that have\n * gone, and creates them for files that have arrived.\n *\n * TRAP — it is never called from setup, from a derived value or during rendering, only\n * once mounted, from a watcher and from handlers. That is what keeps the component\n * renderable on a server: the server draws the kind icon, and so does the browser's\n * first render, the map being empty until then — the same reasoning as today's date in\n * VDatePicker.\n */\nfunction syncThumbnails() {\n // With no list rendered there is nothing to draw a thumbnail in, so no address is\n // created at all. This gate — and not a warning — is what makes the default\n // configuration cost strictly nothing.\n const wanted = new Set(\n !props.hideThumbnails && props.preview !== false\n ? model.value.filter((file) => isThumbable(file) && !undecodable.has(file))\n : [],\n )\n\n for (const [file, url] of thumbUrls) {\n if (wanted.has(file)) continue\n URL.revokeObjectURL(url)\n thumbUrls.delete(file)\n }\n for (const file of wanted) {\n if (!thumbUrls.has(file)) thumbUrls.set(file, URL.createObjectURL(file))\n }\n}\n\n// @fallback\n/**\n * The image failed to decode — a format the browser does not read, a corrupt file, a\n * type that lied about itself. The address is released and the kind icon takes over: a\n * failure to draw must never leave an empty square in the list.\n */\nfunction dropThumbnail(file: File) {\n const url = thumbUrls.get(file)\n if (!url) return\n URL.revokeObjectURL(url)\n thumbUrls.delete(file)\n undecodable.add(file)\n}\n\n/**\n * The files whose image failed once. They are still in the selection, so without this\n * `syncThumbnails` would hand each of them a new address on every change of the list, only\n * for the `<img>` to fail again. Weak, so a file that leaves takes its entry with it.\n */\nconst undecodable = new WeakSet<File>()\n\n// @ssr\n// The addresses are created in the browser only; the server and the browser's\n// first render both show the kind icon, so the two markups agree.\nonMounted(syncThumbnails)\n/*\n * Watching deeply costs nothing here and covers a consumer who ADDS to the list rather\n * than replacing it: the walk stops at a File, which is neither a plain object nor a\n * collection, so it never descends past the array itself.\n */\nwatch([model, () => props.hideThumbnails, () => props.preview], syncThumbnails, { deep: true })\n// Released BEFORE the component is torn down and never after — the same rule `useTimer`\n// and VHotkeys follow.\nonBeforeUnmount(() => {\n for (const url of thumbUrls.values()) URL.revokeObjectURL(url)\n thumbUrls.clear()\n})\n\n/**\n * Everything each row of the list needs, assembled in one place and once per change of the\n * list, the language, the icons or a thumbnail — not once per render. A drag over the zone\n * re-renders the component at the pointer's rate, and the rows would otherwise work out\n * their kind and their size again every time, for every slot that reads them.\n *\n * A Vue template has no way of declaring a reusable fragment, so this is also what keeps\n * the slots that can replace part of a row fed from a single source.\n */\nconst rows = computed<{ key: number; row: FilePickerRow; removeLabel: string }[]>(() =>\n showList.value\n ? model.value.map((file, index) => {\n const kind = fileKind(file)\n return {\n key: fileKey(file),\n row: {\n file,\n index,\n kind,\n thumbnail: thumbUrls.get(file),\n icon: iconForKind(kind),\n sizeText: formatBytes(file.size, locale.value),\n remove: () => removeAt(index),\n },\n removeLabel: m.value.common.remove(file.name),\n }\n })\n : [],\n)\n\ndefineExpose({\n /** Moves the focus to the browse control: the button, or the zone when it is one. */\n focus: (options?: FocusOptions) => focusTarget()?.focus(options),\n /**\n * Opens the file dialog. It only works when called from something the reader did, a\n * click or a key press: browsers refuse to open a file dialog by themselves.\n */\n open: openPicker,\n /**\n * The zone's own box, for what neither of the two above covers. It is the wrapper and\n * not the hidden file input: that one is the FORM's element, this is the reader's.\n */\n el: rootEl,\n})\n</script>\n\n<template>\n <div\n ref=\"rootEl\"\n class=\"v-file-picker\"\n :class=\"rootClass\"\n :style=\"rootStyle\"\n :data-preview=\"preview || undefined\"\n :data-disabled=\"disabled ? '' : undefined\"\n :data-readonly=\"readonly ? '' : undefined\"\n :data-invalid=\"invalid ? '' : undefined\"\n :data-dragging=\"dragging ? '' : undefined\"\n @dragenter=\"onDragEnter\"\n @dragover=\"onDragOver\"\n @dragleave=\"onDragLeave\"\n @drop=\"onDrop\"\n >\n <input v-bind=\"nativeInputAttrs\" ref=\"fileEl\" class=\"v-file-picker-native v-hidden-input\" />\n\n <!-- TRAP — this wrapper is not decoration. The root is what the layout asks about\n its own width, and an element cannot ask about ITSELF: whatever flips has to be\n a descendant of it. Deleting this element makes the side-by-side layout\n silently stop folding, with no error anywhere. -->\n <div class=\"v-file-picker-body\">\n <!-- A real button as soon as the zone IS the control: the role, Enter, Space, the\n focus and the complete inertness of a disabled control then come from the\n platform. A plain container otherwise — a button inside a button is invalid\n markup, and unreachable by keyboard. -->\n <component\n :is=\"hideBrowse ? 'button' : 'div'\"\n ref=\"zoneEl\"\n :aria-invalid=\"hideBrowse && invalid ? 'true' : undefined\"\n :aria-disabled=\"hideBrowse && readonly ? 'true' : undefined\"\n v-bind=\"zoneAttrs\"\n class=\"v-file-picker-zone\"\n :type=\"hideBrowse ? 'button' : undefined\"\n :disabled=\"hideBrowse && disabled ? true : undefined\"\n @click=\"onZoneClick\"\n >\n <span class=\"v-file-picker-icon\">\n <slot name=\"icon\">\n <VSpinner v-if=\"loading\" :label=\"loadingText\" />\n <VIcon v-else v-bind=\"iconProps(icon)\" />\n </slot>\n </span>\n\n <!-- Rendered as a span in BOTH shapes: a paragraph is not allowed inside a\n button, and the markup must not change form between the two — one shape\n means one set of CSS rules. -->\n <VTypography as=\"span\" variant=\"subtitle\" class=\"v-file-picker-title\">\n <slot name=\"title\">{{ title }}</slot>\n </VTypography>\n\n <VTypography\n v-if=\"subtitle || $slots.subtitle\"\n as=\"span\"\n variant=\"body-sm\"\n class=\"v-file-picker-subtitle\"\n >\n <slot name=\"subtitle\">{{ subtitle }}</slot>\n </VTypography>\n\n <template v-if=\"!hideBrowse\">\n <!-- Deliberately not hidden from screen readers: \"or\" is real text, and it\n reads naturally between the instruction and the button. The two rules on\n either side of it are pseudo-elements, and therefore decorative by\n construction. -->\n <span class=\"v-file-picker-separator\">{{ m.filePicker.or }}</span>\n\n <slot name=\"browse\" :open=\"openPicker\" :disabled=\"!interactive\">\n <!-- Read-only leaves it reachable, as every read-only control of the design\n system is: unavailable rather than disabled. The invalid state is said on\n it, the control the reader reaches, the zone being a plain container. -->\n <VButton\n class=\"v-file-picker-browse\"\n variant=\"outline\"\n tone=\"neutral\"\n :disabled=\"disabled\"\n :aria-disabled=\"readonly ? 'true' : undefined\"\n :aria-invalid=\"invalid ? 'true' : undefined\"\n @click=\"openPicker\"\n >\n {{ browseText ?? m.filePicker.browse }}\n </VButton>\n </slot>\n </template>\n </component>\n\n <ul v-if=\"showList\" ref=\"listEl\" class=\"v-file-picker-list\" :aria-label=\"m.filePicker.list\">\n <li v-for=\"{ key, row, removeLabel } in rows\" :key=\"key\" class=\"v-file-picker-item\">\n <slot name=\"item\" v-bind=\"row\">\n <span class=\"v-file-picker-thumb\">\n <slot name=\"thumbnail\" v-bind=\"row\">\n <img\n v-if=\"row.thumbnail\"\n class=\"v-file-picker-image\"\n :src=\"row.thumbnail\"\n alt=\"\"\n loading=\"lazy\"\n decoding=\"async\"\n @error=\"dropThumbnail(row.file)\"\n />\n <VIcon v-else v-bind=\"iconProps(row.icon)\" />\n </slot>\n </span>\n\n <span class=\"v-file-picker-info\">\n <span class=\"v-file-picker-name\" :title=\"row.file.name\">{{ row.file.name }}</span>\n <span class=\"v-file-picker-size\">{{ row.sizeText }}</span>\n </span>\n\n <slot\n name=\"remove\"\n :file=\"row.file\"\n :index=\"row.index\"\n :remove=\"row.remove\"\n :remove-label=\"removeLabel\"\n >\n <VIconButton\n class=\"v-file-picker-remove\"\n size=\"sm\"\n :icon=\"removeIcon\"\n :label=\"removeLabel\"\n :disabled=\"!interactive\"\n @click=\"row.remove\"\n />\n </slot>\n </slot>\n </li>\n </ul>\n </div>\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n /* These variables carry the component's name for a reason: they INHERIT, so a bare\n `--bg` or `--border-color` set by the host application on any ancestor would be\n picked up here instead — and nothing would catch it, since the unit tests evaluate\n no styles at all.\n\n They are declared on the ROOT so that the drag, disabled and read-only states each\n redefine them in ONE place, which is what makes those states structurally incapable\n of disagreeing with hover or focus. */\n .v-file-picker {\n --file-picker-border-color: var(--vectis-color-border-strong);\n --file-picker-bg: var(--vectis-color-surface-sunken);\n --file-picker-text: var(--vectis-color-text);\n --file-picker-text-muted: var(--vectis-color-text-muted);\n --file-picker-row-bg: var(--vectis-color-surface-raised);\n --file-picker-thumb-bg: var(--vectis-color-surface-muted);\n\n /* Positioned so the hidden file input, which has no size at all, has something to be\n placed against. */\n position: relative;\n display: block;\n inline-size: 100%;\n font-family: var(--vectis-text-family);\n }\n\n .v-file-picker-body {\n display: flex;\n flex-direction: column;\n gap: var(--vectis-space-4);\n }\n\n /* One set of rules serves both shapes the zone can take. All that has to be undone is\n what the browser gives a button — its own appearance, font and margin — since\n everything else is declared here regardless. The full width is part of that: a\n button shrinks to fit its content, where a container does not. */\n .v-file-picker-zone {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: var(--vectis-space-2);\n inline-size: 100%;\n min-block-size: var(--vectis-control-size-file-picker-min-block);\n margin: 0;\n padding: var(--vectis-space-6) var(--vectis-space-4);\n appearance: none;\n border: 1px dashed var(--file-picker-border-color);\n border-radius: var(--vectis-radius-surface);\n background: var(--file-picker-bg);\n color: var(--file-picker-text);\n font: inherit;\n text-align: center;\n transition:\n border-color var(--vectis-duration-fast) var(--vectis-ease-default),\n background-color var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n\n .v-file-picker:not([data-disabled]):not([data-readonly]) .v-file-picker-zone {\n cursor: pointer;\n }\n\n /* Not over an invalid zone: at (0,5,0) this rule outranks the invalid one below, and the\n pointer would paint the accent over the one cue that says something is wrong. */\n .v-file-picker:not([data-disabled]):not([data-readonly]):not([data-invalid])\n .v-file-picker-zone:hover {\n --file-picker-border-color: var(--vectis-color-accent);\n }\n\n /* Invalid redefines the variable the zone paints its outline with, the way the drag\n highlight does: the states can then never disagree about what colour the border is. */\n .v-file-picker[data-invalid] .v-file-picker-zone {\n --file-picker-border-color: var(--vectis-color-danger);\n }\n\n .v-file-picker-zone:focus-visible {\n outline: var(--vectis-focus-ring-width) solid var(--vectis-focus-ring-color);\n outline-offset: var(--vectis-focus-ring-offset);\n }\n\n /* While a file is being dragged over it, the zone is highlighted by redefining the\n very variables it paints itself with — so the highlight cannot disagree with the\n hover and focus states. */\n .v-file-picker[data-dragging] {\n --file-picker-border-color: var(--vectis-color-accent);\n --file-picker-bg: var(--vectis-color-accent-surface);\n }\n\n /* The large icon's size is set HERE, on its own wrapper, and never on the zone: set\n there it would inherit down and enlarge the browse button's icons as well. */\n .v-file-picker-icon {\n --vectis-icon-size: var(--vectis-control-size-file-picker-icon);\n\n /* The wrapper is floored at the icon's own size, whatever it holds. An illustration of\n your own in the `#icon` slot may be drawn smaller than the icon, and without that\n floor the zone would change height with it — the box has to be the icon's even when\n its content is not. A floor and not a fixed size, so a taller one still grows it\n rather than spilling out of it; the centring is what keeps a smaller content in the\n middle of the box instead of at its start. */\n min-inline-size: var(--vectis-control-size-file-picker-icon);\n min-block-size: var(--vectis-control-size-file-picker-icon);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: var(--file-picker-text-muted);\n }\n\n /* The spinner standing in for the icon while loading takes the icon's box, the way it\n does in every field: a spinner's size is the box it occupies, and the icon size is\n set on this wrapper. */\n .v-file-picker-icon > .v-spinner {\n font-size: var(--vectis-icon-size);\n }\n\n .v-file-picker-subtitle {\n /* Set through VTypography's own colour variable rather than with a plain colour:\n there is then a single source, and the disabled state below overrides that same\n one instead of introducing a second. */\n --typography-color: var(--file-picker-text-muted);\n }\n\n /* The word set between two rules, entirely in CSS: the two lines are pseudo-elements\n sharing the row with the text between them. No extra element is added to the markup,\n and nothing decorative reaches the accessibility tree. */\n .v-file-picker-separator {\n display: flex;\n align-items: center;\n gap: var(--vectis-space-3);\n inline-size: 100%;\n margin-block-start: var(--vectis-space-2);\n color: var(--file-picker-text-muted);\n font-size: var(--vectis-text-caption-size);\n }\n\n .v-file-picker-separator::before,\n .v-file-picker-separator::after {\n content: '';\n flex: 1 1 0;\n border-block-start: 1px solid var(--vectis-color-border);\n }\n\n .v-file-picker-list {\n display: flex;\n flex-direction: column;\n gap: var(--vectis-space-2);\n margin: 0;\n padding: 0;\n list-style: none;\n }\n\n .v-file-picker-item {\n display: flex;\n align-items: center;\n gap: var(--vectis-space-3);\n padding: var(--vectis-space-2);\n border: 1px solid var(--vectis-color-border);\n border-radius: var(--vectis-radius-interactive);\n background: var(--file-picker-row-bg);\n }\n\n .v-file-picker-thumb {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n inline-size: var(--vectis-control-size-file-picker-thumb);\n block-size: var(--vectis-control-size-file-picker-thumb);\n overflow: hidden;\n border-radius: var(--vectis-radius-interactive);\n background: var(--file-picker-thumb-bg);\n color: var(--file-picker-text-muted);\n }\n\n .v-file-picker-image {\n display: block;\n inline-size: 100%;\n block-size: 100%;\n object-fit: cover;\n }\n\n /* The zero minimum is what makes the ellipsis below possible at all: a flex item\n refuses by default to shrink below its own content, so without it a long file name\n would widen the row instead of being cut short. */\n .v-file-picker-info {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n min-inline-size: 0;\n color: var(--file-picker-text);\n }\n\n .v-file-picker-name {\n overflow: hidden;\n font-size: var(--vectis-text-body-sm-size);\n white-space: nowrap;\n text-overflow: ellipsis;\n }\n\n /* Figures of equal width, so the sizes line up down the column instead of wobbling.\n That is not a typographic role, so it stays a local rule — the same reasoning as\n VFileInput's counter. */\n .v-file-picker-size {\n color: var(--file-picker-text-muted);\n font-size: var(--vectis-text-caption-size);\n font-variant-numeric: tabular-nums;\n }\n\n /*\n * Making the component a query container is reserved for the side-by-side layout,\n * since only its rule below depends on it — and it is not free.\n *\n * A container of this kind computes its width WITHOUT looking at its content, so the\n * component would lose its natural width inside an automatically sized grid column or\n * an inline box. In the two other layouts it keeps it.\n */\n .v-file-picker[data-preview='end'] {\n container-type: inline-size;\n container-name: v-file-picker;\n }\n\n .v-file-picker[data-preview='end'] .v-file-picker-body {\n flex-direction: row;\n align-items: flex-start;\n }\n\n .v-file-picker[data-preview='end'] .v-file-picker-zone,\n .v-file-picker[data-preview='end'] .v-file-picker-list {\n flex: 1 1 0;\n min-inline-size: 0;\n }\n\n /*\n * The threshold is written as a literal length, a container query accepting no\n * variables. It is the width NEEDED to hold the two columns side by side, and not what\n * is left once they fold: the zone stops being readable below about 18rem — its\n * instruction wraps onto two lines and the button follows — a row needs about 15rem to\n * show a thumbnail, a name worth reading and its remove button, and there is a gutter\n * between them.\n */\n @container v-file-picker (max-width: 34rem) {\n .v-file-picker[data-preview='end'] .v-file-picker-body {\n flex-direction: column;\n }\n }\n\n /* A disabled zone greys out through the colour tokens and never through opacity.\n\n The pairing used is the design system's own for a disabled surface, exactly as\n VInput sets it: a lighter text would look more convincingly disabled, and would fall\n below the required contrast against that background — which the accessibility checks\n refuse.\n\n Both text variables take the SAME value here, so that the secondary line does not\n sink below the title on a surface that is already dimmed. */\n .v-file-picker[data-disabled] {\n --file-picker-border-color: var(--vectis-color-border);\n --file-picker-bg: var(--vectis-color-surface-muted);\n --file-picker-text: var(--vectis-color-text-muted);\n --file-picker-text-muted: var(--vectis-color-text-muted);\n --file-picker-row-bg: var(--vectis-color-surface-muted);\n }\n\n .v-file-picker[data-readonly] {\n --file-picker-border-color: var(--vectis-color-border);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-file-picker-zone {\n transition: none;\n }\n }\n\n /*\n * Under Windows forced colours the backgrounds are dropped and every border colour is\n * replaced, so the drag highlight — which is nothing but colour — would disappear\n * entirely. A change of border STYLE survives that: the dashed outline becomes solid\n * for as long as a file hovers over the zone.\n */\n @media (forced-colors: active) {\n .v-file-picker[data-dragging] .v-file-picker-zone {\n border-style: solid;\n }\n\n .v-file-picker-thumb {\n border: 1px solid;\n }\n }\n}\n</style>\n"],"mappings":"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"}
|