@ecoma-io/loom 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +38 -6
- package/dist/packages/blocks/app-header/src/AppHeader.js.map +1 -1
- package/dist/packages/blocks/app-header/src/AppHeader.vue.d.ts.map +1 -1
- package/dist/packages/blocks/app-header/src/AppHeader.vue_vue_type_script_setup_true_lang.js +1 -0
- package/dist/packages/blocks/app-header/src/AppHeader.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/blocks/desktop-app-shell/src/DesktopAppShell.vue.d.ts +3 -3
- package/dist/packages/blocks/metric-card/src/MetricCard.js.map +1 -1
- package/dist/packages/blocks/metric-card/src/MetricCard.vue.d.ts +22 -4
- package/dist/packages/blocks/metric-card/src/MetricCard.vue.d.ts.map +1 -1
- package/dist/packages/blocks/metric-card/src/MetricCard.vue_vue_type_script_setup_true_lang.js +38 -15
- package/dist/packages/blocks/metric-card/src/MetricCard.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/blocks/title-bar/src/TitleBar.vue.d.ts +3 -3
- package/dist/packages/blocks/toast-stack/src/ToastStack.vue.d.ts +3 -3
- package/dist/packages/composition/scroll-reel/src/ScrollReel.js +2 -2
- package/dist/packages/composition/scroll-reel/src/ScrollReel.js.map +1 -1
- package/dist/packages/composition/scroll-reel/src/ScrollReel.vue.d.ts +26 -0
- package/dist/packages/composition/scroll-reel/src/ScrollReel.vue_vue_type_script_setup_true_lang.js +27 -7
- package/dist/packages/composition/scroll-reel/src/ScrollReel.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/composition/scroll-reel/src/index.d.ts +2 -1
- package/dist/packages/composition/scroll-reel/src/index.js +2 -1
- package/dist/packages/core/src/index.d.ts +1 -1
- package/dist/packages/core/src/index.d.ts.map +1 -1
- package/dist/packages/core/src/index.js +2 -2
- package/dist/packages/core/src/motion.d.ts +13 -0
- package/dist/packages/core/src/motion.d.ts.map +1 -1
- package/dist/packages/core/src/motion.js +20 -13
- package/dist/packages/core/src/motion.js.map +1 -1
- package/dist/packages/core/src/theme.d.ts +9 -0
- package/dist/packages/core/src/theme.d.ts.map +1 -1
- package/dist/packages/core/src/theme.js +36 -10
- package/dist/packages/core/src/theme.js.map +1 -1
- package/dist/packages/labels/src/ancestor-disabled.d.ts +5 -1
- package/dist/packages/labels/src/ancestor-disabled.d.ts.map +1 -1
- package/dist/packages/labels/src/ancestor-disabled.js +5 -1
- package/dist/packages/labels/src/ancestor-disabled.js.map +1 -1
- package/dist/packages/labels/src/component-shapes.d.ts +73 -0
- package/dist/packages/labels/src/component-shapes.d.ts.map +1 -1
- package/dist/packages/labels/src/date-labels.d.ts +8 -6
- package/dist/packages/labels/src/date-labels.d.ts.map +1 -1
- package/dist/packages/labels/src/date-labels.js +8 -6
- package/dist/packages/labels/src/date-labels.js.map +1 -1
- package/dist/packages/labels/src/index.d.ts +2 -2
- package/dist/packages/labels/src/index.d.ts.map +1 -1
- package/dist/packages/labels/src/label-registry.d.ts +7 -1
- package/dist/packages/labels/src/label-registry.d.ts.map +1 -1
- package/dist/packages/layouts/reading/src/Reading.js.map +1 -1
- package/dist/packages/layouts/reading/src/Reading.vue.d.ts +16 -15
- package/dist/packages/layouts/reading/src/Reading.vue.d.ts.map +1 -1
- package/dist/packages/layouts/reading/src/Reading.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/layouts/reading/src/index.d.ts +1 -0
- package/dist/packages/layouts/reading/src/index.d.ts.map +1 -1
- package/dist/packages/loom/src/a11y.d.ts +1 -1
- package/dist/packages/loom/src/index.d.ts +191 -174
- package/dist/packages/loom/src/theme.d.ts +3 -0
- package/dist/packages/primitives/alert/src/Alert.js +7 -0
- package/dist/packages/primitives/alert/src/Alert.js.map +1 -0
- package/dist/packages/primitives/alert/src/Alert.vue.d.ts +73 -0
- package/dist/packages/primitives/alert/src/Alert.vue_vue_type_script_setup_true_lang.js +127 -0
- package/dist/packages/primitives/alert/src/Alert.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/packages/primitives/alert/src/index.d.ts +4 -0
- package/dist/packages/primitives/alert/src/index.js +3 -0
- package/dist/packages/primitives/alert-dialog/src/AlertDialog.js.map +1 -1
- package/dist/packages/primitives/alert-dialog/src/AlertDialog.vue.d.ts +2 -2
- package/dist/packages/primitives/alert-dialog/src/AlertDialog.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/packages/primitives/alert-dialog/src/AlertDialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/alert-dialog/src/index.d.ts +1 -1
- package/dist/packages/primitives/avatar-group/src/AvatarGroup.vue.d.ts +3 -3
- package/dist/packages/primitives/avatar-group/src/index.d.ts +1 -1
- package/dist/packages/primitives/badge/src/Badge.js.map +1 -1
- package/dist/packages/primitives/badge/src/Badge.vue.d.ts.map +1 -1
- package/dist/packages/primitives/badge/src/Badge.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/packages/primitives/badge/src/Badge.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/breadcrumb/src/Breadcrumb.js +2 -2
- package/dist/packages/primitives/breadcrumb/src/Breadcrumb.js.map +1 -1
- package/dist/packages/primitives/breadcrumb/src/Breadcrumb.vue.d.ts +28 -0
- package/dist/packages/primitives/breadcrumb/src/Breadcrumb.vue_vue_type_script_setup_true_lang.js +16 -5
- package/dist/packages/primitives/breadcrumb/src/Breadcrumb.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/breadcrumb/src/index.d.ts +2 -1
- package/dist/packages/primitives/breadcrumb/src/index.js +2 -1
- package/dist/packages/primitives/button/src/Button.js.map +1 -1
- package/dist/packages/primitives/button/src/Button.vue.d.ts.map +1 -1
- package/dist/packages/primitives/button/src/Button.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/button/src/index.js +2 -2
- package/dist/packages/primitives/card/src/Card.js +7 -0
- package/dist/packages/primitives/card/src/Card.js.map +1 -0
- package/dist/packages/primitives/card/src/Card.vue.d.ts +72 -0
- package/dist/packages/primitives/card/src/Card.vue_vue_type_script_setup_true_lang.js +65 -0
- package/dist/packages/primitives/card/src/Card.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/packages/primitives/card/src/index.d.ts +3 -0
- package/dist/packages/primitives/card/src/index.d.ts.map +1 -0
- package/dist/packages/primitives/card/src/index.js +2 -0
- package/dist/packages/primitives/carousel/src/Carousel.js +7 -0
- package/dist/packages/primitives/carousel/src/Carousel.js.map +1 -0
- package/dist/packages/primitives/carousel/src/Carousel.vue.d.ts +34 -0
- package/dist/packages/primitives/carousel/src/Carousel.vue_vue_type_script_setup_true_lang.js +175 -0
- package/dist/packages/primitives/carousel/src/Carousel.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/packages/primitives/carousel/src/index.d.ts +3 -0
- package/dist/packages/primitives/carousel/src/index.js +3 -0
- package/dist/packages/primitives/checkbox/src/Checkbox.js.map +1 -1
- package/dist/packages/primitives/checkbox/src/Checkbox.vue.d.ts +1 -1
- package/dist/packages/primitives/checkbox/src/Checkbox.vue.d.ts.map +1 -1
- package/dist/packages/primitives/checkbox/src/Checkbox.vue_vue_type_script_setup_true_lang.js +3 -3
- package/dist/packages/primitives/checkbox/src/Checkbox.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/chip/src/Chip.js.map +1 -1
- package/dist/packages/primitives/chip/src/Chip.vue.d.ts.map +1 -1
- package/dist/packages/primitives/chip/src/Chip.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/packages/primitives/chip/src/Chip.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/collapse/src/Collapse.js +7 -0
- package/dist/packages/primitives/collapse/src/Collapse.js.map +1 -0
- package/dist/packages/primitives/collapse/src/Collapse.vue.d.ts +56 -0
- package/dist/packages/primitives/collapse/src/Collapse.vue.d.ts.map +1 -0
- package/dist/packages/primitives/collapse/src/Collapse.vue_vue_type_script_setup_true_lang.js +81 -0
- package/dist/packages/primitives/collapse/src/Collapse.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/packages/primitives/collapse/src/index.d.ts +2 -0
- package/dist/packages/primitives/collapse/src/index.d.ts.map +1 -0
- package/dist/packages/primitives/collapse/src/index.js +2 -0
- package/dist/packages/primitives/color-picker/src/ColorPicker.js.map +1 -1
- package/dist/packages/primitives/color-picker/src/ColorPicker.vue.d.ts +4 -4
- package/dist/packages/primitives/color-picker/src/ColorPicker.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/packages/primitives/color-picker/src/ColorPicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/color-picker/src/index.d.ts +1 -1
- package/dist/packages/primitives/combobox/src/Combobox.js.map +1 -1
- package/dist/packages/primitives/combobox/src/Combobox.vue.d.ts +2 -2
- package/dist/packages/primitives/combobox/src/Combobox.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/packages/primitives/combobox/src/Combobox.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/combobox/src/index.d.ts +1 -1
- package/dist/packages/primitives/context-menu/src/ContextMenu.js.map +1 -1
- package/dist/packages/primitives/context-menu/src/ContextMenu.vue.d.ts +12 -0
- package/dist/packages/primitives/context-menu/src/ContextMenu.vue.d.ts.map +1 -1
- package/dist/packages/primitives/context-menu/src/ContextMenu.vue_vue_type_script_setup_true_lang.js +7 -3
- package/dist/packages/primitives/context-menu/src/ContextMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/date-picker/src/DatePicker.js.map +1 -1
- package/dist/packages/primitives/date-picker/src/DatePicker.vue.d.ts +2 -2
- package/dist/packages/primitives/date-picker/src/DatePicker.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/packages/primitives/date-picker/src/DatePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/date-range-picker/src/DateRangePicker.js.map +1 -1
- package/dist/packages/primitives/date-range-picker/src/DateRangePicker.vue.d.ts +3 -3
- package/dist/packages/primitives/date-range-picker/src/DateRangePicker.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/packages/primitives/date-range-picker/src/DateRangePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/date-range-picker/src/index.d.ts +1 -1
- package/dist/packages/primitives/date-time-picker/src/DateTimePicker.js.map +1 -1
- package/dist/packages/primitives/date-time-picker/src/DateTimePicker.vue.d.ts +2 -2
- package/dist/packages/primitives/date-time-picker/src/DateTimePicker.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/packages/primitives/date-time-picker/src/DateTimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/date-time-range-picker/src/DateTimeRangePicker.js.map +1 -1
- package/dist/packages/primitives/date-time-range-picker/src/DateTimeRangePicker.vue.d.ts +3 -3
- package/dist/packages/primitives/date-time-range-picker/src/DateTimeRangePicker.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/packages/primitives/date-time-range-picker/src/DateTimeRangePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/date-time-range-picker/src/index.d.ts +1 -1
- package/dist/packages/primitives/dialog/src/Dialog.js.map +1 -1
- package/dist/packages/primitives/dialog/src/Dialog.vue.d.ts +12 -4
- package/dist/packages/primitives/dialog/src/Dialog.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/packages/primitives/dialog/src/Dialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/dialog/src/index.d.ts +1 -1
- package/dist/packages/primitives/drawer/src/Drawer.js.map +1 -1
- package/dist/packages/primitives/drawer/src/Drawer.vue.d.ts +2 -2
- package/dist/packages/primitives/drawer/src/Drawer.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/packages/primitives/drawer/src/Drawer.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/drawer/src/index.d.ts +1 -1
- package/dist/packages/primitives/dropdown-menu/src/DropdownMenu.js.map +1 -1
- package/dist/packages/primitives/dropdown-menu/src/DropdownMenu.vue.d.ts +26 -0
- package/dist/packages/primitives/dropdown-menu/src/DropdownMenu.vue.d.ts.map +1 -1
- package/dist/packages/primitives/dropdown-menu/src/DropdownMenu.vue_vue_type_script_setup_true_lang.js +10 -4
- package/dist/packages/primitives/dropdown-menu/src/DropdownMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/editable/src/Editable.js.map +1 -1
- package/dist/packages/primitives/editable/src/Editable.vue.d.ts +2 -2
- package/dist/packages/primitives/editable/src/Editable.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/packages/primitives/editable/src/Editable.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/editable/src/index.d.ts +1 -1
- package/dist/packages/primitives/file-upload/src/FileUpload.js.map +1 -1
- package/dist/packages/primitives/file-upload/src/FileUpload.vue.d.ts +2 -2
- package/dist/packages/primitives/file-upload/src/FileUpload.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/packages/primitives/file-upload/src/FileUpload.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/file-upload/src/index.d.ts +1 -1
- package/dist/packages/primitives/hover-card/src/HoverCard.js.map +1 -1
- package/dist/packages/primitives/hover-card/src/HoverCard.vue.d.ts.map +1 -1
- package/dist/packages/primitives/hover-card/src/HoverCard.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/packages/primitives/hover-card/src/HoverCard.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/icon-button/src/IconButton.js.map +1 -1
- package/dist/packages/primitives/icon-button/src/IconButton.vue.d.ts +10 -4
- package/dist/packages/primitives/icon-button/src/IconButton.vue.d.ts.map +1 -1
- package/dist/packages/primitives/icon-button/src/IconButton.vue_vue_type_script_setup_true_lang.js +18 -6
- package/dist/packages/primitives/icon-button/src/IconButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/indicator/src/Indicator.vue.d.ts +2 -2
- package/dist/packages/primitives/indicator/src/index.d.ts +1 -1
- package/dist/packages/primitives/kbd/src/Kbd.js +7 -0
- package/dist/packages/primitives/kbd/src/Kbd.js.map +1 -0
- package/dist/packages/primitives/kbd/src/Kbd.vue.d.ts +30 -0
- package/dist/packages/primitives/kbd/src/Kbd.vue.d.ts.map +1 -0
- package/dist/packages/primitives/kbd/src/Kbd.vue_vue_type_script_setup_true_lang.js +29 -0
- package/dist/packages/primitives/kbd/src/Kbd.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/packages/primitives/kbd/src/index.d.ts +3 -0
- package/dist/packages/primitives/kbd/src/index.d.ts.map +1 -0
- package/dist/packages/primitives/kbd/src/index.js +3 -0
- package/dist/packages/primitives/link/src/Link.js.map +1 -1
- package/dist/packages/primitives/link/src/Link.vue.d.ts.map +1 -1
- package/dist/packages/primitives/link/src/Link.vue_vue_type_script_setup_true_lang.js +3 -3
- package/dist/packages/primitives/link/src/Link.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/list/src/List.js +7 -0
- package/dist/packages/primitives/list/src/List.js.map +1 -0
- package/dist/packages/primitives/list/src/List.vue.d.ts +22 -0
- package/dist/packages/primitives/list/src/List.vue.d.ts.map +1 -0
- package/dist/packages/primitives/list/src/List.vue_vue_type_script_setup_true_lang.js +27 -0
- package/dist/packages/primitives/list/src/List.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/packages/primitives/list/src/ListItem.js +7 -0
- package/dist/packages/primitives/list/src/ListItem.js.map +1 -0
- package/dist/packages/primitives/list/src/ListItem.vue.d.ts +75 -0
- package/dist/packages/primitives/list/src/ListItem.vue.d.ts.map +1 -0
- package/dist/packages/primitives/list/src/ListItem.vue_vue_type_script_setup_true_lang.js +101 -0
- package/dist/packages/primitives/list/src/ListItem.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/packages/primitives/list/src/index.d.ts +4 -0
- package/dist/packages/primitives/list/src/index.d.ts.map +1 -0
- package/dist/packages/primitives/list/src/index.js +3 -0
- package/dist/packages/primitives/menubar/src/Menubar.js.map +1 -1
- package/dist/packages/primitives/menubar/src/Menubar.vue.d.ts +20 -6
- package/dist/packages/primitives/menubar/src/Menubar.vue.d.ts.map +1 -1
- package/dist/packages/primitives/menubar/src/Menubar.vue_vue_type_script_setup_true_lang.js +178 -64
- package/dist/packages/primitives/menubar/src/Menubar.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/number-field/src/NumberField.js.map +1 -1
- package/dist/packages/primitives/number-field/src/NumberField.vue.d.ts +2 -2
- package/dist/packages/primitives/number-field/src/NumberField.vue_vue_type_script_setup_true_lang.js +1 -0
- package/dist/packages/primitives/number-field/src/NumberField.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/number-field/src/index.d.ts +1 -1
- package/dist/packages/primitives/otp-input/src/OtpInput.vue.d.ts +2 -2
- package/dist/packages/primitives/otp-input/src/index.d.ts +1 -1
- package/dist/packages/primitives/pagination/src/Pagination.js.map +1 -1
- package/dist/packages/primitives/pagination/src/Pagination.vue.d.ts +3 -3
- package/dist/packages/primitives/pagination/src/Pagination.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/packages/primitives/pagination/src/Pagination.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/pagination/src/index.d.ts +1 -1
- package/dist/packages/primitives/popover/src/Popover.js.map +1 -1
- package/dist/packages/primitives/popover/src/Popover.vue.d.ts.map +1 -1
- package/dist/packages/primitives/popover/src/Popover.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/packages/primitives/popover/src/Popover.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/progress/src/Progress.vue.d.ts +2 -2
- package/dist/packages/primitives/progress/src/index.d.ts +1 -1
- package/dist/packages/primitives/radial-progress/src/RadialProgress.vue.d.ts +2 -2
- package/dist/packages/primitives/radial-progress/src/index.d.ts +1 -1
- package/dist/packages/primitives/radio-group/src/RadioGroup.js.map +1 -1
- package/dist/packages/primitives/radio-group/src/RadioGroup.vue.d.ts.map +1 -1
- package/dist/packages/primitives/radio-group/src/RadioGroup.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/packages/primitives/radio-group/src/RadioGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/rating/src/Rating.vue.d.ts +2 -2
- package/dist/packages/primitives/rating/src/index.d.ts +1 -1
- package/dist/packages/primitives/segmented-control/src/SegmentedControl.js.map +1 -1
- package/dist/packages/primitives/segmented-control/src/SegmentedControl.vue.d.ts.map +1 -1
- package/dist/packages/primitives/segmented-control/src/SegmentedControl.vue_vue_type_script_setup_true_lang.js +2 -3
- package/dist/packages/primitives/segmented-control/src/SegmentedControl.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/select/src/Select.js.map +1 -1
- package/dist/packages/primitives/select/src/Select.vue.d.ts.map +1 -1
- package/dist/packages/primitives/select/src/Select.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/packages/primitives/select/src/Select.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/slider/src/Slider.js.map +1 -1
- package/dist/packages/primitives/slider/src/Slider.vue.d.ts +6 -3
- package/dist/packages/primitives/slider/src/Slider.vue.d.ts.map +1 -1
- package/dist/packages/primitives/slider/src/Slider.vue_vue_type_script_setup_true_lang.js +15 -10
- package/dist/packages/primitives/slider/src/Slider.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/stepper/src/Stepper.vue.d.ts +2 -2
- package/dist/packages/primitives/stepper/src/index.d.ts +1 -1
- package/dist/packages/primitives/switch/src/Switch.js.map +1 -1
- package/dist/packages/primitives/switch/src/Switch.vue.d.ts +1 -1
- package/dist/packages/primitives/switch/src/Switch.vue.d.ts.map +1 -1
- package/dist/packages/primitives/switch/src/Switch.vue_vue_type_script_setup_true_lang.js +3 -3
- package/dist/packages/primitives/switch/src/Switch.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/table/src/Table.js +7 -0
- package/dist/packages/primitives/table/src/Table.js.map +1 -0
- package/dist/packages/primitives/table/src/Table.vue.d.ts +45 -0
- package/dist/packages/primitives/table/src/Table.vue_vue_type_script_setup_true_lang.js +72 -0
- package/dist/packages/primitives/table/src/Table.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/packages/primitives/table/src/TableCell.js +7 -0
- package/dist/packages/primitives/table/src/TableCell.js.map +1 -0
- package/dist/packages/primitives/table/src/TableCell.vue.d.ts +19 -0
- package/dist/packages/primitives/table/src/TableCell.vue.d.ts.map +1 -0
- package/dist/packages/primitives/table/src/TableCell.vue_vue_type_script_setup_true_lang.js +17 -0
- package/dist/packages/primitives/table/src/TableCell.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/packages/primitives/table/src/TableHead.js +7 -0
- package/dist/packages/primitives/table/src/TableHead.js.map +1 -0
- package/dist/packages/primitives/table/src/TableHead.vue.d.ts +56 -0
- package/dist/packages/primitives/table/src/TableHead.vue_vue_type_script_setup_true_lang.js +79 -0
- package/dist/packages/primitives/table/src/TableHead.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/packages/primitives/table/src/TableRow.js +7 -0
- package/dist/packages/primitives/table/src/TableRow.js.map +1 -0
- package/dist/packages/primitives/table/src/TableRow.vue.d.ts +39 -0
- package/dist/packages/primitives/table/src/TableRow.vue.d.ts.map +1 -0
- package/dist/packages/primitives/table/src/TableRow.vue_vue_type_script_setup_true_lang.js +61 -0
- package/dist/packages/primitives/table/src/TableRow.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/packages/primitives/table/src/index.d.ts +10 -0
- package/dist/packages/primitives/table/src/index.js +8 -0
- package/dist/packages/primitives/tabs/src/Tabs.js.map +1 -1
- package/dist/packages/primitives/tabs/src/Tabs.vue.d.ts.map +1 -1
- package/dist/packages/primitives/tabs/src/Tabs.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/packages/primitives/tabs/src/Tabs.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/tags-input/src/TagsInput.js.map +1 -1
- package/dist/packages/primitives/tags-input/src/TagsInput.vue.d.ts +2 -2
- package/dist/packages/primitives/tags-input/src/TagsInput.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/packages/primitives/tags-input/src/TagsInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/tags-input/src/index.d.ts +1 -1
- package/dist/packages/primitives/text-field/src/TextField.js.map +1 -1
- package/dist/packages/primitives/text-field/src/TextField.vue.d.ts +2 -2
- package/dist/packages/primitives/text-field/src/TextField.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/packages/primitives/text-field/src/TextField.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/text-field/src/index.d.ts +1 -1
- package/dist/packages/primitives/text-field/src/index.js +2 -2
- package/dist/packages/primitives/textarea/src/Textarea.js.map +1 -1
- package/dist/packages/primitives/textarea/src/Textarea.vue.d.ts +2 -2
- package/dist/packages/primitives/textarea/src/Textarea.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/packages/primitives/textarea/src/Textarea.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/textarea/src/index.d.ts +1 -1
- package/dist/packages/primitives/textarea/src/index.js +2 -2
- package/dist/packages/primitives/time-picker/src/TimePicker.vue.d.ts +2 -2
- package/dist/packages/primitives/timeline/src/Timeline.js +7 -0
- package/dist/packages/primitives/timeline/src/Timeline.js.map +1 -0
- package/dist/packages/primitives/timeline/src/Timeline.vue.d.ts +37 -0
- package/dist/packages/primitives/timeline/src/Timeline.vue_vue_type_script_setup_true_lang.js +44 -0
- package/dist/packages/primitives/timeline/src/Timeline.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/packages/primitives/timeline/src/TimelineItem.js +7 -0
- package/dist/packages/primitives/timeline/src/TimelineItem.js.map +1 -0
- package/dist/packages/primitives/timeline/src/TimelineItem.vue.d.ts +50 -0
- package/dist/packages/primitives/timeline/src/TimelineItem.vue_vue_type_script_setup_true_lang.js +96 -0
- package/dist/packages/primitives/timeline/src/TimelineItem.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/packages/primitives/timeline/src/index.d.ts +5 -0
- package/dist/packages/primitives/timeline/src/index.js +5 -0
- package/dist/packages/primitives/toast/src/Toast.vue.d.ts +2 -2
- package/dist/packages/primitives/toast/src/ToastItem.js.map +1 -1
- package/dist/packages/primitives/toast/src/ToastItem.vue.d.ts +2 -2
- package/dist/packages/primitives/toast/src/ToastItem.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/packages/primitives/toast/src/ToastItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/toast/src/index.d.ts +1 -1
- package/dist/packages/primitives/tooltip/src/Tooltip.js.map +1 -1
- package/dist/packages/primitives/tooltip/src/Tooltip.vue.d.ts.map +1 -1
- package/dist/packages/primitives/tooltip/src/Tooltip.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/packages/primitives/tooltip/src/Tooltip.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/window-controls/src/WindowControls.vue.d.ts +2 -2
- package/dist/packages/primitives/window-controls/src/index.d.ts +1 -1
- package/dist/styles/global.css +59 -0
- package/dist/styles/theme.css +13 -0
- package/dist/theme.js +3 -0
- package/package.json +13 -7
- package/dist/packages/blocks/desktop-app-shell/src/DesktopAppShell.vue.d.ts.map +0 -1
- package/dist/packages/blocks/title-bar/src/TitleBar.vue.d.ts.map +0 -1
- package/dist/packages/blocks/toast-stack/src/ToastStack.vue.d.ts.map +0 -1
- package/dist/packages/composition/scroll-reel/src/ScrollReel.vue.d.ts.map +0 -1
- package/dist/packages/composition/scroll-reel/src/index.d.ts.map +0 -1
- package/dist/packages/loom/src/a11y.d.ts.map +0 -1
- package/dist/packages/loom/src/index.d.ts.map +0 -1
- package/dist/packages/primitives/alert-dialog/src/AlertDialog.vue.d.ts.map +0 -1
- package/dist/packages/primitives/alert-dialog/src/index.d.ts.map +0 -1
- package/dist/packages/primitives/avatar-group/src/AvatarGroup.vue.d.ts.map +0 -1
- package/dist/packages/primitives/avatar-group/src/index.d.ts.map +0 -1
- package/dist/packages/primitives/breadcrumb/src/Breadcrumb.vue.d.ts.map +0 -1
- package/dist/packages/primitives/breadcrumb/src/index.d.ts.map +0 -1
- package/dist/packages/primitives/color-picker/src/ColorPicker.vue.d.ts.map +0 -1
- package/dist/packages/primitives/color-picker/src/index.d.ts.map +0 -1
- package/dist/packages/primitives/combobox/src/Combobox.vue.d.ts.map +0 -1
- package/dist/packages/primitives/combobox/src/index.d.ts.map +0 -1
- package/dist/packages/primitives/date-picker/src/DatePicker.vue.d.ts.map +0 -1
- package/dist/packages/primitives/date-range-picker/src/DateRangePicker.vue.d.ts.map +0 -1
- package/dist/packages/primitives/date-range-picker/src/index.d.ts.map +0 -1
- package/dist/packages/primitives/date-time-picker/src/DateTimePicker.vue.d.ts.map +0 -1
- package/dist/packages/primitives/date-time-range-picker/src/DateTimeRangePicker.vue.d.ts.map +0 -1
- package/dist/packages/primitives/date-time-range-picker/src/index.d.ts.map +0 -1
- package/dist/packages/primitives/dialog/src/Dialog.vue.d.ts.map +0 -1
- package/dist/packages/primitives/dialog/src/index.d.ts.map +0 -1
- package/dist/packages/primitives/drawer/src/Drawer.vue.d.ts.map +0 -1
- package/dist/packages/primitives/drawer/src/index.d.ts.map +0 -1
- package/dist/packages/primitives/editable/src/Editable.vue.d.ts.map +0 -1
- package/dist/packages/primitives/editable/src/index.d.ts.map +0 -1
- package/dist/packages/primitives/file-upload/src/FileUpload.vue.d.ts.map +0 -1
- package/dist/packages/primitives/file-upload/src/index.d.ts.map +0 -1
- package/dist/packages/primitives/indicator/src/Indicator.vue.d.ts.map +0 -1
- package/dist/packages/primitives/indicator/src/index.d.ts.map +0 -1
- package/dist/packages/primitives/number-field/src/NumberField.vue.d.ts.map +0 -1
- package/dist/packages/primitives/number-field/src/index.d.ts.map +0 -1
- package/dist/packages/primitives/otp-input/src/OtpInput.vue.d.ts.map +0 -1
- package/dist/packages/primitives/otp-input/src/index.d.ts.map +0 -1
- package/dist/packages/primitives/pagination/src/Pagination.vue.d.ts.map +0 -1
- package/dist/packages/primitives/pagination/src/index.d.ts.map +0 -1
- package/dist/packages/primitives/progress/src/Progress.vue.d.ts.map +0 -1
- package/dist/packages/primitives/progress/src/index.d.ts.map +0 -1
- package/dist/packages/primitives/radial-progress/src/RadialProgress.vue.d.ts.map +0 -1
- package/dist/packages/primitives/radial-progress/src/index.d.ts.map +0 -1
- package/dist/packages/primitives/rating/src/Rating.vue.d.ts.map +0 -1
- package/dist/packages/primitives/rating/src/index.d.ts.map +0 -1
- package/dist/packages/primitives/stepper/src/Stepper.vue.d.ts.map +0 -1
- package/dist/packages/primitives/stepper/src/index.d.ts.map +0 -1
- package/dist/packages/primitives/tags-input/src/TagsInput.vue.d.ts.map +0 -1
- package/dist/packages/primitives/tags-input/src/index.d.ts.map +0 -1
- package/dist/packages/primitives/text-field/src/TextField.vue.d.ts.map +0 -1
- package/dist/packages/primitives/text-field/src/index.d.ts.map +0 -1
- package/dist/packages/primitives/textarea/src/Textarea.vue.d.ts.map +0 -1
- package/dist/packages/primitives/textarea/src/index.d.ts.map +0 -1
- package/dist/packages/primitives/time-picker/src/TimePicker.vue.d.ts.map +0 -1
- package/dist/packages/primitives/toast/src/Toast.vue.d.ts.map +0 -1
- package/dist/packages/primitives/toast/src/ToastItem.vue.d.ts.map +0 -1
- package/dist/packages/primitives/toast/src/index.d.ts.map +0 -1
- package/dist/packages/primitives/window-controls/src/WindowControls.vue.d.ts.map +0 -1
- package/dist/packages/primitives/window-controls/src/index.d.ts.map +0 -1
- package/dist/styles/theme.contrast.test.ts +0 -460
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileUpload.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../../../packages/primitives/file-upload/src/FileUpload.vue"],"sourcesContent":["<script lang=\"ts\">\nimport type { FileUploadLabels, FileUploadRejection } from \"@ecoma-io/loom-labels\";\n\nconst BYTE_UNITS = [\"B\", \"KB\", \"MB\", \"GB\"] as const;\n\n/**\n * A byte count as a person reads it.\n *\n * Binary steps with the short decimal names, which is what every operating\n * system file dialog beside this control shows — a reader comparing \"1.4 MB\"\n * here against \"1.4 MB\" in their own file browser should see the same number,\n * and the pedantically-correct \"1.5 MB\" (or \"1.4 MiB\") only reads as a bug.\n * One decimal below ten and none above it, so the size column stays the same\n * width down the list.\n *\n * Deliberately not exported: it is a formatter this control needs, not a\n * public utility, and the moment a host imports it from here the wording of a\n * file size becomes part of this component's API.\n */\nfunction formatBytes(bytes: number): string {\n let value = Math.max(bytes, 0);\n let step = 0;\n while (value >= 1024 && step < BYTE_UNITS.length - 1) {\n value /= 1024;\n step += 1;\n }\n const rounded = step > 0 && value < 10 ? Math.round(value * 10) / 10 : Math.round(value);\n return `${String(rounded)} ${BYTE_UNITS[step] ?? \"B\"}`;\n}\n\n/**\n * Every refusal names the file, because the reader is looking at a list of\n * several and \"that file is too large\" identifies none of them.\n */\nfunction describeRejection(rejection: FileUploadRejection, limit: string): string {\n const name = rejection.file.name;\n switch (rejection.reason) {\n case \"too-large\":\n return `${name} is larger than ${limit}.`;\n case \"type\":\n return `${name} is not an accepted file type.`;\n case \"duplicate\":\n return `${name} has already been chosen.`;\n case \"too-many\":\n return `${name} was not added — only one file can be chosen.`;\n }\n}\n\n/**\n * Loom's English, co-located with the component so it tree-shakes with it, and\n * exported so a host can build a partial vocabulary against the real thing.\n */\nexport const FILE_UPLOAD_LABELS: FileUploadLabels = {\n zone: ({ multiple }) =>\n multiple ? \"Choose files or drag them here\" : \"Choose a file or drag it here\",\n hint: ({ maxSize }) => `Up to ${formatBytes(maxSize)}`,\n size: ({ bytes }) => formatBytes(bytes),\n remove: ({ file }) => `Remove ${file.name}`,\n rejected: ({ rejections, maxSize }) => {\n const limit = maxSize === undefined ? \"the size limit\" : formatBytes(maxSize);\n return rejections.map((rejection) => describeRejection(rejection, limit)).join(\" \");\n },\n};\n</script>\n\n<script setup lang=\"ts\">\nimport { computed, ref, useId, useTemplateRef } from \"vue\";\nimport { CloudUpload, File as FileIcon, TriangleAlert, X } from \"@lucide/vue\";\nimport { cn } from \"@ecoma-io/loom-core\";\nimport { listStaggerDelay } from \"@ecoma-io/loom-core\";\nimport { useSplitAttrs } from \"@ecoma-io/loom-core\";\nimport { useAncestorDisabled } from \"@ecoma-io/loom-labels\";\nimport { useFieldControl } from \"@ecoma-io/loom-labels\";\nimport { useLabels, type LabelOverrides } from \"@ecoma-io/loom-labels\";\n\n/**\n * FileUpload — choosing files, and nothing else. A drop zone that is also a\n * real file dialog, plus the list of what has been chosen so far, with each\n * row removable.\n *\n * **It chooses; it does not upload.** There is no progress bar here and no\n * request: the host reads `modelValue`, sends it wherever it goes, and renders\n * `Progress` (or `Spinner`, when there is no percentage) for that half. Two\n * controls rather than one, because the upload's states — retrying, partial,\n * failed on the server — belong to whatever is doing the uploading, and a\n * control that owned both would have to guess at all of them.\n *\n * **Drag and drop is a shortcut, never the path.** The zone is a `<label>`\n * wrapped around a real `<input type=\"file\">`, visually hidden by the clip\n * technique rather than by `display: none` or `hidden` — both of which take\n * the input out of the tab order and leave a control only a pointer can reach.\n * Tab lands on the input, Space or Enter opens the system file dialog, and the\n * zone draws the focus ring on its behalf because a 1px input cannot show one.\n * A `div` with a click handler in place of that input is the standard defect\n * in this control, and it is invisible to everyone testing with a mouse.\n *\n * Files arriving while `multiple` is set are appended to the list rather than\n * replacing it: a reader who drops two files and then a third means three, and\n * the native input's replace-everything behaviour is the surprise. Without\n * `multiple` the newest choice replaces the old one, exactly as the input does.\n *\n * Inside a [Field](../Field/Field.vue) it wires itself through\n * `useFieldControl()`: the row's id lands on the input (and on the `<label>`'s\n * `for`, so the zone keeps activating it), and the row's `name`, `required`,\n * `invalid` and the id of its hint or error line arrive with it. The row's\n * description is **merged** with this control's own refusal message rather than\n * replacing it — a file turned away for being too large has to keep saying so.\n *\n * There is no `readonly`, and a row's is ignored rather than approximated.\n * `readonly` is inert on `<input type=\"file\">` in every browser, for the reason\n * it is inert on a checkbox: there is no text to protect, only a dialog to\n * open. A zone that may be read but not added to is a disabled zone above a\n * list — and the list, which is where the value actually is, stays readable\n * either way.\n */\nconst props = withDefaults(\n defineProps<{\n /** The chosen files. Leave it unbound to let the control keep its own list. */\n modelValue?: File[] | undefined;\n /** What the file dialog offers and what a drop is checked against — the native `accept` syntax: `.csv`, `image/png`, `image/*`, comma-separated. */\n accept?: string;\n /** Allows more than one file, and appends each new choice to the list instead of replacing it. */\n multiple?: boolean;\n /** Largest file accepted, in bytes. A file over it is refused and named in the message. */\n maxSize?: number;\n /** Unavailable: dims the zone, refuses the dialog, the drop and every remove button. Unset defers to a wrapping Field. */\n disabled?: boolean | undefined;\n /** Error state: paints the destructive border and ring, and sets `aria-invalid` on the input. Unset defers to a wrapping Field's `error`. */\n invalid?: boolean | undefined;\n /** The zone's own line of copy, which is also the input's accessible name. Defaults to `labels.zone`, whose wording matches `multiple`. */\n label?: string;\n /** The smaller line under it. Defaults to `labels.hint` against the `maxSize` limit, when there is one. */\n hint?: string;\n /**\n * Everything this control says that is not a file name, as any subset of\n * `FileUploadLabels` — the rest stay as the host's `provideLoomLabels`\n * vocabulary left them, and then as Loom's English.\n *\n * This is the per-instance correction, not the place to localise an\n * application. `label` and `hint` are the shorter way to reach the two\n * keys of the same name for one zone; this is what reaches the refusal\n * message, the remove buttons and the size column.\n */\n labels?: LabelOverrides<FileUploadLabels>;\n }>(),\n {\n // Not `[]`. An empty array is a concrete value, so it would say \"the host\n // owns this list\" — and a host that binds nothing would then watch every\n // file it chose vanish on the next render. `undefined` is what leaves the\n // control managing its own, the same distinction `optional()` exists to\n // preserve for the Reka-backed primitives.\n modelValue: undefined,\n multiple: false,\n // Not `false`, for either. `false` is a caller saying \"this zone is fine /\n // enabled even though its row is not\"; absent is a caller saying nothing,\n // and only `undefined` survives to mean that past Vue's\n // absent-Boolean-casts-to-false rule — see TextField.vue, which carries the\n // full reasoning.\n disabled: undefined,\n invalid: undefined,\n },\n);\n\nconst emit = defineEmits<{\n /** The full list after the change — files added, or one removed. Never a partial list. */\n \"update:modelValue\": [files: File[]];\n /** Every file refused by this one interaction, each with the rule that refused it. Fires once per interaction, not once per file. */\n reject: [rejections: FileUploadRejection[]];\n}>();\n\n// `text`, not `labels`: the prop of that name is one of the three sources this\n// resolves, and a template reading the raw prop would be reading the overrides\n// rather than the answer.\nconst text = useLabels(\"fileUpload\", FILE_UPLOAD_LABELS, () => props.labels);\n\n// `class` sizes the whole control, so it lands on the root; everything else a\n// caller passes — `name`, `id`, `data-testid`, `aria-describedby` — describes\n// the real `<input type=\"file\">` and lands there. Splitting them is the only\n// way to route both correctly: the root is not a form control and the input is\n// not the box a caller lays out.\ndefineOptions({ inheritAttrs: false });\nconst { attrs, rest: inputAttrs } = useSplitAttrs();\n\n// The label's `for` needs the input's id, and a caller passing their own id —\n// or a Field row publishing one — must not end up with a label pointing at\n// nothing. `inputId` is resolved from `field` at the foot of this block.\nconst generatedId = useId();\nconst messageId = useId();\n\nconst ownFiles = ref<File[]>([]);\nconst files = computed(() => props.modelValue ?? ownFiles.value);\n\nconst rejections = ref<FileUploadRejection[]>([]);\n\n/**\n * A stable key per file, held against the File object itself.\n *\n * Keying the rows by index instead re-keys every row after the one removed, so\n * removing the first of five replays the entrance animation on the other four\n * — the list appears to reload because one row left it. A WeakMap keys by\n * identity, holds nothing alive, and survives the list being reordered.\n */\nconst rowIds = new WeakMap<File, number>();\nlet nextRowId = 0;\nfunction rowId(file: File): number {\n let id = rowIds.get(file);\n if (id === undefined) {\n id = nextRowId++;\n rowIds.set(file, id);\n }\n return id;\n}\n\n/** Name, size and mtime — what the file system itself calls the same file. */\nfunction signature(file: File): string {\n return `${file.name}:${String(file.size)}:${String(file.lastModified)}`;\n}\n\n/**\n * The same test the native input applies to `accept`, applied again to a drop\n * — the browser enforces it in the file dialog and not at all on a drag, so a\n * zone that only sets the attribute accepts anything dropped on it.\n *\n * `file.type` is the browser's guess from the extension and it is empty for\n * anything it does not recognise, which is why an `accept` written as MIME\n * types alone turns away files it meant to take. Naming both — `.csv,text/csv`\n * — is the form that works, and it is what the documentation shows.\n */\nfunction accepts(file: File): boolean {\n const accept = props.accept?.trim();\n if (accept === undefined || accept.length === 0) return true;\n const name = file.name.toLowerCase();\n const type = file.type.toLowerCase();\n return accept.split(\",\").some((raw) => {\n const pattern = raw.trim().toLowerCase();\n if (pattern.length === 0) return false;\n if (pattern.startsWith(\".\")) return name.endsWith(pattern);\n if (pattern.endsWith(\"/*\")) return type.startsWith(pattern.slice(0, -1));\n return type === pattern;\n });\n}\n\nfunction commit(next: File[]): void {\n if (props.modelValue === undefined) ownFiles.value = next;\n emit(\"update:modelValue\", next);\n}\n\n/** Runs the offered files past every rule, keeping what passes and reporting the rest. */\nfunction add(incoming: File[]): void {\n if (field.disabled) return;\n\n const current = files.value;\n const kept = props.multiple ? [...current] : [];\n const seen = new Set(kept.map(signature));\n const refused: FileUploadRejection[] = [];\n const limit = props.maxSize;\n\n for (const file of incoming) {\n if (!props.multiple && kept.length > 0) {\n refused.push({ file, reason: \"too-many\" });\n } else if (limit !== undefined && file.size > limit) {\n refused.push({ file, reason: \"too-large\" });\n } else if (!accepts(file)) {\n refused.push({ file, reason: \"type\" });\n } else if (seen.has(signature(file))) {\n refused.push({ file, reason: \"duplicate\" });\n } else {\n seen.add(signature(file));\n kept.push(file);\n }\n }\n\n rejections.value = refused;\n if (refused.length > 0) emit(\"reject\", refused);\n\n const unchanged = kept.length === current.length && kept.every((file, i) => file === current[i]);\n if (!unchanged) commit(kept);\n}\n\nfunction remove(index: number): void {\n if (field.disabled) return;\n // The message named files from the last selection. Once the reader edits the\n // list themselves it no longer describes anything on screen, and an error\n // sitting under a list somebody is actively fixing reads as an error about\n // that list.\n rejections.value = [];\n commit(files.value.filter((_, i) => i !== index));\n}\n\nfunction onSelect(event: Event): void {\n const input = event.target as HTMLInputElement;\n add(Array.from(input.files ?? []));\n // Cleared so choosing the same file a second time still fires `change`. The\n // input compares the new selection against its own value and stays silent\n // when they match — which, after a file has been removed from the list, is a\n // control that refuses to take back the file the reader just took out.\n input.value = \"\";\n}\n\n/**\n * Enters minus leaves, rather than a boolean.\n *\n * `dragleave` fires on the zone every time the pointer crosses onto one of its\n * own children, so an enter/leave pair drops the highlight and picks it up\n * again as the reader drags across the icon and the copy — the zone flickers\n * under the cursor at the exact moment it is meant to be saying \"let go here\".\n * A child's `dragenter` always lands before the parent's `dragleave`, so the\n * count never reaches zero until the pointer has genuinely left. `relatedTarget`\n * answers the same question in one line, but it is not reliably populated for a\n * drag that began outside the document — which is every drag this zone sees.\n */\nconst dragDepth = ref(0);\nconst dragging = computed(() => dragDepth.value > 0 && !field.disabled);\n\nfunction onDragEnter(): void {\n dragDepth.value += 1;\n}\n\nfunction onDragLeave(): void {\n dragDepth.value = Math.max(dragDepth.value - 1, 0);\n}\n\nfunction onDragOver(event: DragEvent): void {\n // Without this the browser keeps its default handling, which for a file is\n // \"navigate to it\" — the drop never reaches the zone and the page is gone.\n // Setting dropEffect is what makes the cursor say copy rather than move.\n event.preventDefault();\n if (event.dataTransfer) event.dataTransfer.dropEffect = field.disabled ? \"none\" : \"copy\";\n}\n\nfunction onDrop(event: DragEvent): void {\n event.preventDefault();\n // Reset rather than decrement: the drop consumes the drag, and no matching\n // `dragleave` follows it.\n dragDepth.value = 0;\n add(Array.from(event.dataTransfer?.files ?? []));\n}\n\n// Nothing here listens on `window` or `document`. A page-wide drag handler\n// would be the usual way to stop a file dropped *beside* the zone from\n// navigating the browser away, but a library primitive that installs one\n// silently governs every other drop target on the host's page. That decision\n// is the host's, so the listeners a component cannot tear down are the ones it\n// never registers.\n\n// The two content props sit *above* the resolved label rather than replacing\n// it: `label` is the wording for one zone — \"Drop last month's export here\" —\n// and the label is what every other zone says. Read through `text.` here and\n// not resolved above, so a language switch after mount repaints the copy.\nconst zoneLabel = computed(() => props.label ?? text.value.zone({ multiple: props.multiple }));\n\nconst zoneHint = computed(() => {\n if (props.hint !== undefined) return props.hint;\n // The limit is handed over as a byte count, never as `formatBytes` output: a\n // host that writes `1,5 Mo` or Eastern Arabic digits cannot get there from a\n // string this component already decided the shape of.\n return props.maxSize === undefined ? undefined : text.value.hint({ maxSize: props.maxSize });\n});\n\n// One call over the whole list rather than one per refusal joined with a\n// space. The joiner was the fragment: which character separates two sentences\n// is a property of the script, and a language that would rather count the\n// refused files than list them has no way to say so from a per-file message.\nconst message = computed(() =>\n rejections.value.length === 0\n ? \"\"\n : text.value.rejected({ rejections: rejections.value, maxSize: props.maxSize }),\n);\n\n/**\n * The drop is the reason this control cannot be left to the platform.\n *\n * `<fieldset disabled>` makes the nested `<input type=\"file\">` inert, which\n * closes the click and the keyboard, and it makes each file's remove button\n * inert too. It does nothing at all to the `drop` handler, because that sits on\n * a `<label>` — not a form control, and never disabled by a fieldset. `add()`\n * bails on `field.disabled`, which is exactly the value a disabled fieldset\n * does not reach, so a zone inside a disabled group accepted a dragged file\n * while refusing every other way in.\n *\n * Read off the DOM rather than taken from the Field context, which publishes no\n * `disabled` on purpose — see `../../lib/ancestor-disabled.ts`.\n */\nconst root = useTemplateRef<HTMLElement>(\"root\");\nconst groupDisabled = useAncestorDisabled(() => root.value);\n\n// The Field wiring sits here, below `message`, because it reads it: this is the\n// one control in the family that already had something of its own to say about\n// itself, so its `describedBy` is a *merge* and not a hand-over. Its refusal\n// message reads first — a file turned away for being too large is the most\n// specific thing there is to say — then whatever the caller pointed at, then\n// the row's hint or error, which `useFieldControl` appends. Replacing rather\n// than merging at either end is how a rejection stops being announced.\n//\n// The condition is `message` itself, not `rejections`, so the id can never\n// point at a `<p>` the template has not rendered.\n//\n// `name` and `required` are absent from the object because this component has\n// no prop for either: the row's answer stands unopposed, and its `name` reaches\n// the real `<input type=\"file\">`, which is what a `<form>` posts. `readonly` is\n// absent for the reason the docblock gives.\nconst field = useFieldControl(() => ({\n id: attrs.id as string | undefined,\n describedBy: [message.value.length > 0 ? messageId : undefined, attrs[\"aria-describedby\"]]\n .filter((id): id is string => typeof id === \"string\" && id.length > 0)\n .join(\" \"),\n // The fieldset beats the prop in both directions, exactly as it does for the\n // `<input type=\"file\">` inside this very control.\n disabled: groupDisabled.value ? true : props.disabled,\n invalid: props.invalid,\n}));\n\n// `field.id` is the caller's own id, then the row's; the generated one is the\n// floor beneath both, because the `<label for>` and the input have to agree on\n// an id whether or not anybody supplied one.\nconst inputId = computed(() => field.id ?? generatedId);\n</script>\n\n<template>\n <div ref=\"root\" :class=\"cn('flex w-full flex-col', attrs.class as string)\">\n <!-- The drag handlers sit on a <label>, which the rule reads as a static\n element — and it is usually right to: a box with a drop handler and\n nothing else is a control no keyboard can reach. Here the keyboard\n path is the real <input type=\"file\"> nested inside, which the label\n both names and activates, so the drop adds a pointer shortcut to a\n control that already works without one. -->\n <!-- eslint-disable-next-line vuejs-accessibility/no-static-element-interactions -->\n <label\n :for=\"inputId\"\n :data-dragging=\"dragging || undefined\"\n :data-invalid=\"field.invalid || undefined\"\n :data-disabled=\"field.disabled || undefined\"\n :class=\"\n cn(\n // `group` so the two lines of copy below can name their own disabled\n // colour off this element's state. A colour set here would only be\n // *inherited* by them, and both declare a colour of their own — an\n // inherited value loses to any declaration, however weak.\n 'group flex flex-col items-center justify-center gap-2 rounded-md border border-dashed border-input bg-background px-6 py-8 text-center',\n // Border and fill are the drag feedback, so they carry the transition\n // — fast, because a zone that lights up after the pointer has already\n // crossed it is answering a question the reader stopped asking.\n 'transition-[color,background-color,border-color,box-shadow] duration-fast ease-out',\n // Focus lives on the clipped input, which is 1px and can show a reader\n // nothing. The zone wears the ring on its behalf, the same\n // focus-within arrangement TextField uses for its own inner input.\n 'focus-within:outline-2 focus-within:outline-offset-2 focus-within:outline-ring',\n !field.invalid && 'focus-within:shadow-halo',\n // The dash going solid is what keeps the drag state off colour alone.\n 'data-[dragging]:border-solid data-[dragging]:border-primary data-[dragging]:bg-primary-muted',\n // Drained, not dimmed. The zone is a large blank region whose whole\n // purpose is the two lines of text in the middle of it, and\n // `opacity-50` took the headline to 3.06:1 and the hint below it to\n // 2.05:1 — the reader least able to guess what a drop zone wants is\n // the one it stopped telling. The fill falls to the neutral well\n // instead, which is where every other unavailable surface in the\n // library goes, and both lines land at 4.67:1 over it. The dash stays,\n // because it is what marks this out as a drop target even while\n // nothing may be dropped on it; only its colour slackens, from\n // `input` to the lighter `border`, so the state is told in a weight\n // as well as in two fills rather than in hue alone.\n field.disabled\n ? 'cursor-not-allowed border-border bg-muted'\n : 'cursor-pointer hover:bg-subtle',\n // Last of the rules naming a border colour, and the order is\n // load-bearing: `cn()` resolves one by whichever class it saw last,\n // so a zone both refusing a file and unavailable would lose its\n // destructive rim to the disabled one if this sat above it.\n field.invalid && 'border-destructive focus-within:outline-destructive',\n )\n \"\n @dragenter=\"onDragEnter\"\n @dragleave=\"onDragLeave\"\n @dragover=\"onDragOver\"\n @drop=\"onDrop\"\n >\n <!-- `field.attrs` spreads **after** the fallthrough attrs, and that\n position is the contract (see TextField.vue): the bag has already\n resolved the caller's own id and merged their description with this\n zone's refusal message and the row's hint, and it drops every key\n that resolved to nothing, so it can only add. The `:aria-invalid` and\n `:aria-describedby` bindings that used to sit here went with it — an\n individual attribute written after a `v-bind` wins, so either one\n kept would overwrite the resolved value with the raw prop.\n\n `:id` is the deliberate exception, and not that failure: `inputId` is\n the bag's own id with the generated one beneath it, so it can only\n ever restate what the bag holds or supply the id the `<label for>`\n needs when the bag holds none. -->\n <input\n v-bind=\"{ ...inputAttrs, ...field.attrs }\"\n :id=\"inputId\"\n type=\"file\"\n :accept=\"accept\"\n :multiple=\"multiple\"\n :disabled=\"field.disabled\"\n class=\"sr-only\"\n @change=\"onSelect\"\n />\n <!-- The medallion, as EmptyState draws it: a 20px glyph alone in a large\n blank region has nothing holding it and reads as a stray mark. -->\n <span\n aria-hidden=\"true\"\n class=\"grid h-10 w-10 place-items-center rounded-full border border-border bg-subtle text-muted-foreground\"\n >\n <CloudUpload class=\"h-5 w-5\" />\n </span>\n <!-- The disabled colour is declared here rather than inherited from the\n zone, for the reason the `group` on it records: this span sets\n `text-foreground` itself, and an inherited value never beats a\n declared one. The hint below needs no such rule — it is already on\n the muted colour, which holds 4.67:1 over the drained fill. -->\n <span class=\"text-sm text-foreground group-data-[disabled]:text-muted-foreground\">{{\n zoneLabel\n }}</span>\n <span v-if=\"zoneHint\" class=\"text-small text-muted-foreground\">{{ zoneHint }}</span>\n </label>\n\n <!-- The region is in the DOM from the first render, empty. A live region\n mounted at the same moment as its text is a region assistive tech was\n not yet watching, so the first refusal — the one that matters most —\n is the one it announces least reliably. -->\n <div aria-live=\"polite\" aria-atomic=\"true\">\n <p\n v-if=\"message.length > 0\"\n :id=\"messageId\"\n class=\"mt-2 flex animate-fade-rise items-start gap-2 text-small text-destructive-text\"\n >\n <TriangleAlert class=\"mt-0.5 h-4 w-4 shrink-0\" aria-hidden=\"true\" />\n <span>{{ message }}</span>\n </p>\n </div>\n\n <ul v-if=\"files.length > 0\" class=\"mt-3 flex flex-col gap-1.5\">\n <li\n v-for=\"(file, index) in files\"\n :key=\"rowId(file)\"\n class=\"flex animate-fade-rise items-center gap-2 rounded-md border border-border bg-card px-3 py-2\"\n :style=\"{ animationDelay: listStaggerDelay(index) }\"\n >\n <FileIcon class=\"h-4 w-4 shrink-0 text-muted-foreground\" aria-hidden=\"true\" />\n <span class=\"min-w-0 flex-1 truncate text-sm text-foreground\">{{ file.name }}</span>\n <span class=\"shrink-0 tabular text-small text-muted-foreground\">\n {{ text.size({ bytes: file.size }) }}\n </span>\n <!-- Named with the file it removes. Seven buttons all called \"Remove\"\n are seven identical announcements and one guess about which row a\n reader is on. -->\n <button\n type=\"button\"\n :aria-label=\"text.remove({ file })\"\n :disabled=\"field.disabled\"\n class=\"inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-sm text-muted-foreground transition-colors duration-fast ease-out hover:bg-subtle hover:text-foreground focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo disabled:cursor-not-allowed disabled:opacity-50\"\n @click=\"remove(index)\"\n >\n <X class=\"h-4 w-4\" />\n </button>\n </li>\n </ul>\n </div>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"FileUpload.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../../../packages/primitives/file-upload/src/FileUpload.vue"],"sourcesContent":["<script lang=\"ts\">\nimport type { FileUploadLabels, FileUploadRejection } from \"@ecoma-io/loom-labels\";\n\nconst BYTE_UNITS = [\"B\", \"KB\", \"MB\", \"GB\"] as const;\n\n/**\n * A byte count as a person reads it.\n *\n * Binary steps with the short decimal names, which is what every operating\n * system file dialog beside this control shows — a reader comparing \"1.4 MB\"\n * here against \"1.4 MB\" in their own file browser should see the same number,\n * and the pedantically-correct \"1.5 MB\" (or \"1.4 MiB\") only reads as a bug.\n * One decimal below ten and none above it, so the size column stays the same\n * width down the list.\n *\n * Deliberately not exported: it is a formatter this control needs, not a\n * public utility, and the moment a host imports it from here the wording of a\n * file size becomes part of this component's API.\n */\nfunction formatBytes(bytes: number): string {\n let value = Math.max(bytes, 0);\n let step = 0;\n while (value >= 1024 && step < BYTE_UNITS.length - 1) {\n value /= 1024;\n step += 1;\n }\n const rounded = step > 0 && value < 10 ? Math.round(value * 10) / 10 : Math.round(value);\n return `${String(rounded)} ${BYTE_UNITS[step] ?? \"B\"}`;\n}\n\n/**\n * Every refusal names the file, because the reader is looking at a list of\n * several and \"that file is too large\" identifies none of them.\n */\nfunction describeRejection(rejection: FileUploadRejection, limit: string): string {\n const name = rejection.file.name;\n switch (rejection.reason) {\n case \"too-large\":\n return `${name} is larger than ${limit}.`;\n case \"type\":\n return `${name} is not an accepted file type.`;\n case \"duplicate\":\n return `${name} has already been chosen.`;\n case \"too-many\":\n return `${name} was not added — only one file can be chosen.`;\n }\n}\n\n/**\n * Loom's English, co-located with the component so it tree-shakes with it, and\n * exported so a host can build a partial vocabulary against the real thing.\n */\nexport const FILE_UPLOAD_LABELS: FileUploadLabels = {\n zone: ({ multiple }) =>\n multiple ? \"Choose files or drag them here\" : \"Choose a file or drag it here\",\n hint: ({ maxSize }) => `Up to ${formatBytes(maxSize)}`,\n size: ({ bytes }) => formatBytes(bytes),\n remove: ({ file }) => `Remove ${file.name}`,\n rejected: ({ rejections, maxSize }) => {\n const limit = maxSize === undefined ? \"the size limit\" : formatBytes(maxSize);\n return rejections.map((rejection) => describeRejection(rejection, limit)).join(\" \");\n },\n};\n</script>\n\n<script setup lang=\"ts\">\nimport { computed, ref, useId, useTemplateRef } from \"vue\";\nimport { CloudUpload, File as FileIcon, TriangleAlert, X } from \"@lucide/vue\";\nimport { cn } from \"@ecoma-io/loom-core\";\nimport { listStaggerDelay } from \"@ecoma-io/loom-core\";\nimport { useSplitAttrs } from \"@ecoma-io/loom-core\";\nimport { useAncestorDisabled } from \"@ecoma-io/loom-labels\";\nimport { useFieldControl } from \"@ecoma-io/loom-labels\";\nimport { useLabels, type LabelOverrides } from \"@ecoma-io/loom-labels\";\n\n/**\n * FileUpload — choosing files, and nothing else. A drop zone that is also a\n * real file dialog, plus the list of what has been chosen so far, with each\n * row removable.\n *\n * **It chooses; it does not upload.** There is no progress bar here and no\n * request: the host reads `modelValue`, sends it wherever it goes, and renders\n * `Progress` (or `Spinner`, when there is no percentage) for that half. Two\n * controls rather than one, because the upload's states — retrying, partial,\n * failed on the server — belong to whatever is doing the uploading, and a\n * control that owned both would have to guess at all of them.\n *\n * **Drag and drop is a shortcut, never the path.** The zone is a `<label>`\n * wrapped around a real `<input type=\"file\">`, visually hidden by the clip\n * technique rather than by `display: none` or `hidden` — both of which take\n * the input out of the tab order and leave a control only a pointer can reach.\n * Tab lands on the input, Space or Enter opens the system file dialog, and the\n * zone draws the focus ring on its behalf because a 1px input cannot show one.\n * A `div` with a click handler in place of that input is the standard defect\n * in this control, and it is invisible to everyone testing with a mouse.\n *\n * Files arriving while `multiple` is set are appended to the list rather than\n * replacing it: a reader who drops two files and then a third means three, and\n * the native input's replace-everything behaviour is the surprise. Without\n * `multiple` the newest choice replaces the old one, exactly as the input does.\n *\n * Inside a [Field](../Field/Field.vue) it wires itself through\n * `useFieldControl()`: the row's id lands on the input (and on the `<label>`'s\n * `for`, so the zone keeps activating it), and the row's `name`, `required`,\n * `invalid` and the id of its hint or error line arrive with it. The row's\n * description is **merged** with this control's own refusal message rather than\n * replacing it — a file turned away for being too large has to keep saying so.\n *\n * There is no `readonly`, and a row's is ignored rather than approximated.\n * `readonly` is inert on `<input type=\"file\">` in every browser, for the reason\n * it is inert on a checkbox: there is no text to protect, only a dialog to\n * open. A zone that may be read but not added to is a disabled zone above a\n * list — and the list, which is where the value actually is, stays readable\n * either way.\n */\nconst props = withDefaults(\n defineProps<{\n /** The chosen files. Leave it unbound to let the control keep its own list. */\n modelValue?: File[] | undefined;\n /** What the file dialog offers and what a drop is checked against — the native `accept` syntax: `.csv`, `image/png`, `image/*`, comma-separated. */\n accept?: string;\n /** Allows more than one file, and appends each new choice to the list instead of replacing it. */\n multiple?: boolean;\n /** Largest file accepted, in bytes. A file over it is refused and named in the message. */\n maxSize?: number;\n /** Unavailable: dims the zone, refuses the dialog, the drop and every remove button. Unset defers to a wrapping Field. */\n disabled?: boolean | undefined;\n /** Error state: paints the destructive border and ring, and sets `aria-invalid` on the input. Unset defers to a wrapping Field's `error`. */\n invalid?: boolean | undefined;\n /** The zone's own line of copy, which is also the input's accessible name. Defaults to `labels.zone`, whose wording matches `multiple`. */\n label?: string;\n /** The smaller line under it. Defaults to `labels.hint` against the `maxSize` limit, when there is one. */\n hint?: string;\n /**\n * Everything this control says that is not a file name, as any subset of\n * `FileUploadLabels` — the rest stay as the host's `provideLoomLabels`\n * vocabulary left them, and then as Loom's English.\n *\n * This is the per-instance correction, not the place to localise an\n * application. `label` and `hint` are the shorter way to reach the two\n * keys of the same name for one zone; this is what reaches the refusal\n * message, the remove buttons and the size column.\n */\n labels?: LabelOverrides<FileUploadLabels>;\n }>(),\n {\n // Not `[]`. An empty array is a concrete value, so it would say \"the host\n // owns this list\" — and a host that binds nothing would then watch every\n // file it chose vanish on the next render. `undefined` is what leaves the\n // control managing its own, the same distinction `optional()` exists to\n // preserve for the Reka-backed primitives.\n modelValue: undefined,\n multiple: false,\n // Not `false`, for either. `false` is a caller saying \"this zone is fine /\n // enabled even though its row is not\"; absent is a caller saying nothing,\n // and only `undefined` survives to mean that past Vue's\n // absent-Boolean-casts-to-false rule — see TextField.vue, which carries the\n // full reasoning.\n disabled: undefined,\n invalid: undefined,\n },\n);\n\nconst emit = defineEmits<{\n /** The full list after the change — files added, or one removed. Never a partial list. */\n \"update:modelValue\": [files: File[]];\n /** Every file refused by this one interaction, each with the rule that refused it. Fires once per interaction, not once per file. */\n reject: [rejections: FileUploadRejection[]];\n}>();\n\n// `text`, not `labels`: the prop of that name is one of the three sources this\n// resolves, and a template reading the raw prop would be reading the overrides\n// rather than the answer.\nconst text = useLabels(\"fileUpload\", FILE_UPLOAD_LABELS, () => props.labels);\n\n// `class` sizes the whole control, so it lands on the root; everything else a\n// caller passes — `name`, `id`, `data-testid`, `aria-describedby` — describes\n// the real `<input type=\"file\">` and lands there. Splitting them is the only\n// way to route both correctly: the root is not a form control and the input is\n// not the box a caller lays out.\ndefineOptions({ inheritAttrs: false });\nconst { attrs, rest: inputAttrs } = useSplitAttrs();\n\n// The label's `for` needs the input's id, and a caller passing their own id —\n// or a Field row publishing one — must not end up with a label pointing at\n// nothing. `inputId` is resolved from `field` at the foot of this block.\nconst generatedId = useId();\nconst messageId = useId();\n\nconst ownFiles = ref<File[]>([]);\nconst files = computed(() => props.modelValue ?? ownFiles.value);\n\nconst rejections = ref<FileUploadRejection[]>([]);\n\n/**\n * A stable key per file, held against the File object itself.\n *\n * Keying the rows by index instead re-keys every row after the one removed, so\n * removing the first of five replays the entrance animation on the other four\n * — the list appears to reload because one row left it. A WeakMap keys by\n * identity, holds nothing alive, and survives the list being reordered.\n */\nconst rowIds = new WeakMap<File, number>();\nlet nextRowId = 0;\nfunction rowId(file: File): number {\n let id = rowIds.get(file);\n if (id === undefined) {\n id = nextRowId++;\n rowIds.set(file, id);\n }\n return id;\n}\n\n/** Name, size and mtime — what the file system itself calls the same file. */\nfunction signature(file: File): string {\n return `${file.name}:${String(file.size)}:${String(file.lastModified)}`;\n}\n\n/**\n * The same test the native input applies to `accept`, applied again to a drop\n * — the browser enforces it in the file dialog and not at all on a drag, so a\n * zone that only sets the attribute accepts anything dropped on it.\n *\n * `file.type` is the browser's guess from the extension and it is empty for\n * anything it does not recognise, which is why an `accept` written as MIME\n * types alone turns away files it meant to take. Naming both — `.csv,text/csv`\n * — is the form that works, and it is what the documentation shows.\n */\nfunction accepts(file: File): boolean {\n const accept = props.accept?.trim();\n if (accept === undefined || accept.length === 0) return true;\n const name = file.name.toLowerCase();\n const type = file.type.toLowerCase();\n return accept.split(\",\").some((raw) => {\n const pattern = raw.trim().toLowerCase();\n if (pattern.length === 0) return false;\n if (pattern.startsWith(\".\")) return name.endsWith(pattern);\n if (pattern.endsWith(\"/*\")) return type.startsWith(pattern.slice(0, -1));\n return type === pattern;\n });\n}\n\nfunction commit(next: File[]): void {\n if (props.modelValue === undefined) ownFiles.value = next;\n emit(\"update:modelValue\", next);\n}\n\n/** Runs the offered files past every rule, keeping what passes and reporting the rest. */\nfunction add(incoming: File[]): void {\n if (field.disabled) return;\n\n const current = files.value;\n const kept = props.multiple ? [...current] : [];\n const seen = new Set(kept.map(signature));\n const refused: FileUploadRejection[] = [];\n const limit = props.maxSize;\n\n for (const file of incoming) {\n if (!props.multiple && kept.length > 0) {\n refused.push({ file, reason: \"too-many\" });\n } else if (limit !== undefined && file.size > limit) {\n refused.push({ file, reason: \"too-large\" });\n } else if (!accepts(file)) {\n refused.push({ file, reason: \"type\" });\n } else if (seen.has(signature(file))) {\n refused.push({ file, reason: \"duplicate\" });\n } else {\n seen.add(signature(file));\n kept.push(file);\n }\n }\n\n rejections.value = refused;\n if (refused.length > 0) emit(\"reject\", refused);\n\n const unchanged = kept.length === current.length && kept.every((file, i) => file === current[i]);\n if (!unchanged) commit(kept);\n}\n\nfunction remove(index: number): void {\n if (field.disabled) return;\n // The message named files from the last selection. Once the reader edits the\n // list themselves it no longer describes anything on screen, and an error\n // sitting under a list somebody is actively fixing reads as an error about\n // that list.\n rejections.value = [];\n commit(files.value.filter((_, i) => i !== index));\n}\n\nfunction onSelect(event: Event): void {\n const input = event.target as HTMLInputElement;\n add(Array.from(input.files ?? []));\n // Cleared so choosing the same file a second time still fires `change`. The\n // input compares the new selection against its own value and stays silent\n // when they match — which, after a file has been removed from the list, is a\n // control that refuses to take back the file the reader just took out.\n input.value = \"\";\n}\n\n/**\n * Enters minus leaves, rather than a boolean.\n *\n * `dragleave` fires on the zone every time the pointer crosses onto one of its\n * own children, so an enter/leave pair drops the highlight and picks it up\n * again as the reader drags across the icon and the copy — the zone flickers\n * under the cursor at the exact moment it is meant to be saying \"let go here\".\n * A child's `dragenter` always lands before the parent's `dragleave`, so the\n * count never reaches zero until the pointer has genuinely left. `relatedTarget`\n * answers the same question in one line, but it is not reliably populated for a\n * drag that began outside the document — which is every drag this zone sees.\n */\nconst dragDepth = ref(0);\nconst dragging = computed(() => dragDepth.value > 0 && !field.disabled);\n\nfunction onDragEnter(): void {\n dragDepth.value += 1;\n}\n\nfunction onDragLeave(): void {\n dragDepth.value = Math.max(dragDepth.value - 1, 0);\n}\n\nfunction onDragOver(event: DragEvent): void {\n // Without this the browser keeps its default handling, which for a file is\n // \"navigate to it\" — the drop never reaches the zone and the page is gone.\n // Setting dropEffect is what makes the cursor say copy rather than move.\n event.preventDefault();\n if (event.dataTransfer) event.dataTransfer.dropEffect = field.disabled ? \"none\" : \"copy\";\n}\n\nfunction onDrop(event: DragEvent): void {\n event.preventDefault();\n // Reset rather than decrement: the drop consumes the drag, and no matching\n // `dragleave` follows it.\n dragDepth.value = 0;\n add(Array.from(event.dataTransfer?.files ?? []));\n}\n\n// Nothing here listens on `window` or `document`. A page-wide drag handler\n// would be the usual way to stop a file dropped *beside* the zone from\n// navigating the browser away, but a library primitive that installs one\n// silently governs every other drop target on the host's page. That decision\n// is the host's, so the listeners a component cannot tear down are the ones it\n// never registers.\n\n// The two content props sit *above* the resolved label rather than replacing\n// it: `label` is the wording for one zone — \"Drop last month's export here\" —\n// and the label is what every other zone says. Read through `text.` here and\n// not resolved above, so a language switch after mount repaints the copy.\nconst zoneLabel = computed(() => props.label ?? text.value.zone({ multiple: props.multiple }));\n\nconst zoneHint = computed(() => {\n if (props.hint !== undefined) return props.hint;\n // The limit is handed over as a byte count, never as `formatBytes` output: a\n // host that writes `1,5 Mo` or Eastern Arabic digits cannot get there from a\n // string this component already decided the shape of.\n return props.maxSize === undefined ? undefined : text.value.hint({ maxSize: props.maxSize });\n});\n\n// One call over the whole list rather than one per refusal joined with a\n// space. The joiner was the fragment: which character separates two sentences\n// is a property of the script, and a language that would rather count the\n// refused files than list them has no way to say so from a per-file message.\nconst message = computed(() =>\n rejections.value.length === 0\n ? \"\"\n : text.value.rejected({ rejections: rejections.value, maxSize: props.maxSize }),\n);\n\n/**\n * The drop is the reason this control cannot be left to the platform.\n *\n * `<fieldset disabled>` makes the nested `<input type=\"file\">` inert, which\n * closes the click and the keyboard, and it makes each file's remove button\n * inert too. It does nothing at all to the `drop` handler, because that sits on\n * a `<label>` — not a form control, and never disabled by a fieldset. `add()`\n * bails on `field.disabled`, which is exactly the value a disabled fieldset\n * does not reach, so a zone inside a disabled group accepted a dragged file\n * while refusing every other way in.\n *\n * Read off the DOM rather than taken from the Field context, which publishes no\n * `disabled` on purpose — see `../../lib/ancestor-disabled.ts`.\n */\nconst root = useTemplateRef<HTMLElement>(\"root\");\nconst groupDisabled = useAncestorDisabled(() => root.value);\n\n// The Field wiring sits here, below `message`, because it reads it: this is the\n// one control in the family that already had something of its own to say about\n// itself, so its `describedBy` is a *merge* and not a hand-over. Its refusal\n// message reads first — a file turned away for being too large is the most\n// specific thing there is to say — then whatever the caller pointed at, then\n// the row's hint or error, which `useFieldControl` appends. Replacing rather\n// than merging at either end is how a rejection stops being announced.\n//\n// The condition is `message` itself, not `rejections`, so the id can never\n// point at a `<p>` the template has not rendered.\n//\n// `name` and `required` are absent from the object because this component has\n// no prop for either: the row's answer stands unopposed, and its `name` reaches\n// the real `<input type=\"file\">`, which is what a `<form>` posts. `readonly` is\n// absent for the reason the docblock gives.\nconst field = useFieldControl(() => ({\n id: attrs.id as string | undefined,\n describedBy: [message.value.length > 0 ? messageId : undefined, attrs[\"aria-describedby\"]]\n .filter((id): id is string => typeof id === \"string\" && id.length > 0)\n .join(\" \"),\n // The fieldset beats the prop in both directions, exactly as it does for the\n // `<input type=\"file\">` inside this very control.\n disabled: groupDisabled.value ? true : props.disabled,\n invalid: props.invalid,\n}));\n\n// `field.id` is the caller's own id, then the row's; the generated one is the\n// floor beneath both, because the `<label for>` and the input have to agree on\n// an id whether or not anybody supplied one.\nconst inputId = computed(() => field.id ?? generatedId);\n</script>\n\n<template>\n <div ref=\"root\" :class=\"cn('flex w-full flex-col', attrs.class as string)\">\n <!-- The drag handlers sit on a <label>, which the rule reads as a static\n element — and it is usually right to: a box with a drop handler and\n nothing else is a control no keyboard can reach. Here the keyboard\n path is the real <input type=\"file\"> nested inside, which the label\n both names and activates, so the drop adds a pointer shortcut to a\n control that already works without one. -->\n <!-- eslint-disable-next-line vuejs-accessibility/no-static-element-interactions -->\n <label\n :for=\"inputId\"\n :data-dragging=\"dragging || undefined\"\n :data-invalid=\"field.invalid || undefined\"\n :data-disabled=\"field.disabled || undefined\"\n :class=\"\n cn(\n // `group` so the two lines of copy below can name their own disabled\n // colour off this element's state. A colour set here would only be\n // *inherited* by them, and both declare a colour of their own — an\n // inherited value loses to any declaration, however weak.\n 'group flex flex-col items-center justify-center gap-2 rounded-md border border-dashed border-input bg-background px-6 py-8 text-center',\n // Border and fill are the drag feedback, so they carry the transition\n // — fast, because a zone that lights up after the pointer has already\n // crossed it is answering a question the reader stopped asking.\n 'transition-[color,background-color,border-color,box-shadow] duration-fast ease-out',\n // Focus lives on the clipped input, which is 1px and can show a reader\n // nothing. The zone wears the ring on its behalf, the same\n // focus-within arrangement TextField uses for its own inner input.\n 'focus-within:outline-2 focus-within:outline-offset-2 focus-within:outline-ring',\n !field.invalid && 'focus-within:shadow-halo',\n // The dash going solid is what keeps the drag state off colour alone.\n 'data-[dragging]:border-solid data-[dragging]:border-primary data-[dragging]:bg-primary-muted',\n // Drained, not dimmed. The zone is a large blank region whose whole\n // purpose is the two lines of text in the middle of it, and\n // `opacity-50` took the headline to 3.06:1 and the hint below it to\n // 2.05:1 — the reader least able to guess what a drop zone wants is\n // the one it stopped telling. The fill falls to the neutral well\n // instead, which is where every other unavailable surface in the\n // library goes, and both lines land at 4.67:1 over it. The dash stays,\n // because it is what marks this out as a drop target even while\n // nothing may be dropped on it; only its colour slackens, from\n // `input` to the lighter `border`, so the state is told in a weight\n // as well as in two fills rather than in hue alone.\n field.disabled\n ? 'cursor-not-allowed border-border bg-muted'\n : 'cursor-pointer hover:bg-subtle',\n // Last of the rules naming a border colour, and the order is\n // load-bearing: `cn()` resolves one by whichever class it saw last,\n // so a zone both refusing a file and unavailable would lose its\n // destructive rim to the disabled one if this sat above it.\n field.invalid && 'border-destructive focus-within:outline-destructive',\n )\n \"\n @dragenter=\"onDragEnter\"\n @dragleave=\"onDragLeave\"\n @dragover=\"onDragOver\"\n @drop=\"onDrop\"\n >\n <!-- `field.attrs` spreads **after** the fallthrough attrs, and that\n position is the contract (see TextField.vue): the bag has already\n resolved the caller's own id and merged their description with this\n zone's refusal message and the row's hint, and it drops every key\n that resolved to nothing, so it can only add. The `:aria-invalid` and\n `:aria-describedby` bindings that used to sit here went with it — an\n individual attribute written after a `v-bind` wins, so either one\n kept would overwrite the resolved value with the raw prop.\n\n `:id` is the deliberate exception, and not that failure: `inputId` is\n the bag's own id with the generated one beneath it, so it can only\n ever restate what the bag holds or supply the id the `<label for>`\n needs when the bag holds none. -->\n <input\n v-bind=\"{ ...inputAttrs, ...field.attrs }\"\n :id=\"inputId\"\n type=\"file\"\n :accept=\"accept\"\n :multiple=\"multiple\"\n :disabled=\"field.disabled\"\n class=\"sr-only\"\n @change=\"onSelect\"\n />\n <!-- The medallion, as EmptyState draws it: a 20px glyph alone in a large\n blank region has nothing holding it and reads as a stray mark. -->\n <span\n aria-hidden=\"true\"\n class=\"grid h-10 w-10 place-items-center rounded-full border border-border bg-subtle text-muted-foreground\"\n >\n <CloudUpload class=\"h-5 w-5\" />\n </span>\n <!-- The disabled colour is declared here rather than inherited from the\n zone, for the reason the `group` on it records: this span sets\n `text-foreground` itself, and an inherited value never beats a\n declared one. The hint below needs no such rule — it is already on\n the muted colour, which holds 4.67:1 over the drained fill. -->\n <span class=\"text-sm text-foreground group-data-[disabled]:text-muted-foreground\">{{\n zoneLabel\n }}</span>\n <span v-if=\"zoneHint\" class=\"text-small text-muted-foreground\">{{ zoneHint }}</span>\n </label>\n\n <!-- The region is in the DOM from the first render, empty. A live region\n mounted at the same moment as its text is a region assistive tech was\n not yet watching, so the first refusal — the one that matters most —\n is the one it announces least reliably. -->\n <div aria-live=\"polite\" aria-atomic=\"true\">\n <p\n v-if=\"message.length > 0\"\n :id=\"messageId\"\n class=\"mt-2 flex animate-fade-rise items-start gap-2 text-small text-destructive-text\"\n >\n <TriangleAlert class=\"mt-0.5 h-4 w-4 shrink-0\" aria-hidden=\"true\" />\n <span>{{ message }}</span>\n </p>\n </div>\n\n <ul v-if=\"files.length > 0\" class=\"mt-3 flex flex-col gap-1.5\">\n <li\n v-for=\"(file, index) in files\"\n :key=\"rowId(file)\"\n class=\"flex animate-fade-rise items-center gap-2 rounded-md border border-border bg-card px-3 py-2\"\n :style=\"{ animationDelay: listStaggerDelay(index) }\"\n >\n <FileIcon class=\"h-4 w-4 shrink-0 text-muted-foreground\" aria-hidden=\"true\" />\n <span class=\"min-w-0 flex-1 truncate text-sm text-foreground\">{{ file.name }}</span>\n <span class=\"shrink-0 tabular text-small text-muted-foreground\">\n {{ text.size({ bytes: file.size }) }}\n </span>\n <!-- Named with the file it removes. Seven buttons all called \"Remove\"\n are seven identical announcements and one guess about which row a\n reader is on. -->\n <!-- Drained, not dimmed: `opacity-50` faded the glyph inside its own\n row card, compositing it below contrast — the failure Button\n records for its dim. The glyph-only control takes the neutral\n well, and the native attribute carries unavailability to AT. -->\n <button\n type=\"button\"\n :aria-label=\"text.remove({ file })\"\n :disabled=\"field.disabled\"\n class=\"inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-sm text-muted-foreground transition-colors duration-fast ease-out hover:bg-subtle hover:text-foreground focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo disabled:cursor-not-allowed disabled:bg-muted disabled:shadow-none\"\n @click=\"remove(index)\"\n >\n <X class=\"h-4 w-4\" />\n </button>\n </li>\n </ul>\n </div>\n</template>\n"],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { default, FILE_UPLOAD_LABELS } from "./FileUpload.vue";
|
|
2
|
-
export type { FileUploadLabels, FileUploadRejectReason, FileUploadRejection, } from "
|
|
2
|
+
export type { FileUploadLabels, FileUploadRejectReason, FileUploadRejection, } from "../../../labels/src/index";
|
|
3
3
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HoverCard.js","names":[],"sources":["../../../../../packages/primitives/hover-card/src/HoverCard.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Which edge of the trigger the card prefers, before collision flipping. The\n * members mirror Reka's own `Side`, and the template binding is what enforces\n * that: a member Reka does not accept stops `:side=\"side\"` type-checking.\n * Declared here rather than aliased so the generated props table prints the\n * four values instead of a name that tells the reader nothing.\n */\nexport type HoverCardSide = \"top\" | \"right\" | \"bottom\" | \"left\";\n\n/**\n * How the card aligns against the trigger along the cross-axis, before\n * collision flipping. Same rationale as `HoverCardSide`.\n */\nexport type HoverCardAlign = \"start\" | \"center\" | \"end\";\n</script>\n\n<script setup lang=\"ts\">\nimport {\n HoverCardRoot,\n HoverCardTrigger,\n HoverCardPortal,\n HoverCardContent,\n HoverCardArrow,\n} from \"reka-ui\";\nimport { cn } from \"@ecoma-io/loom-core\";\nimport { optional } from \"@ecoma-io/loom-core\";\n\n/**\n * HoverCard — a
|
|
1
|
+
{"version":3,"file":"HoverCard.js","names":[],"sources":["../../../../../packages/primitives/hover-card/src/HoverCard.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Which edge of the trigger the card prefers, before collision flipping. The\n * members mirror Reka's own `Side`, and the template binding is what enforces\n * that: a member Reka does not accept stops `:side=\"side\"` type-checking.\n * Declared here rather than aliased so the generated props table prints the\n * four values instead of a name that tells the reader nothing.\n */\nexport type HoverCardSide = \"top\" | \"right\" | \"bottom\" | \"left\";\n\n/**\n * How the card aligns against the trigger along the cross-axis, before\n * collision flipping. Same rationale as `HoverCardSide`.\n */\nexport type HoverCardAlign = \"start\" | \"center\" | \"end\";\n</script>\n\n<script setup lang=\"ts\">\nimport {\n HoverCardRoot,\n HoverCardTrigger,\n HoverCardPortal,\n HoverCardContent,\n HoverCardArrow,\n} from \"reka-ui\";\nimport { cn } from \"@ecoma-io/loom-core\";\nimport { optional } from \"@ecoma-io/loom-core\";\n\n/**\n * HoverCard — a supplementary preview surface on hover, for content the user\n * reads rather than operates.\n *\n * The pointer can travel from the trigger into the card without closing it —\n * the close delay exists for that transit, which is what makes a hover card a\n * complementary surface and a tooltip a non-interactive hint. But that reach\n * is a pointer privilege only. Reka strips `tabindex=\"-1\"` onto every tabbable\n * node inside the content on mount, and the trigger closes the card on blur\n * after `closeDelay` (300ms by default) — so by the time a keyboard user\n * tabbed toward anything inside, the card would already be gone. Interactive\n * content inside a HoverCard is unreachable by keyboard (WCAG 2.1.1), whatever\n * the markup allows.\n *\n * The honest contract: keep the card's content non-interactive — text, an\n * image, a definition — and duplicate anything actionable somewhere reachable.\n * When a preview genuinely needs its own links or buttons, it is not a hover\n * card; it is a `Popover`, whose content takes focus and whose Esc/outside\n * dismissal gives a keyboard user a way in and out.\n *\n * The content is NOT wired as `aria-describedby` — it is a supplementary panel,\n * not an accessible name supplement. A screen reader user who never hovers\n * should still have the trigger's own accessible name, and the card is extra\n * rather than essential.\n */\nwithDefaults(\n defineProps<{\n /** The edge of the trigger to anchor against, before collision flipping. */\n side?: HoverCardSide;\n /** Gap in pixels between the trigger and the card. */\n sideOffset?: number;\n /** Alignment against the trigger along the cross-axis, before collision flipping. */\n align?: HoverCardAlign;\n /** Alignment offset in pixels from the chosen alignment position. */\n alignOffset?: number;\n /** Milliseconds of hover before the card appears. */\n openDelay?: number;\n /** Milliseconds before the card disappears after the pointer leaves both trigger and content. */\n closeDelay?: number;\n /** Drive the card from the host with `v-model:open`. Omit for hover alone. */\n open?: boolean | undefined;\n }>(),\n // `open: undefined` is load-bearing, not a redundant default — it is what\n // keeps the uncontrolled third state reachable past Vue's absent-Boolean\n // casting. `optional()` in the template is the other half; its docblock\n // carries the reasoning for both.\n {\n side: \"bottom\",\n sideOffset: 6,\n align: \"start\",\n alignOffset: 0,\n openDelay: 300,\n closeDelay: 300,\n open: undefined,\n },\n);\n\ndefineEmits<{ \"update:open\": [value: boolean] }>();\n</script>\n\n<template>\n <HoverCardRoot\n :open-delay=\"openDelay\"\n :close-delay=\"closeDelay\"\n v-bind=\"optional({ open })\"\n @update:open=\"$emit('update:open', $event)\"\n >\n <!-- @slot The element that opens the card on hover. Rendered `as-child`, so\n the caller's own element *is* the trigger and keeps its own accessible\n name. -->\n <HoverCardTrigger as-child>\n <slot name=\"trigger\" />\n </HoverCardTrigger>\n\n <HoverCardPortal>\n <HoverCardContent\n :side=\"side\"\n :side-offset=\"sideOffset\"\n :align=\"align\"\n :align-offset=\"alignOffset\"\n :class=\"\n cn(\n 'z-overlay w-64 rounded-md border border-border bg-popover p-4 text-popover-foreground shadow-md outline-none',\n // Both states scoped, never unconditional. Reka's Presence\n // keeps closed content mounted until an animationend arrives, and\n // a mount-only animation never fires a second one — so an\n // unconditional animation class leaves a stray card in the page.\n // Scoped, the closed element computes `animation-name: none` and\n // Presence unmounts it at once; the paired exit is precisely what\n // Presence is waiting to hold it for.\n 'data-[state=open]:animate-scale-in data-[state=closed]:animate-scale-out',\n )\n \"\n style=\"transform-origin: var(--reka-popper-transform-origin)\"\n >\n <!-- @slot The card content. Pointer-reachable, but keep it\n non-interactive — see the component docblock for why keyboard\n users cannot reach anything focusable in here. -->\n <slot />\n <HoverCardArrow class=\"fill-popover\" :width=\"10\" :height=\"5\" />\n </HoverCardContent>\n </HoverCardPortal>\n </HoverCardRoot>\n</template>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HoverCard.vue.d.ts","sourceRoot":"","sources":["../../../../../packages/primitives/hover-card/src/HoverCard.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"HoverCard.vue.d.ts","sourceRoot":"","sources":["../../../../../packages/primitives/hover-card/src/HoverCard.vue"],"names":[],"mappings":"AAkJA;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEhE;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;wBACnC,OAAO,YAAY;AAAxC,wBAAyC;AACzC,QAAA,MAAM,YAAY;IA2Bd,4EAA4E;WACrE,aAAa;IACpB,sDAAsD;iBACzC,MAAM;IACnB,qFAAqF;YAC7E,cAAc;IACtB,qEAAqE;kBACvD,MAAM;IACpB,qDAAqD;gBACzC,MAAM;IAClB,iGAAiG;iBACpF,MAAM;IACnB,8EAA8E;WACvE,OAAO,GAAG,SAAS;;;;IAb1B,4EAA4E;WACrE,aAAa;IACpB,sDAAsD;iBACzC,MAAM;IACnB,qFAAqF;YAC7E,cAAc;IACtB,qEAAqE;kBACvD,MAAM;IACpB,qDAAqD;gBACzC,MAAM;IAClB,iGAAiG;iBACpF,MAAM;IACnB,8EAA8E;WACvE,OAAO,GAAG,SAAS;;;;UAZnB,aAAa;gBAEP,MAAM;WAEX,cAAc;iBAER,MAAM;eAER,MAAM;gBAEL,MAAM;UAEZ,OAAO,GAAG,SAAS;;cAuLhB,CAAC,KAAK,IAAiB,KAAK,GAAG;;cAC/B,CAAC,KAAK,IAAiB,KAAK,GAAG;EAWzC,CAAC;AAWL,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
|
package/dist/packages/primitives/hover-card/src/HoverCard.vue_vue_type_script_setup_true_lang.js
CHANGED
|
@@ -34,7 +34,7 @@ var HoverCard_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ define
|
|
|
34
34
|
"side-offset": __props.sideOffset,
|
|
35
35
|
align: __props.align,
|
|
36
36
|
"align-offset": __props.alignOffset,
|
|
37
|
-
class: normalizeClass(unref(cn)("z-
|
|
37
|
+
class: normalizeClass(unref(cn)("z-overlay w-64 rounded-md border border-border bg-popover p-4 text-popover-foreground shadow-md outline-none", "data-[state=open]:animate-scale-in data-[state=closed]:animate-scale-out")),
|
|
38
38
|
style: { "transform-origin": "var(--reka-popper-transform-origin)" }
|
|
39
39
|
}, {
|
|
40
40
|
default: withCtx(() => [renderSlot(_ctx.$slots, "default"), createVNode(unref(HoverCardArrow), {
|
package/dist/packages/primitives/hover-card/src/HoverCard.vue_vue_type_script_setup_true_lang.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HoverCard.vue_vue_type_script_setup_true_lang.js","names":["$emit"],"sources":["../../../../../packages/primitives/hover-card/src/HoverCard.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Which edge of the trigger the card prefers, before collision flipping. The\n * members mirror Reka's own `Side`, and the template binding is what enforces\n * that: a member Reka does not accept stops `:side=\"side\"` type-checking.\n * Declared here rather than aliased so the generated props table prints the\n * four values instead of a name that tells the reader nothing.\n */\nexport type HoverCardSide = \"top\" | \"right\" | \"bottom\" | \"left\";\n\n/**\n * How the card aligns against the trigger along the cross-axis, before\n * collision flipping. Same rationale as `HoverCardSide`.\n */\nexport type HoverCardAlign = \"start\" | \"center\" | \"end\";\n</script>\n\n<script setup lang=\"ts\">\nimport {\n HoverCardRoot,\n HoverCardTrigger,\n HoverCardPortal,\n HoverCardContent,\n HoverCardArrow,\n} from \"reka-ui\";\nimport { cn } from \"@ecoma-io/loom-core\";\nimport { optional } from \"@ecoma-io/loom-core\";\n\n/**\n * HoverCard — a
|
|
1
|
+
{"version":3,"file":"HoverCard.vue_vue_type_script_setup_true_lang.js","names":["$emit"],"sources":["../../../../../packages/primitives/hover-card/src/HoverCard.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Which edge of the trigger the card prefers, before collision flipping. The\n * members mirror Reka's own `Side`, and the template binding is what enforces\n * that: a member Reka does not accept stops `:side=\"side\"` type-checking.\n * Declared here rather than aliased so the generated props table prints the\n * four values instead of a name that tells the reader nothing.\n */\nexport type HoverCardSide = \"top\" | \"right\" | \"bottom\" | \"left\";\n\n/**\n * How the card aligns against the trigger along the cross-axis, before\n * collision flipping. Same rationale as `HoverCardSide`.\n */\nexport type HoverCardAlign = \"start\" | \"center\" | \"end\";\n</script>\n\n<script setup lang=\"ts\">\nimport {\n HoverCardRoot,\n HoverCardTrigger,\n HoverCardPortal,\n HoverCardContent,\n HoverCardArrow,\n} from \"reka-ui\";\nimport { cn } from \"@ecoma-io/loom-core\";\nimport { optional } from \"@ecoma-io/loom-core\";\n\n/**\n * HoverCard — a supplementary preview surface on hover, for content the user\n * reads rather than operates.\n *\n * The pointer can travel from the trigger into the card without closing it —\n * the close delay exists for that transit, which is what makes a hover card a\n * complementary surface and a tooltip a non-interactive hint. But that reach\n * is a pointer privilege only. Reka strips `tabindex=\"-1\"` onto every tabbable\n * node inside the content on mount, and the trigger closes the card on blur\n * after `closeDelay` (300ms by default) — so by the time a keyboard user\n * tabbed toward anything inside, the card would already be gone. Interactive\n * content inside a HoverCard is unreachable by keyboard (WCAG 2.1.1), whatever\n * the markup allows.\n *\n * The honest contract: keep the card's content non-interactive — text, an\n * image, a definition — and duplicate anything actionable somewhere reachable.\n * When a preview genuinely needs its own links or buttons, it is not a hover\n * card; it is a `Popover`, whose content takes focus and whose Esc/outside\n * dismissal gives a keyboard user a way in and out.\n *\n * The content is NOT wired as `aria-describedby` — it is a supplementary panel,\n * not an accessible name supplement. A screen reader user who never hovers\n * should still have the trigger's own accessible name, and the card is extra\n * rather than essential.\n */\nwithDefaults(\n defineProps<{\n /** The edge of the trigger to anchor against, before collision flipping. */\n side?: HoverCardSide;\n /** Gap in pixels between the trigger and the card. */\n sideOffset?: number;\n /** Alignment against the trigger along the cross-axis, before collision flipping. */\n align?: HoverCardAlign;\n /** Alignment offset in pixels from the chosen alignment position. */\n alignOffset?: number;\n /** Milliseconds of hover before the card appears. */\n openDelay?: number;\n /** Milliseconds before the card disappears after the pointer leaves both trigger and content. */\n closeDelay?: number;\n /** Drive the card from the host with `v-model:open`. Omit for hover alone. */\n open?: boolean | undefined;\n }>(),\n // `open: undefined` is load-bearing, not a redundant default — it is what\n // keeps the uncontrolled third state reachable past Vue's absent-Boolean\n // casting. `optional()` in the template is the other half; its docblock\n // carries the reasoning for both.\n {\n side: \"bottom\",\n sideOffset: 6,\n align: \"start\",\n alignOffset: 0,\n openDelay: 300,\n closeDelay: 300,\n open: undefined,\n },\n);\n\ndefineEmits<{ \"update:open\": [value: boolean] }>();\n</script>\n\n<template>\n <HoverCardRoot\n :open-delay=\"openDelay\"\n :close-delay=\"closeDelay\"\n v-bind=\"optional({ open })\"\n @update:open=\"$emit('update:open', $event)\"\n >\n <!-- @slot The element that opens the card on hover. Rendered `as-child`, so\n the caller's own element *is* the trigger and keeps its own accessible\n name. -->\n <HoverCardTrigger as-child>\n <slot name=\"trigger\" />\n </HoverCardTrigger>\n\n <HoverCardPortal>\n <HoverCardContent\n :side=\"side\"\n :side-offset=\"sideOffset\"\n :align=\"align\"\n :align-offset=\"alignOffset\"\n :class=\"\n cn(\n 'z-overlay w-64 rounded-md border border-border bg-popover p-4 text-popover-foreground shadow-md outline-none',\n // Both states scoped, never unconditional. Reka's Presence\n // keeps closed content mounted until an animationend arrives, and\n // a mount-only animation never fires a second one — so an\n // unconditional animation class leaves a stray card in the page.\n // Scoped, the closed element computes `animation-name: none` and\n // Presence unmounts it at once; the paired exit is precisely what\n // Presence is waiting to hold it for.\n 'data-[state=open]:animate-scale-in data-[state=closed]:animate-scale-out',\n )\n \"\n style=\"transform-origin: var(--reka-popper-transform-origin)\"\n >\n <!-- @slot The card content. Pointer-reachable, but keep it\n non-interactive — see the component docblock for why keyboard\n users cannot reach anything focusable in here. -->\n <slot />\n <HoverCardArrow class=\"fill-popover\" :width=\"10\" :height=\"5\" />\n </HoverCardContent>\n </HoverCardPortal>\n </HoverCardRoot>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;GAyFE,OAAA,UAAA,GAAA,YAyCgB,MAAA,aAAA,GAzChB,WAyCgB;IAxCb,cAAY,QAAA;IACZ,eAAa,QAAA;GACN,GAAA,MAAA,QAAA,CAAQ,CAAA,EAAA,MAAG,QAAA,KAAI,CAAA,GAAA,EACtB,iBAAW,OAAA,OAAA,OAAA,MAAA,WAAEA,KAAAA,MAAK,eAAgB,MAAM,GAAA,CAAA,GAAA;IAKzC,SAAA,cAEmB,CAFnB,YAEmB,MAAA,gBAAA,GAAA,EAFD,YAAA,GAAQ,GAAA;KACxB,SAAA,cAAuB,CAAvB,WAAuB,KAAA,QAAA,SAAA,CAAA,CAAA;;IAGzB,CAAA,GAAA,YA2BkB,MAAA,eAAA,GAAA,MAAA;KA1BhB,SAAA,cAyBmB,CAzBnB,YAyBmB,MAAA,gBAAA,GAAA;MAxBhB,MAAM,QAAA;MACN,eAAa,QAAA;MACb,OAAO,QAAA;MACP,gBAAc,QAAA;MACd,OAAK,eAAa,MAAA,EAAA,CAAE,CAAA,gHAAA,0EAAA,CAAA;MAarB,OAAA,EAAA,oBAAA,sCAAA;;MAKA,SAAA,cAAQ,CAAR,WAAQ,KAAA,QAAA,SAAA,GACR,YAA+D,MAAA,cAAA,GAAA;OAA/C,OAAM;OAAgB,OAAO;OAAK,QAAQ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IconButton.js","names":[],"sources":["../../../../../packages/primitives/icon-button/src/IconButton.vue"],"sourcesContent":["<script lang=\"ts\">\nimport { cva } from \"class-variance-authority\";\n\nexport type IconButtonVariant = \"default\" | \"secondary\" | \"ghost\" | \"destructive\";\n\nexport type IconButtonSize = \"sm\" | \"md\" | \"lg\";\n\n/**\n * An icon-only button is a square, so every size is height-equals-width and has\n * no horizontal padding. The four variants match Button's press language — hover\n * lifts by fill — but `default` here names what Button calls `primary`, because
|
|
1
|
+
{"version":3,"file":"IconButton.js","names":[],"sources":["../../../../../packages/primitives/icon-button/src/IconButton.vue"],"sourcesContent":["<script lang=\"ts\">\nimport { cva } from \"class-variance-authority\";\n\nexport type IconButtonVariant = \"default\" | \"secondary\" | \"ghost\" | \"destructive\";\n\nexport type IconButtonSize = \"sm\" | \"md\" | \"lg\";\n\n/**\n * An icon-only button is a square, so every size is height-equals-width and has\n * no horizontal padding. The four variants match Button's press language — hover\n * lifts by fill, active presses down, focus blooms the primary ring — but\n * `default` here names what Button calls `primary`, because an icon button is\n * never the screen's primary action and the word would mislead.\n */\nexport const iconButtonVariants = cva(\n [\n \"relative inline-flex items-center justify-center rounded-md select-none\",\n // Button's own transition list, verbatim: transform rides --ease-spring so\n // the press squish springs, while colour and shadow stay on --ease-out.\n // A bare `transition-colors` silently dropped any transform change.\n \"[transition:transform_var(--duration-fast)_var(--ease-spring),background-color_var(--duration-fast)_var(--ease-out),color_var(--duration-fast)_var(--ease-out),box-shadow_var(--duration-fast)_var(--ease-out)]\",\n \"active:scale-press focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo\",\n \"disabled:pointer-events-none\",\n ],\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90 active:bg-primary/80\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80 active:bg-secondary/70\",\n ghost: \"hover:bg-subtle text-foreground\",\n destructive:\n \"bg-destructive text-destructive-foreground hover:bg-destructive/90 active:bg-destructive/80\",\n } satisfies Record<IconButtonVariant, string>,\n size: {\n sm: \"h-8 w-8\",\n md: \"h-9 w-9\",\n lg: \"h-10 w-10\",\n } satisfies Record<IconButtonSize, string>,\n },\n defaultVariants: {\n variant: \"default\",\n size: \"md\",\n },\n },\n);\n</script>\n\n<script setup lang=\"ts\">\nimport { cn } from \"@ecoma-io/loom-core\";\n\nwithDefaults(\n defineProps<{\n /** Visual weight, matching Button's press language but without the `primary` name — an icon button is never the action a screen is asking for. */\n variant?: IconButtonVariant;\n /** Square hit area. Every size is 24px or above (WCAG 2.2 SC 2.5.8). */\n size?: IconButtonSize;\n /** The accessible name. An icon-only button without one is a WCAG failure, so this prop is required. */\n label: string;\n /** Unavailable rather than dimmed — drains to the neutral well and blocks pointer events. */\n disabled?: boolean;\n /** The native button type. Defaults to `button`, never an accidental submit. */\n type?: \"button\" | \"submit\" | \"reset\";\n }>(),\n { variant: \"default\", size: \"md\", disabled: false, type: \"button\" },\n);\n</script>\n\n<template>\n <button\n :type=\"type\"\n :class=\"\n cn(\n iconButtonVariants({ variant, size }),\n $attrs.class,\n // Drained, not dimmed — Button's rule, and for the same measured reason:\n // `opacity-50` faded the fill and the glyph together, multiplying away\n // whatever contrast either had. One neutral treatment covers all four\n // variants here exactly as it does on Button — a fill-bearing icon\n // button gives up its hue, `ghost` gains a fill — because an unavailable\n // control has no emphasis left to carry, and the native `disabled`\n // attribute above carries the state to assistive tech regardless.\n // No `border-border` companion: unlike Button's variants none of these\n // paints a border to slacken.\n disabled && 'bg-muted text-muted-foreground shadow-none',\n )\n \"\n :aria-label=\"label\"\n :disabled=\"disabled\"\n >\n <slot />\n </button>\n</template>\n"],"mappings":""}
|
|
@@ -3,8 +3,9 @@ export type IconButtonSize = "sm" | "md" | "lg";
|
|
|
3
3
|
/**
|
|
4
4
|
* An icon-only button is a square, so every size is height-equals-width and has
|
|
5
5
|
* no horizontal padding. The four variants match Button's press language — hover
|
|
6
|
-
* lifts by fill
|
|
7
|
-
*
|
|
6
|
+
* lifts by fill, active presses down, focus blooms the primary ring — but
|
|
7
|
+
* `default` here names what Button calls `primary`, because an icon button is
|
|
8
|
+
* never the screen's primary action and the word would mislead.
|
|
8
9
|
*/
|
|
9
10
|
export declare const iconButtonVariants: (props?: ({
|
|
10
11
|
variant?: "default" | "destructive" | "secondary" | "ghost" | null | undefined;
|
|
@@ -19,8 +20,10 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
|
|
|
19
20
|
size?: IconButtonSize;
|
|
20
21
|
/** The accessible name. An icon-only button without one is a WCAG failure, so this prop is required. */
|
|
21
22
|
label: string;
|
|
22
|
-
/** Unavailable —
|
|
23
|
+
/** Unavailable rather than dimmed — drains to the neutral well and blocks pointer events. */
|
|
23
24
|
disabled?: boolean;
|
|
25
|
+
/** The native button type. Defaults to `button`, never an accidental submit. */
|
|
26
|
+
type?: "button" | "submit" | "reset";
|
|
24
27
|
}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{
|
|
25
28
|
/** Visual weight, matching Button's press language but without the `primary` name — an icon button is never the action a screen is asking for. */
|
|
26
29
|
variant?: IconButtonVariant;
|
|
@@ -28,10 +31,13 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
|
|
|
28
31
|
size?: IconButtonSize;
|
|
29
32
|
/** The accessible name. An icon-only button without one is a WCAG failure, so this prop is required. */
|
|
30
33
|
label: string;
|
|
31
|
-
/** Unavailable —
|
|
34
|
+
/** Unavailable rather than dimmed — drains to the neutral well and blocks pointer events. */
|
|
32
35
|
disabled?: boolean;
|
|
36
|
+
/** The native button type. Defaults to `button`, never an accidental submit. */
|
|
37
|
+
type?: "button" | "submit" | "reset";
|
|
33
38
|
}> & Readonly<{}>, {
|
|
34
39
|
size: IconButtonSize;
|
|
40
|
+
type: "button" | "submit" | "reset";
|
|
35
41
|
disabled: boolean;
|
|
36
42
|
variant: IconButtonVariant;
|
|
37
43
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IconButton.vue.d.ts","sourceRoot":"","sources":["../../../../../packages/primitives/icon-button/src/IconButton.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"IconButton.vue.d.ts","sourceRoot":"","sources":["../../../../../packages/primitives/icon-button/src/IconButton.vue"],"names":[],"mappings":"AAqGA,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,WAAW,GAAG,OAAO,GAAG,aAAa,CAAC;AAElF,MAAM,MAAM,cAAc,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAEhD;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB;;;8EA+B9B,CAAC;wBACmB,OAAO,YAAY;AAAxC,wBAAyC;AACzC,QAAA,MAAM,YAAY;IAEd,kJAAkJ;cACxI,iBAAiB;IAC3B,wEAAwE;WACjE,cAAc;IACrB,wGAAwG;WACjG,MAAM;IACb,6FAA6F;eAClF,OAAO;IAClB,gFAAgF;WACzE,QAAQ,GAAG,QAAQ,GAAG,OAAO;;IATpC,kJAAkJ;cACxI,iBAAiB;IAC3B,wEAAwE;WACjE,cAAc;IACrB,wGAAwG;WACjG,MAAM;IACb,6FAA6F;eAClF,OAAO;IAClB,gFAAgF;WACzE,QAAQ,GAAG,QAAQ,GAAG,OAAO;;UAN7B,cAAc;UAMd,QAAQ,GAAG,QAAQ,GAAG,OAAO;cAFzB,OAAO;aANR,iBAAiB;;cA4DjB,CAAC,KAAK,IAAgB,KAAK,GAAG;EAUxC,CAAC;AAWL,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
|
package/dist/packages/primitives/icon-button/src/IconButton.vue_vue_type_script_setup_true_lang.js
CHANGED
|
@@ -3,14 +3,24 @@ import "../../../core/src/index.js";
|
|
|
3
3
|
import { createElementBlock, defineComponent, normalizeClass, openBlock, renderSlot, unref } from "vue";
|
|
4
4
|
import { cva } from "class-variance-authority";
|
|
5
5
|
//#region packages/primitives/icon-button/src/IconButton.vue?vue&type=script&setup=true&lang.ts
|
|
6
|
-
var _hoisted_1 = [
|
|
6
|
+
var _hoisted_1 = [
|
|
7
|
+
"type",
|
|
8
|
+
"aria-label",
|
|
9
|
+
"disabled"
|
|
10
|
+
];
|
|
7
11
|
/**
|
|
8
12
|
* An icon-only button is a square, so every size is height-equals-width and has
|
|
9
13
|
* no horizontal padding. The four variants match Button's press language — hover
|
|
10
|
-
* lifts by fill
|
|
11
|
-
*
|
|
14
|
+
* lifts by fill, active presses down, focus blooms the primary ring — but
|
|
15
|
+
* `default` here names what Button calls `primary`, because an icon button is
|
|
16
|
+
* never the screen's primary action and the word would mislead.
|
|
12
17
|
*/
|
|
13
|
-
var iconButtonVariants = cva(
|
|
18
|
+
var iconButtonVariants = cva([
|
|
19
|
+
"relative inline-flex items-center justify-center rounded-md select-none",
|
|
20
|
+
"[transition:transform_var(--duration-fast)_var(--ease-spring),background-color_var(--duration-fast)_var(--ease-out),color_var(--duration-fast)_var(--ease-out),box-shadow_var(--duration-fast)_var(--ease-out)]",
|
|
21
|
+
"active:scale-press focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo",
|
|
22
|
+
"disabled:pointer-events-none"
|
|
23
|
+
], {
|
|
14
24
|
variants: {
|
|
15
25
|
variant: {
|
|
16
26
|
default: "bg-primary text-primary-foreground hover:bg-primary/90 active:bg-primary/80",
|
|
@@ -38,15 +48,17 @@ var IconButton_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defin
|
|
|
38
48
|
disabled: {
|
|
39
49
|
type: Boolean,
|
|
40
50
|
default: false
|
|
41
|
-
}
|
|
51
|
+
},
|
|
52
|
+
type: { default: "button" }
|
|
42
53
|
},
|
|
43
54
|
setup(__props) {
|
|
44
55
|
return (_ctx, _cache) => {
|
|
45
56
|
return openBlock(), createElementBlock("button", {
|
|
57
|
+
type: __props.type,
|
|
46
58
|
class: normalizeClass(unref(cn)(unref(iconButtonVariants)({
|
|
47
59
|
variant: __props.variant,
|
|
48
60
|
size: __props.size
|
|
49
|
-
}), _ctx.$attrs.class)),
|
|
61
|
+
}), _ctx.$attrs.class, __props.disabled && "bg-muted text-muted-foreground shadow-none")),
|
|
50
62
|
"aria-label": __props.label,
|
|
51
63
|
disabled: __props.disabled
|
|
52
64
|
}, [renderSlot(_ctx.$slots, "default")], 10, _hoisted_1);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IconButton.vue_vue_type_script_setup_true_lang.js","names":["$attrs"],"sources":["../../../../../packages/primitives/icon-button/src/IconButton.vue"],"sourcesContent":["<script lang=\"ts\">\nimport { cva } from \"class-variance-authority\";\n\nexport type IconButtonVariant = \"default\" | \"secondary\" | \"ghost\" | \"destructive\";\n\nexport type IconButtonSize = \"sm\" | \"md\" | \"lg\";\n\n/**\n * An icon-only button is a square, so every size is height-equals-width and has\n * no horizontal padding. The four variants match Button's press language — hover\n * lifts by fill — but `default` here names what Button calls `primary`, because
|
|
1
|
+
{"version":3,"file":"IconButton.vue_vue_type_script_setup_true_lang.js","names":["$attrs"],"sources":["../../../../../packages/primitives/icon-button/src/IconButton.vue"],"sourcesContent":["<script lang=\"ts\">\nimport { cva } from \"class-variance-authority\";\n\nexport type IconButtonVariant = \"default\" | \"secondary\" | \"ghost\" | \"destructive\";\n\nexport type IconButtonSize = \"sm\" | \"md\" | \"lg\";\n\n/**\n * An icon-only button is a square, so every size is height-equals-width and has\n * no horizontal padding. The four variants match Button's press language — hover\n * lifts by fill, active presses down, focus blooms the primary ring — but\n * `default` here names what Button calls `primary`, because an icon button is\n * never the screen's primary action and the word would mislead.\n */\nexport const iconButtonVariants = cva(\n [\n \"relative inline-flex items-center justify-center rounded-md select-none\",\n // Button's own transition list, verbatim: transform rides --ease-spring so\n // the press squish springs, while colour and shadow stay on --ease-out.\n // A bare `transition-colors` silently dropped any transform change.\n \"[transition:transform_var(--duration-fast)_var(--ease-spring),background-color_var(--duration-fast)_var(--ease-out),color_var(--duration-fast)_var(--ease-out),box-shadow_var(--duration-fast)_var(--ease-out)]\",\n \"active:scale-press focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo\",\n \"disabled:pointer-events-none\",\n ],\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90 active:bg-primary/80\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80 active:bg-secondary/70\",\n ghost: \"hover:bg-subtle text-foreground\",\n destructive:\n \"bg-destructive text-destructive-foreground hover:bg-destructive/90 active:bg-destructive/80\",\n } satisfies Record<IconButtonVariant, string>,\n size: {\n sm: \"h-8 w-8\",\n md: \"h-9 w-9\",\n lg: \"h-10 w-10\",\n } satisfies Record<IconButtonSize, string>,\n },\n defaultVariants: {\n variant: \"default\",\n size: \"md\",\n },\n },\n);\n</script>\n\n<script setup lang=\"ts\">\nimport { cn } from \"@ecoma-io/loom-core\";\n\nwithDefaults(\n defineProps<{\n /** Visual weight, matching Button's press language but without the `primary` name — an icon button is never the action a screen is asking for. */\n variant?: IconButtonVariant;\n /** Square hit area. Every size is 24px or above (WCAG 2.2 SC 2.5.8). */\n size?: IconButtonSize;\n /** The accessible name. An icon-only button without one is a WCAG failure, so this prop is required. */\n label: string;\n /** Unavailable rather than dimmed — drains to the neutral well and blocks pointer events. */\n disabled?: boolean;\n /** The native button type. Defaults to `button`, never an accidental submit. */\n type?: \"button\" | \"submit\" | \"reset\";\n }>(),\n { variant: \"default\", size: \"md\", disabled: false, type: \"button\" },\n);\n</script>\n\n<template>\n <button\n :type=\"type\"\n :class=\"\n cn(\n iconButtonVariants({ variant, size }),\n $attrs.class,\n // Drained, not dimmed — Button's rule, and for the same measured reason:\n // `opacity-50` faded the fill and the glyph together, multiplying away\n // whatever contrast either had. One neutral treatment covers all four\n // variants here exactly as it does on Button — a fill-bearing icon\n // button gives up its hue, `ghost` gains a fill — because an unavailable\n // control has no emphasis left to carry, and the native `disabled`\n // attribute above carries the state to assistive tech regardless.\n // No `border-border` companion: unlike Button's variants none of these\n // paints a border to slacken.\n disabled && 'bg-muted text-muted-foreground shadow-none',\n )\n \"\n :aria-label=\"label\"\n :disabled=\"disabled\"\n >\n <slot />\n </button>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;AAcA,IAAa,qBAAqB,IAChC;CACE;CAIA;CACA;CACA;AACF,GACA;CACE,UAAU;EACR,SAAS;GACP,SAAS;GACT,WACE;GACF,OAAO;GACP,aACE;EACJ;EACA,MAAM;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;EACN;CACF;CACA,iBAAiB;EACf,SAAS;EACT,MAAM;CACR;AACF,CACF;;;;;;;;;;;;;;;GAwBE,OAAA,UAAA,GAAA,mBAsBS,UAAA;IArBN,MAAM,QAAA;IACN,OAAK,eAAS,MAAA,EAAA,CAAE,CAAU,MAAA,kBAAA,CAAkB,CAAA;KAAA,SAAG,QAAA;KAAO,MAAE,QAAA;IAAI,CAAA,GAAaA,KAAAA,OAAO,OAA4qB,QAAA,YAAQ,4CAAA,CAAA;IAgBpwB,cAAY,QAAA;IACZ,UAAU,QAAA;GAEX,GAAA,CAAA,WAAQ,KAAA,QAAA,SAAA,CAAA,GAAA,IAAA,UAAA"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type LabelOverrides } from "
|
|
2
|
-
import type { IndicatorLabels } from "
|
|
1
|
+
import { type LabelOverrides } from "../../../labels/src/index";
|
|
2
|
+
import type { IndicatorLabels } from "../../../labels/src/index";
|
|
3
3
|
/** A presence dot, or a number. */
|
|
4
4
|
export type IndicatorVariant = "dot" | "count";
|
|
5
5
|
/** The four presence states a dot can report. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { default, indicatorVariants, indicatorToneVariants, INDICATOR_LABELS, } from "./Indicator.vue";
|
|
2
2
|
export type { IndicatorVariant, IndicatorStatus, IndicatorPlacement, IndicatorTone, IndicatorSurface, } from "./Indicator.vue";
|
|
3
|
-
export type { IndicatorLabels } from "
|
|
3
|
+
export type { IndicatorLabels } from "../../../labels/src/index";
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import Kbd_vue_vue_type_script_setup_true_lang_default, { kbdVariants } from "./Kbd.vue_vue_type_script_setup_true_lang.js";
|
|
2
|
+
//#region packages/primitives/kbd/src/Kbd.vue
|
|
3
|
+
var Kbd_default = Kbd_vue_vue_type_script_setup_true_lang_default;
|
|
4
|
+
//#endregion
|
|
5
|
+
export { Kbd_default as default, kbdVariants };
|
|
6
|
+
|
|
7
|
+
//# sourceMappingURL=Kbd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Kbd.js","names":[],"sources":["../../../../../packages/primitives/kbd/src/Kbd.vue"],"sourcesContent":["<script lang=\"ts\">\nimport { cva } from \"class-variance-authority\";\n\n/**\n * Kbd — one key cap. A combination is several of these side by side, joined\n * by a visible separator the host renders (`+` or `-`), with the whole run\n * given an accessible name on its wrapper; Kbd deliberately does not parse\n * shortcut strings, because the line between \"display\" and \"shortcut\n * manager\" is exactly where this primitive should stop.\n */\nexport type KbdSize = \"sm\" | \"md\";\n\nexport const kbdVariants = cva(\n [\n \"inline-flex select-none items-center justify-center rounded-sm\",\n // The cap: a subtle well, a hairline, and a bottom-weighted edge so it\n // reads as something you could press. Tokens only — high-contrast and\n // dark both come from the same pair every surface uses.\n \"border border-border border-b-border-strong bg-subtle text-foreground shadow-sm\",\n \"font-mono tabular whitespace-nowrap\",\n ],\n {\n variants: {\n size: {\n // Display-only, so target-size rules do not bind — the floors exist\n // because inline caps sit inside sentences, and one that shifts the\n // baseline or reads as a speck is worse than a generous box.\n sm: \"min-h-6 min-w-6 px-1.5 text-xs\",\n md: \"min-h-7 min-w-7 px-2 text-small\",\n },\n },\n defaultVariants: { size: \"md\" },\n },\n);\n</script>\n\n<script setup lang=\"ts\">\nimport { cn } from \"@ecoma-io/loom-core\";\n\nwithDefaults(\n defineProps<{\n /** `sm` sits inside prose and table cells; `md` for settings pages. */\n size?: KbdSize;\n }>(),\n { size: \"md\" },\n);\n</script>\n\n<template>\n <kbd :class=\"cn(kbdVariants({ size }))\">\n <!-- @slot The key's face — a letter, a glyph like ⌘, an arrow character. -->\n <slot />\n </kbd>\n</template>\n"],"mappings":""}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kbd — one key cap. A combination is several of these side by side, joined
|
|
3
|
+
* by a visible separator the host renders (`+` or `-`), with the whole run
|
|
4
|
+
* given an accessible name on its wrapper; Kbd deliberately does not parse
|
|
5
|
+
* shortcut strings, because the line between "display" and "shortcut
|
|
6
|
+
* manager" is exactly where this primitive should stop.
|
|
7
|
+
*/
|
|
8
|
+
export type KbdSize = "sm" | "md";
|
|
9
|
+
export declare const kbdVariants: (props?: ({
|
|
10
|
+
size?: "sm" | "md" | null | undefined;
|
|
11
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
12
|
+
declare const _default: typeof __VLS_export;
|
|
13
|
+
export default _default;
|
|
14
|
+
declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
|
|
15
|
+
/** `sm` sits inside prose and table cells; `md` for settings pages. */
|
|
16
|
+
size?: KbdSize;
|
|
17
|
+
}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{
|
|
18
|
+
/** `sm` sits inside prose and table cells; `md` for settings pages. */
|
|
19
|
+
size?: KbdSize;
|
|
20
|
+
}> & Readonly<{}>, {
|
|
21
|
+
size: KbdSize;
|
|
22
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, {
|
|
23
|
+
default?: (props: {}) => any;
|
|
24
|
+
}>;
|
|
25
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
26
|
+
new (): {
|
|
27
|
+
$slots: S;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=Kbd.vue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Kbd.vue.d.ts","sourceRoot":"","sources":["../../../../../packages/primitives/kbd/src/Kbd.vue"],"names":[],"mappings":"AA8DA;;;;;;GAMG;AACH,MAAM,MAAM,OAAO,GAAG,IAAI,GAAG,IAAI,CAAC;AAElC,eAAO,MAAM,WAAW;;8EAqBvB,CAAC;wBACmB,OAAO,YAAY;AAAxC,wBAAyC;AACzC,QAAA,MAAM,YAAY;IAEd,uEAAuE;WAChE,OAAO;;IADd,uEAAuE;WAChE,OAAO;;UAAP,OAAO;;cAkCJ,CAAC,KAAK,IAAgB,KAAK,GAAG;EAUxC,CAAC;AAWL,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { cn } from "../../../core/src/cn.js";
|
|
2
|
+
import "../../../core/src/index.js";
|
|
3
|
+
import { createElementBlock, defineComponent, normalizeClass, openBlock, renderSlot, unref } from "vue";
|
|
4
|
+
import { cva } from "class-variance-authority";
|
|
5
|
+
//#region packages/primitives/kbd/src/Kbd.vue?vue&type=script&setup=true&lang.ts
|
|
6
|
+
var kbdVariants = cva([
|
|
7
|
+
"inline-flex select-none items-center justify-center rounded-sm",
|
|
8
|
+
"border border-border border-b-border-strong bg-subtle text-foreground shadow-sm",
|
|
9
|
+
"font-mono tabular whitespace-nowrap"
|
|
10
|
+
], {
|
|
11
|
+
variants: { size: {
|
|
12
|
+
sm: "min-h-6 min-w-6 px-1.5 text-xs",
|
|
13
|
+
md: "min-h-7 min-w-7 px-2 text-small"
|
|
14
|
+
} },
|
|
15
|
+
defaultVariants: { size: "md" }
|
|
16
|
+
});
|
|
17
|
+
var Kbd_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
|
|
18
|
+
__name: "Kbd",
|
|
19
|
+
props: { size: { default: "md" } },
|
|
20
|
+
setup(__props) {
|
|
21
|
+
return (_ctx, _cache) => {
|
|
22
|
+
return openBlock(), createElementBlock("kbd", { class: normalizeClass(unref(cn)(unref(kbdVariants)({ size: __props.size }))) }, [renderSlot(_ctx.$slots, "default")], 2);
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
//#endregion
|
|
27
|
+
export { Kbd_vue_vue_type_script_setup_true_lang_default as default, kbdVariants };
|
|
28
|
+
|
|
29
|
+
//# sourceMappingURL=Kbd.vue_vue_type_script_setup_true_lang.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Kbd.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../../../packages/primitives/kbd/src/Kbd.vue"],"sourcesContent":["<script lang=\"ts\">\nimport { cva } from \"class-variance-authority\";\n\n/**\n * Kbd — one key cap. A combination is several of these side by side, joined\n * by a visible separator the host renders (`+` or `-`), with the whole run\n * given an accessible name on its wrapper; Kbd deliberately does not parse\n * shortcut strings, because the line between \"display\" and \"shortcut\n * manager\" is exactly where this primitive should stop.\n */\nexport type KbdSize = \"sm\" | \"md\";\n\nexport const kbdVariants = cva(\n [\n \"inline-flex select-none items-center justify-center rounded-sm\",\n // The cap: a subtle well, a hairline, and a bottom-weighted edge so it\n // reads as something you could press. Tokens only — high-contrast and\n // dark both come from the same pair every surface uses.\n \"border border-border border-b-border-strong bg-subtle text-foreground shadow-sm\",\n \"font-mono tabular whitespace-nowrap\",\n ],\n {\n variants: {\n size: {\n // Display-only, so target-size rules do not bind — the floors exist\n // because inline caps sit inside sentences, and one that shifts the\n // baseline or reads as a speck is worse than a generous box.\n sm: \"min-h-6 min-w-6 px-1.5 text-xs\",\n md: \"min-h-7 min-w-7 px-2 text-small\",\n },\n },\n defaultVariants: { size: \"md\" },\n },\n);\n</script>\n\n<script setup lang=\"ts\">\nimport { cn } from \"@ecoma-io/loom-core\";\n\nwithDefaults(\n defineProps<{\n /** `sm` sits inside prose and table cells; `md` for settings pages. */\n size?: KbdSize;\n }>(),\n { size: \"md\" },\n);\n</script>\n\n<template>\n <kbd :class=\"cn(kbdVariants({ size }))\">\n <!-- @slot The key's face — a letter, a glyph like ⌘, an arrow character. -->\n <slot />\n </kbd>\n</template>\n"],"mappings":";;;;;AAYA,IAAa,cAAc,IACzB;CACE;CAIA;CACA;AACF,GACA;CACE,UAAU,EACR,MAAM;EAIJ,IAAI;EACJ,IAAI;CACN,EACF;CACA,iBAAiB,EAAE,MAAM,KAAK;AAChC,CACF;;;;;;GAgBE,OAAA,UAAA,GAAA,mBAGM,OAAA,EAHA,OAAK,eAAE,MAAA,EAAA,CAAE,CAAC,MAAA,WAAA,CAAW,CAAA,EAAA,MAAG,QAAA,KAAI,CAAA,CAAA,CAAA,EAAA,GAAA,CAEhC,WAAQ,KAAA,QAAA,SAAA,CAAA,GAAA,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../packages/primitives/kbd/src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACjD,YAAY,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Link.js","names":[],"sources":["../../../../../packages/primitives/link/src/Link.vue"],"sourcesContent":["<script lang=\"ts\">\nimport { cva } from \"class-variance-authority\";\n\n/** The visual emphasis assigned to a link. */\nexport type LinkVariant = \"default\" | \"muted\" | \"accent\" | \"subtle\";\n\nexport const linkVariants = cva(\n \"inline-flex items-center gap-1 transition-colors duration-fast ease-out focus-visible:outline-
|
|
1
|
+
{"version":3,"file":"Link.js","names":[],"sources":["../../../../../packages/primitives/link/src/Link.vue"],"sourcesContent":["<script lang=\"ts\">\nimport { cva } from \"class-variance-authority\";\n\n/** The visual emphasis assigned to a link. */\nexport type LinkVariant = \"default\" | \"muted\" | \"accent\" | \"subtle\";\n\nexport const linkVariants = cva(\n \"inline-flex items-center gap-1 transition-colors duration-fast ease-out focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo\",\n {\n variants: {\n variant: {\n default: \"text-primary-text underline underline-offset-4 hover:text-primary-text/80\",\n // Underlined like its siblings. WCAG 1.4.1 asks for a non-colour\n // carrier and the underline is the one links have; `muted` used to be\n // the variant that dropped it while keeping a hover colour change,\n // which identified the link by hue alone.\n muted: \"text-muted-foreground underline underline-offset-4 hover:text-foreground\",\n accent: \"text-accent-text underline underline-offset-4 hover:text-accent-text/80\",\n subtle:\n \"text-foreground/80 hover:text-foreground underline underline-offset-4 decoration-border hover:decoration-foreground/50\",\n } satisfies Record<LinkVariant, string>,\n underline: {\n true: \"\",\n false: \"no-underline\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n underline: true,\n },\n },\n);\n</script>\n\n<script setup lang=\"ts\">\nimport { cn } from \"@ecoma-io/loom-core\";\n\nwithDefaults(\n defineProps<{\n /** Controls the link's visual emphasis. */\n variant?: LinkVariant;\n /** Draws an underline beneath the link label. */\n underline?: boolean;\n /** The destination the link navigates to. */\n href: string;\n /** Opens the destination in a new tab and marks it as an external link. */\n external?: boolean;\n /** Replaces the anchor with an unavailable, non-interactive span. */\n disabled?: boolean;\n }>(),\n {\n variant: \"default\",\n underline: true,\n external: false,\n disabled: false,\n },\n);\n</script>\n\n<template>\n <span\n v-if=\"disabled\"\n :class=\"\n cn(\n linkVariants({ variant, underline }),\n // Drained, not dimmed — the same rule Button and Chip follow. The dim\n // faded whatever hue the variant wore, taking the label's contrast\n // down with it; a link has no fill to drain, so it takes the neutral\n // well the transparent controls take, and `aria-disabled` carries the\n // state rather than colour alone.\n 'cursor-default bg-muted text-muted-foreground pointer-events-none',\n $attrs.class,\n )\n \"\n aria-disabled=\"true\"\n >\n <slot />\n </span>\n <a\n v-else\n :href=\"href\"\n :class=\"cn(linkVariants({ variant, underline }), $attrs.class)\"\n :target=\"external ? '_blank' : undefined\"\n :rel=\"external ? 'noopener noreferrer' : undefined\"\n >\n <slot />\n <svg\n v-if=\"external\"\n class=\"h-3.5 w-3.5 shrink-0\"\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <path d=\"M7 17 17 7\" />\n <path d=\"M7 7h10v10\" />\n </svg>\n </a>\n</template>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Link.vue.d.ts","sourceRoot":"","sources":["../../../../../packages/primitives/link/src/Link.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Link.vue.d.ts","sourceRoot":"","sources":["../../../../../packages/primitives/link/src/Link.vue"],"names":[],"mappings":"AAiHA,8CAA8C;AAC9C,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEpE,eAAO,MAAM,YAAY;;;8EAyBxB,CAAC;wBACmB,OAAO,YAAY;AAAxC,wBAAyC;AACzC,QAAA,MAAM,YAAY;IAEd,2CAA2C;cACjC,WAAW;IACrB,iDAAiD;gBACrC,OAAO;IACnB,6CAA6C;UACvC,MAAM;IACZ,2EAA2E;eAChE,OAAO;IAClB,qEAAqE;eAC1D,OAAO;;IATlB,2CAA2C;cACjC,WAAW;IACrB,iDAAiD;gBACrC,OAAO;IACnB,6CAA6C;UACvC,MAAM;IACZ,2EAA2E;eAChE,OAAO;IAClB,qEAAqE;eAC1D,OAAO;;cAAP,OAAO;aARR,WAAW;eAET,OAAO;cAIR,OAAO;;cA8FR,CAAC,KAAK,IAAgB,KAAK,GAAG;;cAC9B,CAAC,KAAK,IAAgB,KAAK,GAAG;EAWxC,CAAC;AAWL,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
|