@ecoma-io/loom 0.3.0 → 0.5.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/README.md +11 -9
- package/dist/a11y.js +2 -2
- package/dist/index.js +73 -6
- package/dist/node_modules/.pnpm/{@internationalized_date@3.12.3 → @internationalized_date@3.12.4}/node_modules/@internationalized/date/dist/private/CalendarDate.js +1 -1
- package/dist/node_modules/.pnpm/{@internationalized_date@3.12.3 → @internationalized_date@3.12.4}/node_modules/@internationalized/date/dist/private/CalendarDate.js.map +1 -1
- package/dist/node_modules/.pnpm/{@internationalized_date@3.12.3 → @internationalized_date@3.12.4}/node_modules/@internationalized/date/dist/private/calendars/GregorianCalendar.js +1 -1
- package/dist/node_modules/.pnpm/{@internationalized_date@3.12.3 → @internationalized_date@3.12.4}/node_modules/@internationalized/date/dist/private/calendars/GregorianCalendar.js.map +1 -1
- package/dist/node_modules/.pnpm/{@internationalized_date@3.12.3 → @internationalized_date@3.12.4}/node_modules/@internationalized/date/dist/private/conversion.js +1 -1
- package/dist/node_modules/.pnpm/{@internationalized_date@3.12.3 → @internationalized_date@3.12.4}/node_modules/@internationalized/date/dist/private/conversion.js.map +1 -1
- package/dist/node_modules/.pnpm/{@internationalized_date@3.12.3 → @internationalized_date@3.12.4}/node_modules/@internationalized/date/dist/private/manipulation.js +1 -1
- package/dist/node_modules/.pnpm/{@internationalized_date@3.12.3 → @internationalized_date@3.12.4}/node_modules/@internationalized/date/dist/private/manipulation.js.map +1 -1
- package/dist/node_modules/.pnpm/{@internationalized_date@3.12.3 → @internationalized_date@3.12.4}/node_modules/@internationalized/date/dist/private/queries.js +1 -1
- package/dist/node_modules/.pnpm/{@internationalized_date@3.12.3 → @internationalized_date@3.12.4}/node_modules/@internationalized/date/dist/private/queries.js.map +1 -1
- package/dist/node_modules/.pnpm/{@internationalized_date@3.12.3 → @internationalized_date@3.12.4}/node_modules/@internationalized/date/dist/private/string.js +1 -1
- package/dist/node_modules/.pnpm/{@internationalized_date@3.12.3 → @internationalized_date@3.12.4}/node_modules/@internationalized/date/dist/private/string.js.map +1 -1
- package/dist/node_modules/.pnpm/{@internationalized_date@3.12.3 → @internationalized_date@3.12.4}/node_modules/@internationalized/date/dist/private/utils.js +1 -1
- package/dist/node_modules/.pnpm/{@internationalized_date@3.12.3 → @internationalized_date@3.12.4}/node_modules/@internationalized/date/dist/private/utils.js.map +1 -1
- 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/empty-state/src/EmptyState.js.map +1 -1
- package/dist/packages/blocks/empty-state/src/EmptyState.vue.d.ts.map +1 -1
- package/dist/packages/blocks/empty-state/src/EmptyState.vue_vue_type_script_setup_true_lang.js +5 -6
- package/dist/packages/blocks/empty-state/src/EmptyState.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/blocks/error-summary/src/ErrorSummary.js +7 -0
- package/dist/packages/blocks/error-summary/src/ErrorSummary.js.map +1 -0
- package/dist/packages/blocks/error-summary/src/ErrorSummary.vue.d.ts +31 -0
- package/dist/packages/blocks/error-summary/src/ErrorSummary.vue_vue_type_script_setup_true_lang.js +90 -0
- package/dist/packages/blocks/error-summary/src/ErrorSummary.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/packages/blocks/error-summary/src/index.d.ts +4 -0
- package/dist/packages/blocks/error-summary/src/index.js +3 -0
- 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 +28 -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/composition/sidebar/src/Sidebar.js.map +1 -1
- package/dist/packages/composition/sidebar/src/Sidebar.vue.d.ts +4 -0
- package/dist/packages/composition/sidebar/src/Sidebar.vue.d.ts.map +1 -1
- package/dist/packages/composition/sidebar/src/Sidebar.vue_vue_type_script_setup_true_lang.js +13 -4
- package/dist/packages/composition/sidebar/src/Sidebar.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/composition/split/src/Split.js.map +1 -1
- package/dist/packages/composition/split/src/Split.vue.d.ts +11 -12
- package/dist/packages/composition/split/src/Split.vue.d.ts.map +1 -1
- package/dist/packages/composition/split/src/Split.vue_vue_type_script_setup_true_lang.js +15 -5
- package/dist/packages/composition/split/src/Split.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/core/src/a11y-scope.d.ts +71 -5
- package/dist/packages/core/src/a11y-scope.d.ts.map +1 -1
- package/dist/packages/core/src/a11y-scope.js +126 -6
- package/dist/packages/core/src/a11y-scope.js.map +1 -1
- package/dist/packages/core/src/index.d.ts +2 -2
- package/dist/packages/core/src/index.d.ts.map +1 -1
- package/dist/packages/core/src/index.js +3 -3
- 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 +236 -1
- package/dist/packages/labels/src/component-shapes.d.ts.map +1 -1
- package/dist/packages/labels/src/date-labels.d.ts +86 -7
- package/dist/packages/labels/src/date-labels.d.ts.map +1 -1
- package/dist/packages/labels/src/date-labels.js +58 -9
- package/dist/packages/labels/src/date-labels.js.map +1 -1
- package/dist/packages/labels/src/field-context.d.ts +2 -2
- package/dist/packages/labels/src/field-context.js.map +1 -1
- package/dist/packages/labels/src/index.d.ts +3 -3
- package/dist/packages/labels/src/index.d.ts.map +1 -1
- package/dist/packages/labels/src/index.js +2 -2
- package/dist/packages/labels/src/label-registry.d.ts +15 -1
- package/dist/packages/labels/src/label-registry.d.ts.map +1 -1
- package/dist/packages/layouts/dashboard/src/Dashboard.js.map +1 -1
- package/dist/packages/layouts/dashboard/src/Dashboard.vue.d.ts +4 -4
- package/dist/packages/layouts/dashboard/src/Dashboard.vue.d.ts.map +1 -1
- package/dist/packages/layouts/dashboard/src/Dashboard.vue_vue_type_script_setup_true_lang.js.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/layouts/settings/src/Settings.js.map +1 -1
- package/dist/packages/layouts/settings/src/Settings.vue.d.ts +3 -3
- package/dist/packages/layouts/settings/src/Settings.vue.d.ts.map +1 -1
- package/dist/packages/layouts/settings/src/Settings.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/layouts/split-layout/src/SplitLayout.js.map +1 -1
- package/dist/packages/layouts/split-layout/src/SplitLayout.vue.d.ts +4 -6
- package/dist/packages/layouts/split-layout/src/SplitLayout.vue.d.ts.map +1 -1
- package/dist/packages/layouts/split-layout/src/SplitLayout.vue_vue_type_script_setup_true_lang.js +20 -5
- package/dist/packages/layouts/split-layout/src/SplitLayout.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/layouts/split-layout/src/index.d.ts +1 -1
- package/dist/packages/layouts/split-layout/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 +217 -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 +91 -0
- package/dist/packages/primitives/alert/src/Alert.vue_vue_type_script_setup_true_lang.js +130 -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/src/Avatar.js.map +1 -1
- package/dist/packages/primitives/avatar/src/Avatar.vue.d.ts +2 -2
- package/dist/packages/primitives/avatar/src/Avatar.vue.d.ts.map +1 -1
- package/dist/packages/primitives/avatar/src/Avatar.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/packages/primitives/avatar/src/Avatar.vue_vue_type_script_setup_true_lang.js.map +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/calendar/src/Calendar.js +7 -0
- package/dist/packages/primitives/calendar/src/Calendar.js.map +1 -0
- package/dist/packages/primitives/calendar/src/Calendar.vue.d.ts +95 -0
- package/dist/packages/primitives/calendar/src/Calendar.vue_vue_type_script_setup_true_lang.js +204 -0
- package/dist/packages/primitives/calendar/src/Calendar.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/packages/primitives/calendar/src/index.d.ts +3 -0
- package/dist/packages/primitives/calendar/src/index.js +3 -0
- 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 +3 -3
- 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/command/src/Command.js +7 -0
- package/dist/packages/primitives/command/src/Command.js.map +1 -0
- package/dist/packages/primitives/command/src/Command.vue.d.ts +77 -0
- package/dist/packages/primitives/command/src/Command.vue_vue_type_script_setup_true_lang.js +333 -0
- package/dist/packages/primitives/command/src/Command.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/packages/primitives/command/src/index.d.ts +4 -0
- package/dist/packages/primitives/command/src/index.js +3 -0
- 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/copy-button/src/CopyButton.js +7 -0
- package/dist/packages/primitives/copy-button/src/CopyButton.js.map +1 -0
- package/dist/packages/primitives/copy-button/src/CopyButton.vue.d.ts +64 -0
- package/dist/packages/primitives/copy-button/src/CopyButton.vue_vue_type_script_setup_true_lang.js +113 -0
- package/dist/packages/primitives/copy-button/src/CopyButton.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/packages/primitives/copy-button/src/index.d.ts +4 -0
- package/dist/packages/primitives/copy-button/src/index.js +3 -0
- package/dist/packages/primitives/data-grid/src/DataGrid.js +7 -0
- package/dist/packages/primitives/data-grid/src/DataGrid.js.map +1 -0
- package/dist/packages/primitives/data-grid/src/DataGrid.vue.d.ts +128 -0
- package/dist/packages/primitives/data-grid/src/DataGrid.vue_vue_type_script_setup_true_lang.js +347 -0
- package/dist/packages/primitives/data-grid/src/DataGrid.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/packages/primitives/data-grid/src/index.d.ts +4 -0
- package/dist/packages/primitives/data-grid/src/index.js +3 -0
- 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 +14 -14
- 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 +22 -19
- 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 +18 -17
- 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 +18 -17
- 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 +27 -11
- package/dist/packages/primitives/dialog/src/Dialog.vue_vue_type_script_setup_true_lang.js +6 -4
- 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 +12 -4
- package/dist/packages/primitives/drawer/src/Drawer.vue_vue_type_script_setup_true_lang.js +13 -5
- 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/hover-card/src/index.d.ts.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/live-region/src/LiveRegion.js +7 -0
- package/dist/packages/primitives/live-region/src/LiveRegion.js.map +1 -0
- package/dist/packages/primitives/live-region/src/LiveRegion.vue.d.ts +36 -0
- package/dist/packages/primitives/live-region/src/LiveRegion.vue.d.ts.map +1 -0
- package/dist/packages/primitives/live-region/src/LiveRegion.vue_vue_type_script_setup_true_lang.js +59 -0
- package/dist/packages/primitives/live-region/src/LiveRegion.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/packages/primitives/live-region/src/context.d.ts +40 -0
- package/dist/packages/primitives/live-region/src/context.d.ts.map +1 -0
- package/dist/packages/primitives/live-region/src/context.js +85 -0
- package/dist/packages/primitives/live-region/src/context.js.map +1 -0
- package/dist/packages/primitives/live-region/src/index.d.ts +4 -0
- package/dist/packages/primitives/live-region/src/index.d.ts.map +1 -0
- package/dist/packages/primitives/live-region/src/index.js +3 -0
- package/dist/packages/primitives/live-region/src/useAnnounce.d.ts +17 -0
- package/dist/packages/primitives/live-region/src/useAnnounce.d.ts.map +1 -0
- package/dist/packages/primitives/live-region/src/useAnnounce.js +25 -0
- package/dist/packages/primitives/live-region/src/useAnnounce.js.map +1 -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 +211 -64
- package/dist/packages/primitives/menubar/src/Menubar.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/packages/primitives/meter/src/Meter.js +7 -0
- package/dist/packages/primitives/meter/src/Meter.js.map +1 -0
- package/dist/packages/primitives/meter/src/Meter.vue.d.ts +87 -0
- package/dist/packages/primitives/meter/src/Meter.vue_vue_type_script_setup_true_lang.js +236 -0
- package/dist/packages/primitives/meter/src/Meter.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/packages/primitives/meter/src/index.d.ts +4 -0
- package/dist/packages/primitives/meter/src/index.js +3 -0
- package/dist/packages/primitives/navigation-menu/src/NavigationMenu.js +7 -0
- package/dist/packages/primitives/navigation-menu/src/NavigationMenu.js.map +1 -0
- package/dist/packages/primitives/navigation-menu/src/NavigationMenu.vue.d.ts +69 -0
- package/dist/packages/primitives/navigation-menu/src/NavigationMenu.vue.d.ts.map +1 -0
- package/dist/packages/primitives/navigation-menu/src/NavigationMenu.vue_vue_type_script_setup_true_lang.js +118 -0
- package/dist/packages/primitives/navigation-menu/src/NavigationMenu.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/packages/primitives/navigation-menu/src/index.d.ts +3 -0
- package/dist/packages/primitives/navigation-menu/src/index.d.ts.map +1 -0
- package/dist/packages/primitives/navigation-menu/src/index.js +2 -0
- 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/skip-link/src/SkipLink.js +7 -0
- package/dist/packages/primitives/skip-link/src/SkipLink.js.map +1 -0
- package/dist/packages/primitives/skip-link/src/SkipLink.vue.d.ts +62 -0
- package/dist/packages/primitives/skip-link/src/SkipLink.vue_vue_type_script_setup_true_lang.js +64 -0
- package/dist/packages/primitives/skip-link/src/SkipLink.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/packages/primitives/skip-link/src/index.d.ts +3 -0
- package/dist/packages/primitives/skip-link/src/index.js +3 -0
- 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.js.map +1 -1
- package/dist/packages/primitives/stepper/src/Stepper.vue.d.ts +2 -2
- package/dist/packages/primitives/stepper/src/Stepper.vue_vue_type_script_setup_true_lang.js +7 -5
- package/dist/packages/primitives/stepper/src/Stepper.vue_vue_type_script_setup_true_lang.js.map +1 -1
- 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.js.map +1 -1
- package/dist/packages/primitives/time-picker/src/TimePicker.vue.d.ts +2 -2
- package/dist/packages/primitives/time-picker/src/TimePicker.vue_vue_type_script_setup_true_lang.js +10 -8
- package/dist/packages/primitives/time-picker/src/TimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- 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 +5 -3
- 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/toggle-group/src/ToggleGroup.js +7 -0
- package/dist/packages/primitives/toggle-group/src/ToggleGroup.js.map +1 -0
- package/dist/packages/primitives/toggle-group/src/ToggleGroup.vue.d.ts +53 -0
- package/dist/packages/primitives/toggle-group/src/ToggleGroup.vue.d.ts.map +1 -0
- package/dist/packages/primitives/toggle-group/src/ToggleGroup.vue_vue_type_script_setup_true_lang.js +111 -0
- package/dist/packages/primitives/toggle-group/src/ToggleGroup.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/packages/primitives/toggle-group/src/index.d.ts +3 -0
- package/dist/packages/primitives/toggle-group/src/index.d.ts.map +1 -0
- package/dist/packages/primitives/toggle-group/src/index.js +2 -0
- package/dist/packages/primitives/toolbar/src/Toolbar.js +7 -0
- package/dist/packages/primitives/toolbar/src/Toolbar.js.map +1 -0
- package/dist/packages/primitives/toolbar/src/Toolbar.vue.d.ts +31 -0
- package/dist/packages/primitives/toolbar/src/Toolbar.vue.d.ts.map +1 -0
- package/dist/packages/primitives/toolbar/src/Toolbar.vue_vue_type_script_setup_true_lang.js +149 -0
- package/dist/packages/primitives/toolbar/src/Toolbar.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/packages/primitives/toolbar/src/ToolbarSeparator.js +7 -0
- package/dist/packages/primitives/toolbar/src/ToolbarSeparator.js.map +1 -0
- package/dist/packages/primitives/toolbar/src/ToolbarSeparator.vue.d.ts +24 -0
- package/dist/packages/primitives/toolbar/src/ToolbarSeparator.vue.d.ts.map +1 -0
- package/dist/packages/primitives/toolbar/src/ToolbarSeparator.vue_vue_type_script_setup_true_lang.js +40 -0
- package/dist/packages/primitives/toolbar/src/ToolbarSeparator.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/packages/primitives/toolbar/src/index.d.ts +4 -0
- package/dist/packages/primitives/toolbar/src/index.d.ts.map +1 -0
- package/dist/packages/primitives/toolbar/src/index.js +3 -0
- 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/tree-view/src/TreeView.js +7 -0
- package/dist/packages/primitives/tree-view/src/TreeView.js.map +1 -0
- package/dist/packages/primitives/tree-view/src/TreeView.vue.d.ts +99 -0
- package/dist/packages/primitives/tree-view/src/TreeView.vue_vue_type_script_setup_true_lang.js +310 -0
- package/dist/packages/primitives/tree-view/src/TreeView.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/packages/primitives/tree-view/src/TreeViewNode.js +7 -0
- package/dist/packages/primitives/tree-view/src/TreeViewNode.js.map +1 -0
- package/dist/packages/primitives/tree-view/src/TreeViewNode.vue.d.ts +15 -0
- package/dist/packages/primitives/tree-view/src/TreeViewNode.vue.d.ts.map +1 -0
- package/dist/packages/primitives/tree-view/src/TreeViewNode.vue_vue_type_script_setup_true_lang.js +103 -0
- package/dist/packages/primitives/tree-view/src/TreeViewNode.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/packages/primitives/tree-view/src/context.d.ts +39 -0
- package/dist/packages/primitives/tree-view/src/context.d.ts.map +1 -0
- package/dist/packages/primitives/tree-view/src/context.js +6 -0
- package/dist/packages/primitives/tree-view/src/context.js.map +1 -0
- package/dist/packages/primitives/tree-view/src/index.d.ts +4 -0
- package/dist/packages/primitives/tree-view/src/index.js +3 -0
- package/dist/packages/primitives/visually-hidden/src/VisuallyHidden.js +7 -0
- package/dist/packages/primitives/visually-hidden/src/VisuallyHidden.js.map +1 -0
- package/dist/packages/primitives/visually-hidden/src/VisuallyHidden.vue.d.ts +21 -0
- package/dist/packages/primitives/visually-hidden/src/VisuallyHidden.vue.d.ts.map +1 -0
- package/dist/packages/primitives/visually-hidden/src/VisuallyHidden.vue_vue_type_script_setup_true_lang.js +27 -0
- package/dist/packages/primitives/visually-hidden/src/VisuallyHidden.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/packages/primitives/visually-hidden/src/index.d.ts +3 -0
- package/dist/packages/primitives/visually-hidden/src/index.d.ts.map +1 -0
- package/dist/packages/primitives/visually-hidden/src/index.js +2 -0
- 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 +37 -30
- 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
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collapse — one disclosure: a trigger that shows and hides a single region
|
|
3
|
+
* of content. The generic primitive under Accordion's row-group; the state
|
|
4
|
+
* machinery is Reka's Collapsible, so controlled and uncontrolled use,
|
|
5
|
+
* aria-expanded/aria-controls wiring and rapid open/close are all owned
|
|
6
|
+
* there rather than reimplemented here.
|
|
7
|
+
*
|
|
8
|
+
* Expansion animates on the shared height pair (`--animate-expand` /
|
|
9
|
+
* `--animate-collapse`) keyed to Reka's measured
|
|
10
|
+
* `--reka-collapsible-content-height`; padding lives on an inner wrapper
|
|
11
|
+
* because a padded outer box would pop at both ends of the animation while
|
|
12
|
+
* its height interpolated.
|
|
13
|
+
*/
|
|
14
|
+
declare const _default: typeof __VLS_export;
|
|
15
|
+
export default _default;
|
|
16
|
+
declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
|
|
17
|
+
/**
|
|
18
|
+
* Controls visibility; pair with `v-model:open`. Omit it and the collapse
|
|
19
|
+
* owns its own state, seeded by `defaultOpen`.
|
|
20
|
+
*/
|
|
21
|
+
open?: boolean | undefined;
|
|
22
|
+
/** The uncontrolled starting state. */
|
|
23
|
+
defaultOpen?: boolean;
|
|
24
|
+
/** Unavailable rather than hidden: the trigger stays put and inert. */
|
|
25
|
+
disabled?: boolean;
|
|
26
|
+
}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
27
|
+
"update:open": (value: boolean) => any;
|
|
28
|
+
}, string, import("vue").PublicProps, Readonly<{
|
|
29
|
+
/**
|
|
30
|
+
* Controls visibility; pair with `v-model:open`. Omit it and the collapse
|
|
31
|
+
* owns its own state, seeded by `defaultOpen`.
|
|
32
|
+
*/
|
|
33
|
+
open?: boolean | undefined;
|
|
34
|
+
/** The uncontrolled starting state. */
|
|
35
|
+
defaultOpen?: boolean;
|
|
36
|
+
/** Unavailable rather than hidden: the trigger stays put and inert. */
|
|
37
|
+
disabled?: boolean;
|
|
38
|
+
}> & Readonly<{
|
|
39
|
+
"onUpdate:open"?: (value: boolean) => any;
|
|
40
|
+
}>, {
|
|
41
|
+
disabled: boolean;
|
|
42
|
+
open: boolean | undefined;
|
|
43
|
+
defaultOpen: boolean;
|
|
44
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, {
|
|
45
|
+
trigger?: (props: {
|
|
46
|
+
open: boolean;
|
|
47
|
+
}) => any;
|
|
48
|
+
} & {
|
|
49
|
+
default?: (props: {}) => any;
|
|
50
|
+
}>;
|
|
51
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
52
|
+
new (): {
|
|
53
|
+
$slots: S;
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=Collapse.vue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Collapse.vue.d.ts","sourceRoot":"","sources":["../../../../../packages/primitives/collapse/src/Collapse.vue"],"names":[],"mappings":"AAmHA;;;;;;;;;;;;GAYG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AACzC,QAAA,MAAM,YAAY;IAEd;;;OAGG;WACI,OAAO,GAAG,SAAS;IAC1B,uCAAuC;kBACzB,OAAO;IACrB,uEAAuE;eAC5D,OAAO;;;;IARlB;;;OAGG;WACI,OAAO,GAAG,SAAS;IAC1B,uCAAuC;kBACzB,OAAO;IACrB,uEAAuE;eAC5D,OAAO;;;;cAAP,OAAO;UAJX,OAAO,GAAG,SAAS;iBAEZ,OAAO;;cAqLX,CAAC,KAAK;;KAAiB,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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { cn } from "../../../core/src/cn.js";
|
|
2
|
+
import { optional } from "../../../core/src/props.js";
|
|
3
|
+
import "../../../core/src/index.js";
|
|
4
|
+
import { createBlock, createElementVNode, createVNode, defineComponent, mergeProps, normalizeClass, openBlock, renderSlot, unref, useId, withCtx } from "vue";
|
|
5
|
+
import { ChevronDown } from "@lucide/vue";
|
|
6
|
+
import { CollapsibleContent, CollapsibleRoot, CollapsibleTrigger } from "reka-ui";
|
|
7
|
+
//#region packages/primitives/collapse/src/Collapse.vue?vue&type=script&setup=true&lang.ts
|
|
8
|
+
var _hoisted_1 = ["id"];
|
|
9
|
+
/**
|
|
10
|
+
* Collapse — one disclosure: a trigger that shows and hides a single region
|
|
11
|
+
* of content. The generic primitive under Accordion's row-group; the state
|
|
12
|
+
* machinery is Reka's Collapsible, so controlled and uncontrolled use,
|
|
13
|
+
* aria-expanded/aria-controls wiring and rapid open/close are all owned
|
|
14
|
+
* there rather than reimplemented here.
|
|
15
|
+
*
|
|
16
|
+
* Expansion animates on the shared height pair (`--animate-expand` /
|
|
17
|
+
* `--animate-collapse`) keyed to Reka's measured
|
|
18
|
+
* `--reka-collapsible-content-height`; padding lives on an inner wrapper
|
|
19
|
+
* because a padded outer box would pop at both ends of the animation while
|
|
20
|
+
* its height interpolated.
|
|
21
|
+
*/
|
|
22
|
+
var Collapse_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
|
|
23
|
+
__name: "Collapse",
|
|
24
|
+
props: {
|
|
25
|
+
open: {
|
|
26
|
+
type: Boolean,
|
|
27
|
+
default: void 0
|
|
28
|
+
},
|
|
29
|
+
defaultOpen: {
|
|
30
|
+
type: Boolean,
|
|
31
|
+
default: false
|
|
32
|
+
},
|
|
33
|
+
disabled: {
|
|
34
|
+
type: Boolean,
|
|
35
|
+
default: false
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
emits: ["update:open"],
|
|
39
|
+
setup(__props) {
|
|
40
|
+
const triggerId = useId();
|
|
41
|
+
const contentId = useId();
|
|
42
|
+
return (_ctx, _cache) => {
|
|
43
|
+
return openBlock(), createBlock(unref(CollapsibleRoot), mergeProps(unref(optional)({ open: __props.open }), {
|
|
44
|
+
"default-open": __props.defaultOpen,
|
|
45
|
+
disabled: __props.disabled,
|
|
46
|
+
"unmount-on-hide": false,
|
|
47
|
+
"onUpdate:open": _cache[0] || (_cache[0] = ($event) => _ctx.$emit("update:open", $event))
|
|
48
|
+
}), {
|
|
49
|
+
default: withCtx(({ open: state }) => [createVNode(unref(CollapsibleTrigger), {
|
|
50
|
+
id: unref(triggerId),
|
|
51
|
+
"aria-controls": unref(contentId),
|
|
52
|
+
class: normalizeClass(unref(cn)("group flex w-full items-center justify-between gap-3 rounded-md px-4 py-3 text-left text-sm font-medium", "transition-colors duration-fast ease-out hover:bg-subtle", "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo", "disabled:pointer-events-none disabled:bg-transparent disabled:text-muted-foreground"))
|
|
53
|
+
}, {
|
|
54
|
+
default: withCtx(() => [renderSlot(_ctx.$slots, "trigger", { open: state }), createVNode(unref(ChevronDown), {
|
|
55
|
+
class: "h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-fast ease-out group-data-[state=open]:rotate-180",
|
|
56
|
+
"aria-hidden": "true"
|
|
57
|
+
})]),
|
|
58
|
+
_: 2
|
|
59
|
+
}, 1032, [
|
|
60
|
+
"id",
|
|
61
|
+
"aria-controls",
|
|
62
|
+
"class"
|
|
63
|
+
]), createVNode(unref(CollapsibleContent), {
|
|
64
|
+
"data-loom-collapse": "",
|
|
65
|
+
class: "overflow-hidden data-[state=open]:animate-expand data-[state=closed]:animate-collapse"
|
|
66
|
+
}, {
|
|
67
|
+
default: withCtx(() => [createElementVNode("div", {
|
|
68
|
+
id: unref(contentId),
|
|
69
|
+
class: "px-4 pb-4"
|
|
70
|
+
}, [renderSlot(_ctx.$slots, "default")], 8, _hoisted_1)]),
|
|
71
|
+
_: 3
|
|
72
|
+
})]),
|
|
73
|
+
_: 3
|
|
74
|
+
}, 16, ["default-open", "disabled"]);
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
//#endregion
|
|
79
|
+
export { Collapse_vue_vue_type_script_setup_true_lang_default as default };
|
|
80
|
+
|
|
81
|
+
//# sourceMappingURL=Collapse.vue_vue_type_script_setup_true_lang.js.map
|
package/dist/packages/primitives/collapse/src/Collapse.vue_vue_type_script_setup_true_lang.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Collapse.vue_vue_type_script_setup_true_lang.js","names":["$emit"],"sources":["../../../../../packages/primitives/collapse/src/Collapse.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Collapse — one disclosure: a trigger that shows and hides a single region\n * of content. The generic primitive under Accordion's row-group; the state\n * machinery is Reka's Collapsible, so controlled and uncontrolled use,\n * aria-expanded/aria-controls wiring and rapid open/close are all owned\n * there rather than reimplemented here.\n *\n * Expansion animates on the shared height pair (`--animate-expand` /\n * `--animate-collapse`) keyed to Reka's measured\n * `--reka-collapsible-content-height`; padding lives on an inner wrapper\n * because a padded outer box would pop at both ends of the animation while\n * its height interpolated.\n */\n</script>\n\n<script setup lang=\"ts\">\nimport { ChevronDown } from \"@lucide/vue\";\nimport { CollapsibleContent, CollapsibleRoot, CollapsibleTrigger } from \"reka-ui\";\nimport { cn, optional } from \"@ecoma-io/loom-core\";\nimport { useId } from \"vue\";\n\nwithDefaults(\n defineProps<{\n /**\n * Controls visibility; pair with `v-model:open`. Omit it and the collapse\n * owns its own state, seeded by `defaultOpen`.\n */\n open?: boolean | undefined;\n /** The uncontrolled starting state. */\n defaultOpen?: boolean;\n /** Unavailable rather than hidden: the trigger stays put and inert. */\n disabled?: boolean;\n }>(),\n {\n // `undefined` is the uncontrolled state, and only an explicit default\n // keeps it reachable past Vue's Boolean casting.\n open: undefined,\n defaultOpen: false,\n disabled: false,\n },\n);\n\ndefineEmits<{ \"update:open\": [value: boolean] }>();\n\n// Reka leaves the trigger's aria-controls pointing at an id its Content only\n// registers non-reactively, so a closed-first render ships an empty IDREF.\n// Both halves get explicit ids here instead; fallthrough attributes merge\n// after Reka's own, which is the same mechanism AlertDialog uses to clear\n// its dangling describedby.\nconst triggerId = useId();\nconst contentId = useId();\n</script>\n\n<template>\n <CollapsibleRoot\n v-slot=\"{ open: state }\"\n v-bind=\"optional({ open })\"\n :default-open=\"defaultOpen\"\n :disabled=\"disabled\"\n :unmount-on-hide=\"false\"\n @update:open=\"$emit('update:open', $event)\"\n >\n <CollapsibleTrigger\n :id=\"triggerId\"\n :aria-controls=\"contentId\"\n :class=\"\n cn(\n 'group flex w-full items-center justify-between gap-3 rounded-md px-4 py-3 text-left text-sm font-medium',\n 'transition-colors duration-fast ease-out hover:bg-subtle',\n 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo',\n 'disabled:pointer-events-none disabled:bg-transparent disabled:text-muted-foreground',\n )\n \"\n >\n <!-- @slot The control's visible face, inside a real `<button>` carrying\n aria-expanded/aria-controls and the canonical focus ring. `open`\n mirrors the real state, controlled or not. -->\n <slot name=\"trigger\" :open=\"state\" />\n <ChevronDown\n class=\"h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-fast ease-out group-data-[state=open]:rotate-180\"\n aria-hidden=\"true\"\n />\n </CollapsibleTrigger>\n <!-- Mounted even while closed: the region id in aria-controls has to\n resolve for a screen reader before the first expansion, and a\n persistent element is what lets the collapse animation actually play\n instead of being unmounted mid-frame. Reka conceals the closed\n region with hidden=\"until-found\". -->\n <CollapsibleContent\n data-loom-collapse=\"\"\n class=\"overflow-hidden data-[state=open]:animate-expand data-[state=closed]:animate-collapse\"\n >\n <!-- The animated box carries no padding of its own: interpolating\n height around fixed padding pops at both ends of the film. This\n inner div also carries the id the trigger references: Reka writes\n its own content id after any we pass, so the reference lands here\n where it actually resolves. -->\n <div :id=\"contentId\" class=\"px-4 pb-4\">\n <!-- @slot The region's content. Nested collapses work unchanged —\n each owns its own region. -->\n <slot />\n </div>\n </CollapsibleContent>\n </CollapsibleRoot>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkDA,MAAM,YAAY,MAAM;EACxB,MAAM,YAAY,MAAM;;GAItB,OAAA,UAAA,GAAA,YAiDkB,MAAA,eAAA,GAjDlB,WAEU,MA+CQ,QAAA,CA/CA,CAAA,EAAA,MAAG,QAAA,KAAI,CAAA,GAAA;IACtB,gBAAc,QAAA;IACd,UAAU,QAAA;IACV,mBAAiB;IACjB,iBAAW,OAAA,OAAA,OAAA,MAAA,WAAEA,KAAAA,MAAK,eAAgB,MAAM;;IAEzC,SAAA,SAoBqB,EAAA,MA3BL,YAAK,CAOrB,YAoBqB,MAAA,kBAAA,GAAA;KAnBlB,IAAI,MAAA,SAAA;KACJ,iBAAe,MAAA,SAAA;KACf,OAAK,eAAW,MAAA,EAAA,CAAE,CAAA,2GAAA,4DAAA,+GAAA,qFAAA,CAAA;;KAYnB,SAAA,cAAqC,CAArC,WAAqC,KAAA,QAAA,WAAA,EAAf,MAAM,MAAK,CAAA,GACjC,YAGE,MAAA,WAAA,GAAA;MAFA,OAAM;MACN,eAAY;;;;;;;IAQhB,CAAA,GAAA,YAcqB,MAAA,kBAAA,GAAA;KAbnB,sBAAmB;KACnB,OAAM;;KAON,SAAA,cAIM,CAJN,mBAIM,OAAA;MAJA,IAAI,MAAA,SAAA;MAAW,OAAM;KAGzB,GAAA,CAAA,WAAQ,KAAA,QAAA,SAAA,CAAA,GAAA,GAAA,UAAA,CAAA,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../packages/primitives/collapse/src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ColorPicker.js","names":[],"sources":["../../../../../packages/primitives/color-picker/src/ColorPicker.vue"],"sourcesContent":["<script lang=\"ts\">\nimport type { ColorPickerLabels } from \"@ecoma-io/loom-labels\";\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 COLOR_PICKER_LABELS: ColorPickerLabels = {\n area: \"Saturation and brightness\",\n areaRoleDescription: \"Colour picker\",\n areaThumb: \"Saturation and brightness\",\n areaThumbRoleDescription: \"Colour thumb\",\n // Differs from Reka's own \"Saturation 60, Brightness 80\" by the one capital,\n // which is the same trick the rest of the library uses to let a test assert\n // whose string reached the DOM rather than merely what it said.\n areaValue: ({ saturation, brightness }) =>\n `Saturation ${String(saturation)}, brightness ${String(brightness)}`,\n hue: \"Hue\",\n hex: \"Hex value\",\n presets: \"Presets\",\n swatch: ({ color }) => color,\n swatchRoleDescription: \"Colour swatch\",\n};\n</script>\n\n<script setup lang=\"ts\">\nimport { computed, nextTick, ref, useTemplateRef, watch } from \"vue\";\nimport {\n ColorAreaRoot,\n ColorAreaArea,\n ColorAreaThumb,\n ColorSliderRoot,\n ColorSliderTrack,\n ColorSliderThumb,\n ColorFieldRoot,\n ColorFieldInput,\n ColorSwatch,\n ColorSwatchPickerRoot,\n ColorSwatchPickerItem,\n colorToString,\n getChannelValue,\n isValidColor,\n normalizeColor,\n type Color,\n} from \"reka-ui\";\nimport { cn } from \"@ecoma-io/loom-core\";\nimport { optional } 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 * ColorPicker — choose one colour, as `#rrggbb`. A saturation/brightness\n * area, a hue slider, an editable hex field, and an optional row of presets.\n * Reach for it when the colour itself is the value being authored: a label\n * colour, a chart series, a theme override.\n *\n * When the choice is actually a small closed set — a status colour, a brand\n * palette — a Select or a RadioGroup names the options and this does not.\n * A picker offers sixteen million answers, which is the wrong control for a\n * question with six.\n *\n * Built on Reka UI's colour parts, which supply the whole semantic layer:\n * `role=\"slider\"` on both thumbs, the area's two-axis arrow stepping, the\n * listbox roving focus over the presets, and the parsing that turns typed text\n * into a colour. Every part models its value as a colour string and emits hex,\n * which is what lets this expose one plain `#rrggbb` rather than a channel\n * object.\n *\n * **Where the \"no raw colour values\" rule falls here.** The colour a person is\n * picking is *data*: the area's gradient, the hue track and every swatch fill\n * are bound from the model value at run time, and a token could not express\n * them. Everything that is *chrome* — the borders, the focus ring, the field,\n * the labels, the disabled state, the rings that keep the thumbs visible —\n * comes from `theme.css` and nothing else. A literal colour in this file is a\n * defect unless it is a value being picked.\n *\n * **The hex is the non-colour channel.** A control that communicates only in\n * colour is unusable by the readers most likely to need help choosing one, so\n * the hex value is always on screen as text and is itself the edit surface;\n * every swatch is named rather than left a bare square — by its hex unless\n * `labels.swatch` gives it words; and the disabled state is carried by\n * `aria-disabled` as well as by the appearance. It is also why the hex is the\n * one part of an unavailable picker that is drained rather than dimmed — see\n * the root's class list.\n *\n * The event contract matches Slider and NumberField. `update:modelValue` is\n * transient — every position a thumb passes through — and `commit` fires once\n * per gesture, so one drag across the area is one undo entry rather than a\n * hundred.\n *\n * Inside a [Field](../Field/Field.vue) it wires itself through\n * `useFieldControl()`, and the row's answers land on two different nodes — see\n * the comment above `groupFieldAttrs`, which is where that split is decided.\n * **A row's label does not name the picker.** `<label for>` names a labelable\n * element and this renders a `div[role=\"group\"]`, so the row's label resolves\n * to it and announces nobody; `ariaLabel`/`ariaLabelledby` below are what name\n * the picker, exactly as they were before.\n *\n * There is no `readonly`, and a row's is ignored rather than approximated. A\n * colour that may be looked at but not changed is a swatch — the `ColorSwatch`\n * beside the hex value already is one — and none of the four parts has a\n * read-only state to put it in, so the honest options were a picker that looks\n * live and swallows every gesture, or none at all.\n */\nconst props = withDefaults(\n defineProps<{\n /** The chosen colour as `#rrggbb`. There is no alpha channel in this version. */\n modelValue?: string;\n /** Preset colours shown as a row of named swatches. Omit it and no row is rendered. */\n swatches?: string[];\n /** Unavailable: dims the picker and refuses the pointer, the keyboard and the field. Unset defers to a wrapping Field. */\n disabled?: boolean | undefined;\n /** The accessible name for the picker as a whole, when nothing visible already labels it. */\n ariaLabel?: string;\n /** The id of the visible element that labels the picker (a Field wrapper's label, say). */\n ariaLabelledby?: string;\n /**\n * Names for the parts, as any subset of `ColorPickerLabels` — the rest stay\n * as the host's `provideLoomLabels` vocabulary left them, and then as\n * Loom's English.\n *\n * `ariaLabel` above names the *picker*; this names what is inside it, and\n * six of its nine keys are the only thing standing between a reader and\n * Reka UI's own English.\n */\n labels?: LabelOverrides<ColorPickerLabels>;\n }>(),\n {\n // Not `false`: absent has to stay tellable from `false` for a Field above\n // to disable the row and for `:disabled=\"false\"` to overrule one that does.\n // Vue casts an absent Boolean prop with no declared default to `false`,\n // which would leave the context wired and inert.\n disabled: undefined,\n },\n);\n\nconst emit = defineEmits<{\n /** Transient: every colour a drag or an arrow step passes through. Not a checkpoint. */\n \"update:modelValue\": [value: string];\n /** Committed: once per gesture — drag release, arrow step, hex entry, preset click. */\n commit: [value: string];\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(\"colorPicker\", COLOR_PICKER_LABELS, () => props.labels);\n\n// The seed for an unset or unparseable model value. Reka's ColorArea, ColorField\n// and ColorSlider each fall back to this same string internally, so matching it\n// is what keeps the four parts agreeing about what \"no colour yet\" looks like\n// rather than each inventing its own. It is picked data, not a theme colour.\nconst FALLBACK = \"#000000\";\n\n// A colour a consumer supplied is parsed by Reka inside a render function, and\n// an unparseable one throws there — taking the host's page down, not just this\n// component. A library cannot do that with a prop, so every value entering\n// `current` is checked first. `isValidColor` is Reka's own parser rather than a\n// regex here, so what this accepts and what the parts accept cannot drift.\nfunction toColor(value: string | undefined): string {\n return value !== undefined && isValidColor(value) ? value : FALLBACK;\n}\n\n// The working colour, fed to all four parts. Seeded from the prop and advanced\n// on every tick, exactly as Slider's `lastValue` is: given a defined model value\n// Reka runs fully controlled, so a host that correctly withholds transient\n// values until commit would otherwise freeze the thumbs at the gesture's start.\nconst current = ref(toColor(props.modelValue));\n\n// The value the host last acknowledged. Every commit path compares against it,\n// which is what makes a gesture that ends where it started — a click that lands\n// on the thumb, an arrow at the edge of the area, the same hex retyped, the\n// already-selected preset clicked again — produce no checkpoint at all.\nconst lastCommitted = ref(current.value);\n\n// An incoming value equal to `current` is this component's own emit echoing\n// back through a `v-model`, and re-baselining on it would swallow the commit at\n// the end of the gesture that produced it. Anything else is the host moving the\n// colour itself, which is a new baseline by definition — which is why this\n// needs no \"is a gesture in flight?\" flag to tell the two apart.\nwatch(\n () => props.modelValue,\n (value) => {\n const next = toColor(value);\n if (next === current.value) return;\n current.value = next;\n lastCommitted.value = next;\n },\n);\n\n// Every one of Reka's parts writes a hex string back into its own model, but\n// each types its update as `string | Color` because that union is what it will\n// *accept* coming in. Narrowing it here rather than casting keeps the object\n// half real: a future part that emits one still resolves to hex instead of\n// stringifying to \"[object Object]\" and failing to parse two frames later.\nfunction applyFromPart(value: string | Color): void {\n apply(typeof value === \"string\" ? value : colorToString(value, \"hex\"));\n}\n\nfunction apply(next: string): void {\n const value = toColor(next);\n if (value === current.value) return;\n current.value = value;\n emit(\"update:modelValue\", value);\n}\n\n/**\n * The area thumb's `aria-valuetext`, which Reka would otherwise build from its\n * own English channel names — \"Saturation 60, Brightness 80\", said again on\n * every arrow key.\n *\n * The two numbers are recomputed here rather than read out of Reka, because\n * Reka exposes neither: `ColorAreaRoot` yields only `style` to its slot and\n * keeps `xValue`/`yValue` in a context this component cannot inject. What it\n * does export is the arithmetic — `getChannelValue` and `normalizeColor` are\n * the same two functions `ColorAreaRoot` calls, applied to the same `current`\n * this component hands it as `model-value`, with the same `Math.round`. So the\n * number here and the `aria-valuenow` beside it agree by construction rather\n * than by coincidence, which is what makes replacing this string safe: Reka\n * re-derives its own pair from the model on the next tick after any gesture,\n * to this identical formula.\n */\nconst areaValueText = computed(() => {\n const color = normalizeColor(current.value);\n return text.value.areaValue({\n saturation: Math.round(getChannelValue(color, \"saturation\")),\n brightness: Math.round(getChannelValue(color, \"brightness\")),\n });\n});\n\nfunction onFieldCommit(value: string | Color): void {\n applyFromPart(value);\n commitCurrent();\n}\n\nfunction commitCurrent(): void {\n if (current.value === lastCommitted.value) return;\n lastCommitted.value = current.value;\n emit(\"commit\", current.value);\n}\n\n// Reka commits the area on pointer release only — `ColorAreaArea` calls its\n// root's `commitValues` from `pointerup` and not from its own key handler — so\n// an arrow-stepped colour would never reach a host's undo stack. Deferring by a\n// tick is what makes this independent of whether Vue runs this listener before\n// or after Reka's on the same element: by then the step has been applied and\n// `current` holds it. `commitCurrent` swallows the no-op at the axis limits.\nconst AREA_STEP_KEYS = new Set([\n \"ArrowLeft\",\n \"ArrowRight\",\n \"ArrowUp\",\n \"ArrowDown\",\n \"PageUp\",\n \"PageDown\",\n \"Home\",\n \"End\",\n]);\n\nfunction onAreaKeydown(event: KeyboardEvent): void {\n if (field.disabled || !AREA_STEP_KEYS.has(event.key)) return;\n void nextTick(commitCurrent);\n}\n\n// A preset that will not parse is dropped rather than rendered: it would be an\n// invisible square that sets an unusable value, and an empty row would leave a\n// `role=\"listbox\"` with no options, which is an ARIA violation of its own. The\n// row is therefore rendered only when something survives this.\nconst presets = computed(() => (props.swatches ?? []).filter((swatch) => isValidColor(swatch)));\n\nfunction onPresetPick(value: unknown): void {\n if (typeof value !== \"string\") return;\n apply(value);\n commitCurrent();\n}\n\n// Unlike Slider and Select, `class` and the remaining fallthrough attributes go\n// to the same node. The picker has four interactive parts and no single one of\n// them is what an `aria-describedby` or a `data-testid` is about — the group\n// around them is. `class` still needs the `cn()` merge rather than Vue's plain\n// concatenation, so it is bound separately from the spread.\ndefineOptions({ inheritAttrs: false });\nconst { attrs, rest: groupAttrs } = useSplitAttrs();\n\n/**\n * Two of this control's four parts are Reka roots that the platform cannot\n * disable: the saturation area and the hue slider render `<span role=\"slider\"\n * tabindex=\"0\">`, and `<fieldset disabled>` reaches only `<input>`, `<button>`,\n * `<select>` and `<textarea>`. Measured in jsdom, both still took an arrow key\n * inside a disabled group and moved the colour — while the hex `<input>` beside\n * them went properly inert, so the picker was half unavailable and half not.\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// `id` and `aria-describedby` arrive as fallthrough attrs rather than props, so\n// they are handed in as this caller's own values: a caller who sets either\n// still beats the row, and the row's description is merged into theirs rather\n// than replacing it. `name`, `required` and `invalid` are absent because this\n// component has no prop for any of them — the row's answer stands unopposed.\nconst field = useFieldControl(() => ({\n id: attrs.id as string | undefined,\n describedBy: attrs[\"aria-describedby\"] as string | undefined,\n // The fieldset beats the prop in both directions, exactly as it does for the\n // hex input inside this very control.\n disabled: groupDisabled.value ? true : props.disabled,\n}));\n\n/**\n * The half of the resolved bag the group takes, and the reason there are two\n * halves at all.\n *\n * A row describes *the picker*, and no one of the four parts is the picker —\n * the colour is authored across all of them — so the group around them is what\n * carries the identity and the description, exactly as a `data-testid` does.\n *\n * `name` and `aria-required` cannot follow them there. ARIA allows neither on\n * `role=\"group\"`, and `aria-allowed-attr` is a WCAG 4.1.2 rule\n * `e2e/accessibility.e2e.ts` runs over every docs page, so shipping the whole\n * bag here would turn that gate red. They go to the hex field instead, which is\n * the picker's one real form control: a native `<input>` holding exactly the\n * `#rrggbb` this component emits, so — unlike NumberField's spinbutton, which\n * holds a *formatted* number and would post its grouping separators — a `name`\n * on it submits the model value itself. `aria-invalid` rides along with them,\n * because a state announced on entering a group is a state most readers meet\n * once, while the field is where an error about the value is actually read.\n */\nconst groupFieldAttrs = computed(() =>\n optional({ id: field.id, \"aria-describedby\": field.attrs[\"aria-describedby\"] }),\n);\n\n// Both thumbs sit on a surface whose colour is the value being chosen, so they\n// have to read against white, against black and against every hue in between. A\n// single-colour thumb cannot: the light ring vanishes on a pale fill and the\n// dark one vanishes on a dark fill. The pair — a `background` band inside a\n// `foreground` hairline — always leaves one of the two in contrast.\nconst THUMB =\n \"block size-6 rounded-full border-2 border-background bg-transparent ring-1 ring-foreground shadow-sm \" +\n \"transition-transform duration-fast ease-spring hover:scale-110 active:scale-95 \" +\n \"focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo \" +\n \"data-[disabled]:pointer-events-none\";\n</script>\n\n<template>\n <div\n ref=\"root\"\n v-bind=\"{ ...groupAttrs, ...groupFieldAttrs }\"\n role=\"group\"\n :aria-label=\"ariaLabel\"\n :aria-labelledby=\"ariaLabelledby\"\n :aria-disabled=\"field.disabled || undefined\"\n :data-disabled=\"field.disabled || undefined\"\n :class=\"\n cn(\n 'flex w-full max-w-xs flex-col gap-3',\n // No `opacity` on the group, and the split below is the whole reason.\n // A dim here ran over everything the picker holds, the hex among it:\n // measured on the built site, `opacity-50` put the hex value at 3.06:1\n // — the same 3.08:1 the text input's own dim produced before it was\n // drained, and the same failure axe does not raise because it exempts\n // a disabled control under 1.4.3.\n //\n // So the two halves part. The three surfaces whose whole content is\n // the colour being picked keep the dim, because that is what\n // unavailable looks like for a surface a token cannot drain; the hex\n // field takes the same drained fill, muted text and slackened rim\n // every other control in the library wears, because it is text and it\n // is the one thing a reader still needs from a picker they cannot use.\n field.disabled && 'cursor-not-allowed',\n attrs.class as string,\n )\n \"\n >\n <!-- Saturation across, brightness up. `style` is Reka's own gradient for\n those two axes at the current hue — the picked colour rendered as a\n surface, which is data and not a token. -->\n <ColorAreaRoot\n v-slot=\"{ style }\"\n :model-value=\"current\"\n color-space=\"hsb\"\n x-channel=\"saturation\"\n y-channel=\"brightness\"\n :disabled=\"field.disabled\"\n @update:model-value=\"applyFromPart\"\n @change-end=\"commitCurrent\"\n >\n <!-- Reka gives this `role=\"application\"`, which hands every key straight\n to the area rather than to the screen reader's own navigation. That\n only works if the region says what it is, so it is named here; the\n thumb inside carries the per-axis values.\n\n Both `aria-roledescription`s below replace one Reka writes in English\n inside its own render function. They reach the DOM as fallthrough\n attributes, which Vue merges last, so each is a replacement rather\n than a second phrase — and removing one falls back to Reka's English\n rather than to nothing, which is the failure no test of Loom's own\n strings would catch.\n\n `aria-valuetext` on the thumb is the third of them and the one a\n reader hears most, since it is re-announced on every arrow key.\n `areaValueText` explains why replacing it does not risk contradicting\n the `aria-valuenow` beside it. -->\n <ColorAreaArea\n :style=\"style\"\n :aria-label=\"text.area\"\n :aria-roledescription=\"text.areaRoleDescription\"\n class=\"relative h-40 w-full rounded-md border border-border data-[disabled]:opacity-50\"\n @keydown=\"onAreaKeydown\"\n >\n <ColorAreaThumb\n :aria-label=\"text.areaThumb\"\n :aria-roledescription=\"text.areaThumbRoleDescription\"\n :aria-valuetext=\"areaValueText\"\n :class=\"THUMB\"\n />\n </ColorAreaArea>\n </ColorAreaRoot>\n\n <ColorSliderRoot\n :model-value=\"current\"\n channel=\"hue\"\n color-space=\"hsb\"\n :disabled=\"field.disabled\"\n class=\"relative flex w-full touch-none items-center py-1\"\n @update:model-value=\"applyFromPart\"\n @change-end=\"commitCurrent\"\n >\n <ColorSliderTrack\n class=\"relative h-3 w-full grow rounded-full border border-border data-[disabled]:opacity-50\"\n />\n <!-- Reka names this from its channel — \"Hue\" — so the binding replaces\n that rather than adding to it. -->\n <ColorSliderThumb :aria-label=\"text.hue\" :class=\"THUMB\" />\n </ColorSliderRoot>\n\n <!-- The hex is the picker's text channel, so it is always on screen and it\n is the edit surface too. Typing writes the model on blur and on Enter\n rather than per keystroke, so a half-typed value is never emitted and\n text that will not parse is reverted to the current colour; the arrow\n keys nudge it a step at a time. Both paths arrive here already at a\n boundary, which is why the field's update is itself the checkpoint. -->\n <ColorFieldRoot\n :model-value=\"current\"\n :disabled=\"field.disabled\"\n class=\"flex h-9 items-center gap-2 rounded-md border border-input bg-background px-3 text-sm text-foreground transition-[color,background-color,border-color,box-shadow] duration-fast ease-out focus-within:outline-2 focus-within:outline-offset-2 focus-within:outline-ring focus-within:shadow-halo data-[disabled]:cursor-not-allowed data-[disabled]:border-border data-[disabled]:bg-muted data-[disabled]:text-muted-foreground\"\n @update:model-value=\"onFieldCommit\"\n >\n <!-- `label` is Reka's own documented prop for this, so it is set rather\n than bound over: left unset the swatch names itself through a\n `getColorName` that answers \"vibrant red\" in English and is not\n exported for Loom to delegate to. The roledescription is a\n fallthrough replacement, as on the area above. -->\n <ColorSwatch\n :color=\"current\"\n :label=\"text.swatch({ color: current })\"\n :aria-roledescription=\"text.swatchRoleDescription\"\n :style=\"{ backgroundColor: current }\"\n class=\"size-6 shrink-0 rounded-sm border border-border\"\n />\n <!-- The row's three form-control answers, which the group cannot hold —\n see `groupFieldAttrs`. `aria-label` stays: it names the *field*, not\n the picker, and a row's label never reached this element anyway. -->\n <ColorFieldInput\n :aria-label=\"text.hex\"\n :name=\"field.name\"\n :aria-required=\"field.required || undefined\"\n :aria-invalid=\"field.invalid || undefined\"\n class=\"tabular min-w-0 flex-1 self-stretch bg-transparent outline-none disabled:cursor-not-allowed\"\n />\n </ColorFieldRoot>\n\n <!-- One tab stop, not one per swatch: Reka's swatch picker is a listbox\n with roving focus, so arrows move between presets and Enter or Space\n chooses. `replace` rather than Reka's default `toggle`: a row of\n presets is a choice, not a set of switches, so clicking the one\n already showing must re-affirm the colour rather than clear it to\n nothing. `onPresetPick`'s string check holds the same line from the\n other side, for the empty selection `toggle` would emit. -->\n <ColorSwatchPickerRoot\n v-if=\"presets.length > 0\"\n :model-value=\"current\"\n :disabled=\"field.disabled\"\n :aria-disabled=\"field.disabled || undefined\"\n selection-behavior=\"replace\"\n :aria-label=\"text.presets\"\n class=\"flex flex-wrap gap-2 data-[disabled]:opacity-50\"\n @update:model-value=\"onPresetPick\"\n >\n <!-- Each item names itself from Reka's English `getColorName` unless this\n binding replaces it, so a row of presets is where that vocabulary\n leaks in bulk. -->\n <ColorSwatchPickerItem\n v-for=\"preset in presets\"\n :key=\"preset\"\n :value=\"preset\"\n :disabled=\"field.disabled\"\n :aria-label=\"text.swatch({ color: preset })\"\n :style=\"{ backgroundColor: preset }\"\n class=\"size-6 cursor-pointer rounded-sm border border-border transition-transform duration-fast ease-spring hover:scale-110 active:scale-95 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo aria-selected:ring-2 aria-selected:ring-primary aria-selected:ring-offset-2 aria-selected:ring-offset-background data-[disabled]:pointer-events-none\"\n />\n </ColorSwatchPickerRoot>\n </div>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"ColorPicker.js","names":[],"sources":["../../../../../packages/primitives/color-picker/src/ColorPicker.vue"],"sourcesContent":["<script lang=\"ts\">\nimport type { ColorPickerLabels } from \"@ecoma-io/loom-labels\";\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 COLOR_PICKER_LABELS: ColorPickerLabels = {\n area: \"Saturation and brightness\",\n areaRoleDescription: \"Colour picker\",\n areaThumb: \"Saturation and brightness\",\n areaThumbRoleDescription: \"Colour thumb\",\n // Differs from Reka's own \"Saturation 60, Brightness 80\" by the one capital,\n // which is the same trick the rest of the library uses to let a test assert\n // whose string reached the DOM rather than merely what it said.\n areaValue: ({ saturation, brightness }) =>\n `Saturation ${String(saturation)}, brightness ${String(brightness)}`,\n hue: \"Hue\",\n hex: \"Hex value\",\n presets: \"Presets\",\n swatch: ({ color }) => color,\n swatchRoleDescription: \"Colour swatch\",\n};\n</script>\n\n<script setup lang=\"ts\">\nimport { computed, nextTick, ref, useTemplateRef, watch } from \"vue\";\nimport {\n ColorAreaRoot,\n ColorAreaArea,\n ColorAreaThumb,\n ColorSliderRoot,\n ColorSliderTrack,\n ColorSliderThumb,\n ColorFieldRoot,\n ColorFieldInput,\n ColorSwatch,\n ColorSwatchPickerRoot,\n ColorSwatchPickerItem,\n colorToString,\n getChannelValue,\n isValidColor,\n normalizeColor,\n type Color,\n} from \"reka-ui\";\nimport { cn } from \"@ecoma-io/loom-core\";\nimport { optional } 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 * ColorPicker — choose one colour, as `#rrggbb`. A saturation/brightness\n * area, a hue slider, an editable hex field, and an optional row of presets.\n * Reach for it when the colour itself is the value being authored: a label\n * colour, a chart series, a theme override.\n *\n * When the choice is actually a small closed set — a status colour, a brand\n * palette — a Select or a RadioGroup names the options and this does not.\n * A picker offers sixteen million answers, which is the wrong control for a\n * question with six.\n *\n * Built on Reka UI's colour parts, which supply the whole semantic layer:\n * `role=\"slider\"` on both thumbs, the area's two-axis arrow stepping, the\n * listbox roving focus over the presets, and the parsing that turns typed text\n * into a colour. Every part models its value as a colour string and emits hex,\n * which is what lets this expose one plain `#rrggbb` rather than a channel\n * object.\n *\n * **Where the \"no raw colour values\" rule falls here.** The colour a person is\n * picking is *data*: the area's gradient, the hue track and every swatch fill\n * are bound from the model value at run time, and a token could not express\n * them. Everything that is *chrome* — the borders, the focus ring, the field,\n * the labels, the disabled state, the rings that keep the thumbs visible —\n * comes from `theme.css` and nothing else. A literal colour in this file is a\n * defect unless it is a value being picked.\n *\n * **The hex is the non-colour channel.** A control that communicates only in\n * colour is unusable by the readers most likely to need help choosing one, so\n * the hex value is always on screen as text and is itself the edit surface;\n * every swatch is named rather than left a bare square — by its hex unless\n * `labels.swatch` gives it words; and the disabled state is carried by\n * `aria-disabled` as well as by the appearance. It is also why the hex and the\n * saturation area are the parts of an unavailable picker that drain rather\n * than dim, while the hue track and presets keep a documented dim — their\n * fills are data colours no token can express. See the root's class list and\n * the comments on those parts.\n *\n * The event contract matches Slider and NumberField. `update:modelValue` is\n * transient — every position a thumb passes through — and `commit` fires once\n * per gesture, so one drag across the area is one undo entry rather than a\n * hundred.\n *\n * Inside a [Field](../Field/Field.vue) it wires itself through\n * `useFieldControl()`, and the row's answers land on two different nodes — see\n * the comment above `groupFieldAttrs`, which is where that split is decided.\n * **A row's label does not name the picker.** `<label for>` names a labelable\n * element and this renders a `div[role=\"group\"]`, so the row's label resolves\n * to it and announces nobody; `ariaLabel`/`ariaLabelledby` below are what name\n * the picker, exactly as they were before.\n *\n * There is no `readonly`, and a row's is ignored rather than approximated. A\n * colour that may be looked at but not changed is a swatch — the `ColorSwatch`\n * beside the hex value already is one — and none of the four parts has a\n * read-only state to put it in, so the honest options were a picker that looks\n * live and swallows every gesture, or none at all.\n */\nconst props = withDefaults(\n defineProps<{\n /** The chosen colour as `#rrggbb`. There is no alpha channel in this version. */\n modelValue?: string;\n /** Preset colours shown as a row of named swatches. Omit it and no row is rendered. */\n swatches?: string[];\n /** Unavailable: drains the picker's chrome, keeps the colour surfaces readable, and refuses the pointer, the keyboard and the field. Unset defers to a wrapping Field. */\n disabled?: boolean | undefined;\n /** The accessible name for the picker as a whole, when nothing visible already labels it. */\n ariaLabel?: string;\n /** The id of the visible element that labels the picker (a Field wrapper's label, say). */\n ariaLabelledby?: string;\n /**\n * Names for the parts, as any subset of `ColorPickerLabels` — the rest stay\n * as the host's `provideLoomLabels` vocabulary left them, and then as\n * Loom's English.\n *\n * `ariaLabel` above names the *picker*; this names what is inside it, and\n * six of its nine keys are the only thing standing between a reader and\n * Reka UI's own English.\n */\n labels?: LabelOverrides<ColorPickerLabels>;\n }>(),\n {\n // Not `false`: absent has to stay tellable from `false` for a Field above\n // to disable the row and for `:disabled=\"false\"` to overrule one that does.\n // Vue casts an absent Boolean prop with no declared default to `false`,\n // which would leave the context wired and inert.\n disabled: undefined,\n },\n);\n\nconst emit = defineEmits<{\n /** Transient: every colour a drag or an arrow step passes through. Not a checkpoint. */\n \"update:modelValue\": [value: string];\n /** Committed: once per gesture — drag release, arrow step, hex entry, preset click. */\n commit: [value: string];\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(\"colorPicker\", COLOR_PICKER_LABELS, () => props.labels);\n\n// The seed for an unset or unparseable model value. Reka's ColorArea, ColorField\n// and ColorSlider each fall back to this same string internally, so matching it\n// is what keeps the four parts agreeing about what \"no colour yet\" looks like\n// rather than each inventing its own. It is picked data, not a theme colour.\nconst FALLBACK = \"#000000\";\n\n// A colour a consumer supplied is parsed by Reka inside a render function, and\n// an unparseable one throws there — taking the host's page down, not just this\n// component. A library cannot do that with a prop, so every value entering\n// `current` is checked first. `isValidColor` is Reka's own parser rather than a\n// regex here, so what this accepts and what the parts accept cannot drift.\nfunction toColor(value: string | undefined): string {\n return value !== undefined && isValidColor(value) ? value : FALLBACK;\n}\n\n// The working colour, fed to all four parts. Seeded from the prop and advanced\n// on every tick, exactly as Slider's `lastValue` is: given a defined model value\n// Reka runs fully controlled, so a host that correctly withholds transient\n// values until commit would otherwise freeze the thumbs at the gesture's start.\nconst current = ref(toColor(props.modelValue));\n\n// The value the host last acknowledged. Every commit path compares against it,\n// which is what makes a gesture that ends where it started — a click that lands\n// on the thumb, an arrow at the edge of the area, the same hex retyped, the\n// already-selected preset clicked again — produce no checkpoint at all.\nconst lastCommitted = ref(current.value);\n\n// An incoming value equal to `current` is this component's own emit echoing\n// back through a `v-model`, and re-baselining on it would swallow the commit at\n// the end of the gesture that produced it. Anything else is the host moving the\n// colour itself, which is a new baseline by definition — which is why this\n// needs no \"is a gesture in flight?\" flag to tell the two apart.\nwatch(\n () => props.modelValue,\n (value) => {\n const next = toColor(value);\n if (next === current.value) return;\n current.value = next;\n lastCommitted.value = next;\n },\n);\n\n// Every one of Reka's parts writes a hex string back into its own model, but\n// each types its update as `string | Color` because that union is what it will\n// *accept* coming in. Narrowing it here rather than casting keeps the object\n// half real: a future part that emits one still resolves to hex instead of\n// stringifying to \"[object Object]\" and failing to parse two frames later.\nfunction applyFromPart(value: string | Color): void {\n apply(typeof value === \"string\" ? value : colorToString(value, \"hex\"));\n}\n\nfunction apply(next: string): void {\n const value = toColor(next);\n if (value === current.value) return;\n current.value = value;\n emit(\"update:modelValue\", value);\n}\n\n/**\n * The area thumb's `aria-valuetext`, which Reka would otherwise build from its\n * own English channel names — \"Saturation 60, Brightness 80\", said again on\n * every arrow key.\n *\n * The two numbers are recomputed here rather than read out of Reka, because\n * Reka exposes neither: `ColorAreaRoot` yields only `style` to its slot and\n * keeps `xValue`/`yValue` in a context this component cannot inject. What it\n * does export is the arithmetic — `getChannelValue` and `normalizeColor` are\n * the same two functions `ColorAreaRoot` calls, applied to the same `current`\n * this component hands it as `model-value`, with the same `Math.round`. So the\n * number here and the `aria-valuenow` beside it agree by construction rather\n * than by coincidence, which is what makes replacing this string safe: Reka\n * re-derives its own pair from the model on the next tick after any gesture,\n * to this identical formula.\n */\nconst areaValueText = computed(() => {\n const color = normalizeColor(current.value);\n return text.value.areaValue({\n saturation: Math.round(getChannelValue(color, \"saturation\")),\n brightness: Math.round(getChannelValue(color, \"brightness\")),\n });\n});\n\nfunction onFieldCommit(value: string | Color): void {\n applyFromPart(value);\n commitCurrent();\n}\n\nfunction commitCurrent(): void {\n if (current.value === lastCommitted.value) return;\n lastCommitted.value = current.value;\n emit(\"commit\", current.value);\n}\n\n// Reka commits the area on pointer release only — `ColorAreaArea` calls its\n// root's `commitValues` from `pointerup` and not from its own key handler — so\n// an arrow-stepped colour would never reach a host's undo stack. Deferring by a\n// tick is what makes this independent of whether Vue runs this listener before\n// or after Reka's on the same element: by then the step has been applied and\n// `current` holds it. `commitCurrent` swallows the no-op at the axis limits.\nconst AREA_STEP_KEYS = new Set([\n \"ArrowLeft\",\n \"ArrowRight\",\n \"ArrowUp\",\n \"ArrowDown\",\n \"PageUp\",\n \"PageDown\",\n \"Home\",\n \"End\",\n]);\n\nfunction onAreaKeydown(event: KeyboardEvent): void {\n if (field.disabled || !AREA_STEP_KEYS.has(event.key)) return;\n void nextTick(commitCurrent);\n}\n\n// A preset that will not parse is dropped rather than rendered: it would be an\n// invisible square that sets an unusable value, and an empty row would leave a\n// `role=\"listbox\"` with no options, which is an ARIA violation of its own. The\n// row is therefore rendered only when something survives this.\nconst presets = computed(() => (props.swatches ?? []).filter((swatch) => isValidColor(swatch)));\n\nfunction onPresetPick(value: unknown): void {\n if (typeof value !== \"string\") return;\n apply(value);\n commitCurrent();\n}\n\n// Unlike Slider and Select, `class` and the remaining fallthrough attributes go\n// to the same node. The picker has four interactive parts and no single one of\n// them is what an `aria-describedby` or a `data-testid` is about — the group\n// around them is. `class` still needs the `cn()` merge rather than Vue's plain\n// concatenation, so it is bound separately from the spread.\ndefineOptions({ inheritAttrs: false });\nconst { attrs, rest: groupAttrs } = useSplitAttrs();\n\n/**\n * Two of this control's four parts are Reka roots that the platform cannot\n * disable: the saturation area and the hue slider render `<span role=\"slider\"\n * tabindex=\"0\">`, and `<fieldset disabled>` reaches only `<input>`, `<button>`,\n * `<select>` and `<textarea>`. Measured in jsdom, both still took an arrow key\n * inside a disabled group and moved the colour — while the hex `<input>` beside\n * them went properly inert, so the picker was half unavailable and half not.\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// `id` and `aria-describedby` arrive as fallthrough attrs rather than props, so\n// they are handed in as this caller's own values: a caller who sets either\n// still beats the row, and the row's description is merged into theirs rather\n// than replacing it. `name`, `required` and `invalid` are absent because this\n// component has no prop for any of them — the row's answer stands unopposed.\nconst field = useFieldControl(() => ({\n id: attrs.id as string | undefined,\n describedBy: attrs[\"aria-describedby\"] as string | undefined,\n // The fieldset beats the prop in both directions, exactly as it does for the\n // hex input inside this very control.\n disabled: groupDisabled.value ? true : props.disabled,\n}));\n\n/**\n * The half of the resolved bag the group takes, and the reason there are two\n * halves at all.\n *\n * A row describes *the picker*, and no one of the four parts is the picker —\n * the colour is authored across all of them — so the group around them is what\n * carries the identity and the description, exactly as a `data-testid` does.\n *\n * `name` and `aria-required` cannot follow them there. ARIA allows neither on\n * `role=\"group\"`, and `aria-allowed-attr` is a WCAG 4.1.2 rule\n * `e2e/accessibility.e2e.ts` runs over every docs page, so shipping the whole\n * bag here would turn that gate red. They go to the hex field instead, which is\n * the picker's one real form control: a native `<input>` holding exactly the\n * `#rrggbb` this component emits, so — unlike NumberField's spinbutton, which\n * holds a *formatted* number and would post its grouping separators — a `name`\n * on it submits the model value itself. `aria-invalid` rides along with them,\n * because a state announced on entering a group is a state most readers meet\n * once, while the field is where an error about the value is actually read.\n */\nconst groupFieldAttrs = computed(() =>\n optional({ id: field.id, \"aria-describedby\": field.attrs[\"aria-describedby\"] }),\n);\n\n// Both thumbs sit on a surface whose colour is the value being chosen, so they\n// have to read against white, against black and against every hue in between. A\n// single-colour thumb cannot: the light ring vanishes on a pale fill and the\n// dark one vanishes on a dark fill. The pair — a `background` band inside a\n// `foreground` hairline — always leaves one of the two in contrast.\nconst THUMB =\n \"block size-6 rounded-full border-2 border-background bg-transparent ring-1 ring-foreground shadow-sm \" +\n \"transition-transform duration-fast ease-spring hover:scale-110 active:scale-95 \" +\n \"focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo \" +\n \"data-[disabled]:pointer-events-none\";\n</script>\n\n<template>\n <div\n ref=\"root\"\n v-bind=\"{ ...groupAttrs, ...groupFieldAttrs }\"\n role=\"group\"\n :aria-label=\"ariaLabel\"\n :aria-labelledby=\"ariaLabelledby\"\n :aria-disabled=\"field.disabled || undefined\"\n :data-disabled=\"field.disabled || undefined\"\n :class=\"\n cn(\n 'flex w-full max-w-xs flex-col gap-3',\n // No `opacity` on the group, and the split below is the whole reason.\n // A dim here ran over everything the picker holds, the hex among it:\n // measured on the built site, `opacity-50` put the hex value at 3.06:1\n // — the same 3.08:1 the text input's own dim produced before it was\n // drained, and the same failure axe does not raise because it exempts\n // a disabled control under 1.4.3.\n //\n // So the parts part ways. The saturation area drains to the neutral\n // well like every other unavailable control (its gradient is this\n // component's own inline binding, so unavailability can withhold it);\n // the hue track and the preset swatches keep a dim because their fills\n // are data colours no token can express; and the hex field takes the\n // drained fill, muted text and slackened rim every other control in\n // the library wears, because it is text and it is the one thing a\n // reader still needs from a picker they cannot use.\n field.disabled && 'cursor-not-allowed',\n attrs.class as string,\n )\n \"\n >\n <!-- Saturation across, brightness up. `style` is Reka's own gradient for\n those two axes at the current hue — the picked colour rendered as a\n surface, which is data and not a token. -->\n <ColorAreaRoot\n v-slot=\"{ style }\"\n :model-value=\"current\"\n color-space=\"hsb\"\n x-channel=\"saturation\"\n y-channel=\"brightness\"\n :disabled=\"field.disabled\"\n @update:model-value=\"applyFromPart\"\n @change-end=\"commitCurrent\"\n >\n <!-- Reka gives this `role=\"application\"`, which hands every key straight\n to the area rather than to the screen reader's own navigation. That\n only works if the region says what it is, so it is named here; the\n thumb inside carries the per-axis values.\n\n Both `aria-roledescription`s below replace one Reka writes in English\n inside its own render function. They reach the DOM as fallthrough\n attributes, which Vue merges last, so each is a replacement rather\n than a second phrase — and removing one falls back to Reka's English\n rather than to nothing, which is the failure no test of Loom's own\n strings would catch.\n\n `aria-valuetext` on the thumb is the third of them and the one a\n reader hears most, since it is re-announced on every arrow key.\n `areaValueText` explains why replacing it does not risk contradicting\n the `aria-valuenow` beside it. -->\n <!-- The gradient is Loom's own inline binding, so unavailability can\n take the surface back: with the picker disabled the gradient is\n withheld and the area falls to the neutral well, drained like every\n other unavailable control rather than faded through. -->\n <ColorAreaArea\n :style=\"field.disabled ? undefined : style\"\n :aria-label=\"text.area\"\n :aria-roledescription=\"text.areaRoleDescription\"\n class=\"relative h-40 w-full rounded-md border border-border bg-background data-[disabled]:bg-muted\"\n @keydown=\"onAreaKeydown\"\n >\n <ColorAreaThumb\n :aria-label=\"text.areaThumb\"\n :aria-roledescription=\"text.areaThumbRoleDescription\"\n :aria-valuetext=\"areaValueText\"\n :class=\"THUMB\"\n />\n </ColorAreaArea>\n </ColorAreaRoot>\n\n <ColorSliderRoot\n :model-value=\"current\"\n channel=\"hue\"\n color-space=\"hsb\"\n :disabled=\"field.disabled\"\n class=\"relative flex w-full touch-none items-center py-1\"\n @update:model-value=\"applyFromPart\"\n @change-end=\"commitCurrent\"\n >\n <!-- The one dim left on a *tokenless* surface, and it stays because it\n must: Reka paints the spectrum as an inline `style` inside its own\n component (verified against its source — the track's background\n never passes through a slot), and no class can outrank an inline\n style. The hue under the thumb is data, not chrome, so draining it\n to a token would be lying about what is there. -->\n <ColorSliderTrack\n class=\"relative h-3 w-full grow rounded-full border border-border data-[disabled]:opacity-50\"\n />\n <!-- Reka names this from its channel — \"Hue\" — so the binding replaces\n that rather than adding to it. -->\n <ColorSliderThumb :aria-label=\"text.hue\" :class=\"THUMB\" />\n </ColorSliderRoot>\n\n <!-- The hex is the picker's text channel, so it is always on screen and it\n is the edit surface too. Typing writes the model on blur and on Enter\n rather than per keystroke, so a half-typed value is never emitted and\n text that will not parse is reverted to the current colour; the arrow\n keys nudge it a step at a time. Both paths arrive here already at a\n boundary, which is why the field's update is itself the checkpoint. -->\n <ColorFieldRoot\n :model-value=\"current\"\n :disabled=\"field.disabled\"\n class=\"flex h-9 items-center gap-2 rounded-md border border-input bg-background px-3 text-sm text-foreground transition-[color,background-color,border-color,box-shadow] duration-fast ease-out focus-within:outline-2 focus-within:outline-offset-2 focus-within:outline-ring focus-within:shadow-halo data-[disabled]:cursor-not-allowed data-[disabled]:border-border data-[disabled]:bg-muted data-[disabled]:text-muted-foreground\"\n @update:model-value=\"onFieldCommit\"\n >\n <!-- `label` is Reka's own documented prop for this, so it is set rather\n than bound over: left unset the swatch names itself through a\n `getColorName` that answers \"vibrant red\" in English and is not\n exported for Loom to delegate to. The roledescription is a\n fallthrough replacement, as on the area above. -->\n <ColorSwatch\n :color=\"current\"\n :label=\"text.swatch({ color: current })\"\n :aria-roledescription=\"text.swatchRoleDescription\"\n :style=\"{ backgroundColor: current }\"\n class=\"size-6 shrink-0 rounded-sm border border-border\"\n />\n <!-- The row's three form-control answers, which the group cannot hold —\n see `groupFieldAttrs`. `aria-label` stays: it names the *field*, not\n the picker, and a row's label never reached this element anyway. -->\n <ColorFieldInput\n :aria-label=\"text.hex\"\n :name=\"field.name\"\n :aria-required=\"field.required || undefined\"\n :aria-invalid=\"field.invalid || undefined\"\n class=\"tabular min-w-0 flex-1 self-stretch bg-transparent outline-none disabled:cursor-not-allowed\"\n />\n </ColorFieldRoot>\n\n <!-- One tab stop, not one per swatch: Reka's swatch picker is a listbox\n with roving focus, so arrows move between presets and Enter or Space\n chooses. `replace` rather than Reka's default `toggle`: a row of\n presets is a choice, not a set of switches, so clicking the one\n already showing must re-affirm the colour rather than clear it to\n nothing. `onPresetPick`'s string check holds the same line from the\n other side, for the empty selection `toggle` would emit. -->\n <ColorSwatchPickerRoot\n v-if=\"presets.length > 0\"\n :model-value=\"current\"\n :disabled=\"field.disabled\"\n :aria-disabled=\"field.disabled || undefined\"\n selection-behavior=\"replace\"\n :aria-label=\"text.presets\"\n class=\"flex flex-wrap gap-2 data-[disabled]:opacity-50\"\n @update:model-value=\"onPresetPick\"\n >\n <!-- Each item names itself from Reka's English `getColorName` unless\n this binding replaces it, so a row of presets is where that\n vocabulary leaks in bulk. -->\n <!-- Each swatch's fill is a preset the host supplied, bound inline right\n here — data colours no token can express (the same constraint as\n the hue track above). Withholding the fill when unavailable would\n blank the palette instead of draining chrome around it, so the row\n keeps the dim: the one honest treatment for content that *is*\n colour. -->\n <ColorSwatchPickerItem\n v-for=\"preset in presets\"\n :key=\"preset\"\n :value=\"preset\"\n :disabled=\"field.disabled\"\n :aria-label=\"text.swatch({ color: preset })\"\n :style=\"{ backgroundColor: preset }\"\n class=\"size-6 cursor-pointer rounded-sm border border-border transition-transform duration-fast ease-spring hover:scale-110 active:scale-95 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo aria-selected:ring-2 aria-selected:ring-primary aria-selected:ring-offset-2 aria-selected:ring-offset-background data-[disabled]:pointer-events-none\"\n />\n </ColorSwatchPickerRoot>\n </div>\n</template>\n"],"mappings":""}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type LabelOverrides } from "
|
|
2
|
-
import type { ColorPickerLabels } from "
|
|
1
|
+
import { type LabelOverrides } from "../../../labels/src/index";
|
|
2
|
+
import type { ColorPickerLabels } from "../../../labels/src/index";
|
|
3
3
|
/**
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -14,7 +14,7 @@ declare const __VLS_export: import("vue").DefineComponent<{
|
|
|
14
14
|
modelValue?: string;
|
|
15
15
|
/** Preset colours shown as a row of named swatches. Omit it and no row is rendered. */
|
|
16
16
|
swatches?: string[];
|
|
17
|
-
/** Unavailable:
|
|
17
|
+
/** Unavailable: drains the picker's chrome, keeps the colour surfaces readable, and refuses the pointer, the keyboard and the field. Unset defers to a wrapping Field. */
|
|
18
18
|
disabled?: boolean | undefined;
|
|
19
19
|
/** The accessible name for the picker as a whole, when nothing visible already labels it. */
|
|
20
20
|
ariaLabel?: string;
|
|
@@ -38,7 +38,7 @@ declare const __VLS_export: import("vue").DefineComponent<{
|
|
|
38
38
|
modelValue?: string;
|
|
39
39
|
/** Preset colours shown as a row of named swatches. Omit it and no row is rendered. */
|
|
40
40
|
swatches?: string[];
|
|
41
|
-
/** Unavailable:
|
|
41
|
+
/** Unavailable: drains the picker's chrome, keeps the colour surfaces readable, and refuses the pointer, the keyboard and the field. Unset defers to a wrapping Field. */
|
|
42
42
|
disabled?: boolean | undefined;
|
|
43
43
|
/** The accessible name for the picker as a whole, when nothing visible already labels it. */
|
|
44
44
|
ariaLabel?: string;
|
package/dist/packages/primitives/color-picker/src/ColorPicker.vue_vue_type_script_setup_true_lang.js
CHANGED
|
@@ -193,10 +193,10 @@ var ColorPicker_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defi
|
|
|
193
193
|
onChangeEnd: commitCurrent
|
|
194
194
|
}, {
|
|
195
195
|
default: withCtx(({ style }) => [createVNode(unref(ColorAreaArea), {
|
|
196
|
-
style: normalizeStyle(style),
|
|
196
|
+
style: normalizeStyle(unref(field).disabled ? void 0 : style),
|
|
197
197
|
"aria-label": unref(text).area,
|
|
198
198
|
"aria-roledescription": unref(text).areaRoleDescription,
|
|
199
|
-
class: "relative h-40 w-full rounded-md border border-border data-[disabled]:
|
|
199
|
+
class: "relative h-40 w-full rounded-md border border-border bg-background data-[disabled]:bg-muted",
|
|
200
200
|
onKeydown: onAreaKeydown
|
|
201
201
|
}, {
|
|
202
202
|
default: withCtx(() => [createVNode(unref(ColorAreaThumb), {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ColorPicker.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../../../packages/primitives/color-picker/src/ColorPicker.vue"],"sourcesContent":["<script lang=\"ts\">\nimport type { ColorPickerLabels } from \"@ecoma-io/loom-labels\";\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 COLOR_PICKER_LABELS: ColorPickerLabels = {\n area: \"Saturation and brightness\",\n areaRoleDescription: \"Colour picker\",\n areaThumb: \"Saturation and brightness\",\n areaThumbRoleDescription: \"Colour thumb\",\n // Differs from Reka's own \"Saturation 60, Brightness 80\" by the one capital,\n // which is the same trick the rest of the library uses to let a test assert\n // whose string reached the DOM rather than merely what it said.\n areaValue: ({ saturation, brightness }) =>\n `Saturation ${String(saturation)}, brightness ${String(brightness)}`,\n hue: \"Hue\",\n hex: \"Hex value\",\n presets: \"Presets\",\n swatch: ({ color }) => color,\n swatchRoleDescription: \"Colour swatch\",\n};\n</script>\n\n<script setup lang=\"ts\">\nimport { computed, nextTick, ref, useTemplateRef, watch } from \"vue\";\nimport {\n ColorAreaRoot,\n ColorAreaArea,\n ColorAreaThumb,\n ColorSliderRoot,\n ColorSliderTrack,\n ColorSliderThumb,\n ColorFieldRoot,\n ColorFieldInput,\n ColorSwatch,\n ColorSwatchPickerRoot,\n ColorSwatchPickerItem,\n colorToString,\n getChannelValue,\n isValidColor,\n normalizeColor,\n type Color,\n} from \"reka-ui\";\nimport { cn } from \"@ecoma-io/loom-core\";\nimport { optional } 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 * ColorPicker — choose one colour, as `#rrggbb`. A saturation/brightness\n * area, a hue slider, an editable hex field, and an optional row of presets.\n * Reach for it when the colour itself is the value being authored: a label\n * colour, a chart series, a theme override.\n *\n * When the choice is actually a small closed set — a status colour, a brand\n * palette — a Select or a RadioGroup names the options and this does not.\n * A picker offers sixteen million answers, which is the wrong control for a\n * question with six.\n *\n * Built on Reka UI's colour parts, which supply the whole semantic layer:\n * `role=\"slider\"` on both thumbs, the area's two-axis arrow stepping, the\n * listbox roving focus over the presets, and the parsing that turns typed text\n * into a colour. Every part models its value as a colour string and emits hex,\n * which is what lets this expose one plain `#rrggbb` rather than a channel\n * object.\n *\n * **Where the \"no raw colour values\" rule falls here.** The colour a person is\n * picking is *data*: the area's gradient, the hue track and every swatch fill\n * are bound from the model value at run time, and a token could not express\n * them. Everything that is *chrome* — the borders, the focus ring, the field,\n * the labels, the disabled state, the rings that keep the thumbs visible —\n * comes from `theme.css` and nothing else. A literal colour in this file is a\n * defect unless it is a value being picked.\n *\n * **The hex is the non-colour channel.** A control that communicates only in\n * colour is unusable by the readers most likely to need help choosing one, so\n * the hex value is always on screen as text and is itself the edit surface;\n * every swatch is named rather than left a bare square — by its hex unless\n * `labels.swatch` gives it words; and the disabled state is carried by\n * `aria-disabled` as well as by the appearance. It is also why the hex is the\n * one part of an unavailable picker that is drained rather than dimmed — see\n * the root's class list.\n *\n * The event contract matches Slider and NumberField. `update:modelValue` is\n * transient — every position a thumb passes through — and `commit` fires once\n * per gesture, so one drag across the area is one undo entry rather than a\n * hundred.\n *\n * Inside a [Field](../Field/Field.vue) it wires itself through\n * `useFieldControl()`, and the row's answers land on two different nodes — see\n * the comment above `groupFieldAttrs`, which is where that split is decided.\n * **A row's label does not name the picker.** `<label for>` names a labelable\n * element and this renders a `div[role=\"group\"]`, so the row's label resolves\n * to it and announces nobody; `ariaLabel`/`ariaLabelledby` below are what name\n * the picker, exactly as they were before.\n *\n * There is no `readonly`, and a row's is ignored rather than approximated. A\n * colour that may be looked at but not changed is a swatch — the `ColorSwatch`\n * beside the hex value already is one — and none of the four parts has a\n * read-only state to put it in, so the honest options were a picker that looks\n * live and swallows every gesture, or none at all.\n */\nconst props = withDefaults(\n defineProps<{\n /** The chosen colour as `#rrggbb`. There is no alpha channel in this version. */\n modelValue?: string;\n /** Preset colours shown as a row of named swatches. Omit it and no row is rendered. */\n swatches?: string[];\n /** Unavailable: dims the picker and refuses the pointer, the keyboard and the field. Unset defers to a wrapping Field. */\n disabled?: boolean | undefined;\n /** The accessible name for the picker as a whole, when nothing visible already labels it. */\n ariaLabel?: string;\n /** The id of the visible element that labels the picker (a Field wrapper's label, say). */\n ariaLabelledby?: string;\n /**\n * Names for the parts, as any subset of `ColorPickerLabels` — the rest stay\n * as the host's `provideLoomLabels` vocabulary left them, and then as\n * Loom's English.\n *\n * `ariaLabel` above names the *picker*; this names what is inside it, and\n * six of its nine keys are the only thing standing between a reader and\n * Reka UI's own English.\n */\n labels?: LabelOverrides<ColorPickerLabels>;\n }>(),\n {\n // Not `false`: absent has to stay tellable from `false` for a Field above\n // to disable the row and for `:disabled=\"false\"` to overrule one that does.\n // Vue casts an absent Boolean prop with no declared default to `false`,\n // which would leave the context wired and inert.\n disabled: undefined,\n },\n);\n\nconst emit = defineEmits<{\n /** Transient: every colour a drag or an arrow step passes through. Not a checkpoint. */\n \"update:modelValue\": [value: string];\n /** Committed: once per gesture — drag release, arrow step, hex entry, preset click. */\n commit: [value: string];\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(\"colorPicker\", COLOR_PICKER_LABELS, () => props.labels);\n\n// The seed for an unset or unparseable model value. Reka's ColorArea, ColorField\n// and ColorSlider each fall back to this same string internally, so matching it\n// is what keeps the four parts agreeing about what \"no colour yet\" looks like\n// rather than each inventing its own. It is picked data, not a theme colour.\nconst FALLBACK = \"#000000\";\n\n// A colour a consumer supplied is parsed by Reka inside a render function, and\n// an unparseable one throws there — taking the host's page down, not just this\n// component. A library cannot do that with a prop, so every value entering\n// `current` is checked first. `isValidColor` is Reka's own parser rather than a\n// regex here, so what this accepts and what the parts accept cannot drift.\nfunction toColor(value: string | undefined): string {\n return value !== undefined && isValidColor(value) ? value : FALLBACK;\n}\n\n// The working colour, fed to all four parts. Seeded from the prop and advanced\n// on every tick, exactly as Slider's `lastValue` is: given a defined model value\n// Reka runs fully controlled, so a host that correctly withholds transient\n// values until commit would otherwise freeze the thumbs at the gesture's start.\nconst current = ref(toColor(props.modelValue));\n\n// The value the host last acknowledged. Every commit path compares against it,\n// which is what makes a gesture that ends where it started — a click that lands\n// on the thumb, an arrow at the edge of the area, the same hex retyped, the\n// already-selected preset clicked again — produce no checkpoint at all.\nconst lastCommitted = ref(current.value);\n\n// An incoming value equal to `current` is this component's own emit echoing\n// back through a `v-model`, and re-baselining on it would swallow the commit at\n// the end of the gesture that produced it. Anything else is the host moving the\n// colour itself, which is a new baseline by definition — which is why this\n// needs no \"is a gesture in flight?\" flag to tell the two apart.\nwatch(\n () => props.modelValue,\n (value) => {\n const next = toColor(value);\n if (next === current.value) return;\n current.value = next;\n lastCommitted.value = next;\n },\n);\n\n// Every one of Reka's parts writes a hex string back into its own model, but\n// each types its update as `string | Color` because that union is what it will\n// *accept* coming in. Narrowing it here rather than casting keeps the object\n// half real: a future part that emits one still resolves to hex instead of\n// stringifying to \"[object Object]\" and failing to parse two frames later.\nfunction applyFromPart(value: string | Color): void {\n apply(typeof value === \"string\" ? value : colorToString(value, \"hex\"));\n}\n\nfunction apply(next: string): void {\n const value = toColor(next);\n if (value === current.value) return;\n current.value = value;\n emit(\"update:modelValue\", value);\n}\n\n/**\n * The area thumb's `aria-valuetext`, which Reka would otherwise build from its\n * own English channel names — \"Saturation 60, Brightness 80\", said again on\n * every arrow key.\n *\n * The two numbers are recomputed here rather than read out of Reka, because\n * Reka exposes neither: `ColorAreaRoot` yields only `style` to its slot and\n * keeps `xValue`/`yValue` in a context this component cannot inject. What it\n * does export is the arithmetic — `getChannelValue` and `normalizeColor` are\n * the same two functions `ColorAreaRoot` calls, applied to the same `current`\n * this component hands it as `model-value`, with the same `Math.round`. So the\n * number here and the `aria-valuenow` beside it agree by construction rather\n * than by coincidence, which is what makes replacing this string safe: Reka\n * re-derives its own pair from the model on the next tick after any gesture,\n * to this identical formula.\n */\nconst areaValueText = computed(() => {\n const color = normalizeColor(current.value);\n return text.value.areaValue({\n saturation: Math.round(getChannelValue(color, \"saturation\")),\n brightness: Math.round(getChannelValue(color, \"brightness\")),\n });\n});\n\nfunction onFieldCommit(value: string | Color): void {\n applyFromPart(value);\n commitCurrent();\n}\n\nfunction commitCurrent(): void {\n if (current.value === lastCommitted.value) return;\n lastCommitted.value = current.value;\n emit(\"commit\", current.value);\n}\n\n// Reka commits the area on pointer release only — `ColorAreaArea` calls its\n// root's `commitValues` from `pointerup` and not from its own key handler — so\n// an arrow-stepped colour would never reach a host's undo stack. Deferring by a\n// tick is what makes this independent of whether Vue runs this listener before\n// or after Reka's on the same element: by then the step has been applied and\n// `current` holds it. `commitCurrent` swallows the no-op at the axis limits.\nconst AREA_STEP_KEYS = new Set([\n \"ArrowLeft\",\n \"ArrowRight\",\n \"ArrowUp\",\n \"ArrowDown\",\n \"PageUp\",\n \"PageDown\",\n \"Home\",\n \"End\",\n]);\n\nfunction onAreaKeydown(event: KeyboardEvent): void {\n if (field.disabled || !AREA_STEP_KEYS.has(event.key)) return;\n void nextTick(commitCurrent);\n}\n\n// A preset that will not parse is dropped rather than rendered: it would be an\n// invisible square that sets an unusable value, and an empty row would leave a\n// `role=\"listbox\"` with no options, which is an ARIA violation of its own. The\n// row is therefore rendered only when something survives this.\nconst presets = computed(() => (props.swatches ?? []).filter((swatch) => isValidColor(swatch)));\n\nfunction onPresetPick(value: unknown): void {\n if (typeof value !== \"string\") return;\n apply(value);\n commitCurrent();\n}\n\n// Unlike Slider and Select, `class` and the remaining fallthrough attributes go\n// to the same node. The picker has four interactive parts and no single one of\n// them is what an `aria-describedby` or a `data-testid` is about — the group\n// around them is. `class` still needs the `cn()` merge rather than Vue's plain\n// concatenation, so it is bound separately from the spread.\ndefineOptions({ inheritAttrs: false });\nconst { attrs, rest: groupAttrs } = useSplitAttrs();\n\n/**\n * Two of this control's four parts are Reka roots that the platform cannot\n * disable: the saturation area and the hue slider render `<span role=\"slider\"\n * tabindex=\"0\">`, and `<fieldset disabled>` reaches only `<input>`, `<button>`,\n * `<select>` and `<textarea>`. Measured in jsdom, both still took an arrow key\n * inside a disabled group and moved the colour — while the hex `<input>` beside\n * them went properly inert, so the picker was half unavailable and half not.\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// `id` and `aria-describedby` arrive as fallthrough attrs rather than props, so\n// they are handed in as this caller's own values: a caller who sets either\n// still beats the row, and the row's description is merged into theirs rather\n// than replacing it. `name`, `required` and `invalid` are absent because this\n// component has no prop for any of them — the row's answer stands unopposed.\nconst field = useFieldControl(() => ({\n id: attrs.id as string | undefined,\n describedBy: attrs[\"aria-describedby\"] as string | undefined,\n // The fieldset beats the prop in both directions, exactly as it does for the\n // hex input inside this very control.\n disabled: groupDisabled.value ? true : props.disabled,\n}));\n\n/**\n * The half of the resolved bag the group takes, and the reason there are two\n * halves at all.\n *\n * A row describes *the picker*, and no one of the four parts is the picker —\n * the colour is authored across all of them — so the group around them is what\n * carries the identity and the description, exactly as a `data-testid` does.\n *\n * `name` and `aria-required` cannot follow them there. ARIA allows neither on\n * `role=\"group\"`, and `aria-allowed-attr` is a WCAG 4.1.2 rule\n * `e2e/accessibility.e2e.ts` runs over every docs page, so shipping the whole\n * bag here would turn that gate red. They go to the hex field instead, which is\n * the picker's one real form control: a native `<input>` holding exactly the\n * `#rrggbb` this component emits, so — unlike NumberField's spinbutton, which\n * holds a *formatted* number and would post its grouping separators — a `name`\n * on it submits the model value itself. `aria-invalid` rides along with them,\n * because a state announced on entering a group is a state most readers meet\n * once, while the field is where an error about the value is actually read.\n */\nconst groupFieldAttrs = computed(() =>\n optional({ id: field.id, \"aria-describedby\": field.attrs[\"aria-describedby\"] }),\n);\n\n// Both thumbs sit on a surface whose colour is the value being chosen, so they\n// have to read against white, against black and against every hue in between. A\n// single-colour thumb cannot: the light ring vanishes on a pale fill and the\n// dark one vanishes on a dark fill. The pair — a `background` band inside a\n// `foreground` hairline — always leaves one of the two in contrast.\nconst THUMB =\n \"block size-6 rounded-full border-2 border-background bg-transparent ring-1 ring-foreground shadow-sm \" +\n \"transition-transform duration-fast ease-spring hover:scale-110 active:scale-95 \" +\n \"focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo \" +\n \"data-[disabled]:pointer-events-none\";\n</script>\n\n<template>\n <div\n ref=\"root\"\n v-bind=\"{ ...groupAttrs, ...groupFieldAttrs }\"\n role=\"group\"\n :aria-label=\"ariaLabel\"\n :aria-labelledby=\"ariaLabelledby\"\n :aria-disabled=\"field.disabled || undefined\"\n :data-disabled=\"field.disabled || undefined\"\n :class=\"\n cn(\n 'flex w-full max-w-xs flex-col gap-3',\n // No `opacity` on the group, and the split below is the whole reason.\n // A dim here ran over everything the picker holds, the hex among it:\n // measured on the built site, `opacity-50` put the hex value at 3.06:1\n // — the same 3.08:1 the text input's own dim produced before it was\n // drained, and the same failure axe does not raise because it exempts\n // a disabled control under 1.4.3.\n //\n // So the two halves part. The three surfaces whose whole content is\n // the colour being picked keep the dim, because that is what\n // unavailable looks like for a surface a token cannot drain; the hex\n // field takes the same drained fill, muted text and slackened rim\n // every other control in the library wears, because it is text and it\n // is the one thing a reader still needs from a picker they cannot use.\n field.disabled && 'cursor-not-allowed',\n attrs.class as string,\n )\n \"\n >\n <!-- Saturation across, brightness up. `style` is Reka's own gradient for\n those two axes at the current hue — the picked colour rendered as a\n surface, which is data and not a token. -->\n <ColorAreaRoot\n v-slot=\"{ style }\"\n :model-value=\"current\"\n color-space=\"hsb\"\n x-channel=\"saturation\"\n y-channel=\"brightness\"\n :disabled=\"field.disabled\"\n @update:model-value=\"applyFromPart\"\n @change-end=\"commitCurrent\"\n >\n <!-- Reka gives this `role=\"application\"`, which hands every key straight\n to the area rather than to the screen reader's own navigation. That\n only works if the region says what it is, so it is named here; the\n thumb inside carries the per-axis values.\n\n Both `aria-roledescription`s below replace one Reka writes in English\n inside its own render function. They reach the DOM as fallthrough\n attributes, which Vue merges last, so each is a replacement rather\n than a second phrase — and removing one falls back to Reka's English\n rather than to nothing, which is the failure no test of Loom's own\n strings would catch.\n\n `aria-valuetext` on the thumb is the third of them and the one a\n reader hears most, since it is re-announced on every arrow key.\n `areaValueText` explains why replacing it does not risk contradicting\n the `aria-valuenow` beside it. -->\n <ColorAreaArea\n :style=\"style\"\n :aria-label=\"text.area\"\n :aria-roledescription=\"text.areaRoleDescription\"\n class=\"relative h-40 w-full rounded-md border border-border data-[disabled]:opacity-50\"\n @keydown=\"onAreaKeydown\"\n >\n <ColorAreaThumb\n :aria-label=\"text.areaThumb\"\n :aria-roledescription=\"text.areaThumbRoleDescription\"\n :aria-valuetext=\"areaValueText\"\n :class=\"THUMB\"\n />\n </ColorAreaArea>\n </ColorAreaRoot>\n\n <ColorSliderRoot\n :model-value=\"current\"\n channel=\"hue\"\n color-space=\"hsb\"\n :disabled=\"field.disabled\"\n class=\"relative flex w-full touch-none items-center py-1\"\n @update:model-value=\"applyFromPart\"\n @change-end=\"commitCurrent\"\n >\n <ColorSliderTrack\n class=\"relative h-3 w-full grow rounded-full border border-border data-[disabled]:opacity-50\"\n />\n <!-- Reka names this from its channel — \"Hue\" — so the binding replaces\n that rather than adding to it. -->\n <ColorSliderThumb :aria-label=\"text.hue\" :class=\"THUMB\" />\n </ColorSliderRoot>\n\n <!-- The hex is the picker's text channel, so it is always on screen and it\n is the edit surface too. Typing writes the model on blur and on Enter\n rather than per keystroke, so a half-typed value is never emitted and\n text that will not parse is reverted to the current colour; the arrow\n keys nudge it a step at a time. Both paths arrive here already at a\n boundary, which is why the field's update is itself the checkpoint. -->\n <ColorFieldRoot\n :model-value=\"current\"\n :disabled=\"field.disabled\"\n class=\"flex h-9 items-center gap-2 rounded-md border border-input bg-background px-3 text-sm text-foreground transition-[color,background-color,border-color,box-shadow] duration-fast ease-out focus-within:outline-2 focus-within:outline-offset-2 focus-within:outline-ring focus-within:shadow-halo data-[disabled]:cursor-not-allowed data-[disabled]:border-border data-[disabled]:bg-muted data-[disabled]:text-muted-foreground\"\n @update:model-value=\"onFieldCommit\"\n >\n <!-- `label` is Reka's own documented prop for this, so it is set rather\n than bound over: left unset the swatch names itself through a\n `getColorName` that answers \"vibrant red\" in English and is not\n exported for Loom to delegate to. The roledescription is a\n fallthrough replacement, as on the area above. -->\n <ColorSwatch\n :color=\"current\"\n :label=\"text.swatch({ color: current })\"\n :aria-roledescription=\"text.swatchRoleDescription\"\n :style=\"{ backgroundColor: current }\"\n class=\"size-6 shrink-0 rounded-sm border border-border\"\n />\n <!-- The row's three form-control answers, which the group cannot hold —\n see `groupFieldAttrs`. `aria-label` stays: it names the *field*, not\n the picker, and a row's label never reached this element anyway. -->\n <ColorFieldInput\n :aria-label=\"text.hex\"\n :name=\"field.name\"\n :aria-required=\"field.required || undefined\"\n :aria-invalid=\"field.invalid || undefined\"\n class=\"tabular min-w-0 flex-1 self-stretch bg-transparent outline-none disabled:cursor-not-allowed\"\n />\n </ColorFieldRoot>\n\n <!-- One tab stop, not one per swatch: Reka's swatch picker is a listbox\n with roving focus, so arrows move between presets and Enter or Space\n chooses. `replace` rather than Reka's default `toggle`: a row of\n presets is a choice, not a set of switches, so clicking the one\n already showing must re-affirm the colour rather than clear it to\n nothing. `onPresetPick`'s string check holds the same line from the\n other side, for the empty selection `toggle` would emit. -->\n <ColorSwatchPickerRoot\n v-if=\"presets.length > 0\"\n :model-value=\"current\"\n :disabled=\"field.disabled\"\n :aria-disabled=\"field.disabled || undefined\"\n selection-behavior=\"replace\"\n :aria-label=\"text.presets\"\n class=\"flex flex-wrap gap-2 data-[disabled]:opacity-50\"\n @update:model-value=\"onPresetPick\"\n >\n <!-- Each item names itself from Reka's English `getColorName` unless this\n binding replaces it, so a row of presets is where that vocabulary\n leaks in bulk. -->\n <ColorSwatchPickerItem\n v-for=\"preset in presets\"\n :key=\"preset\"\n :value=\"preset\"\n :disabled=\"field.disabled\"\n :aria-label=\"text.swatch({ color: preset })\"\n :style=\"{ backgroundColor: preset }\"\n class=\"size-6 cursor-pointer rounded-sm border border-border transition-transform duration-fast ease-spring hover:scale-110 active:scale-95 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo aria-selected:ring-2 aria-selected:ring-primary aria-selected:ring-offset-2 aria-selected:ring-offset-background data-[disabled]:pointer-events-none\"\n />\n </ColorSwatchPickerRoot>\n </div>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ColorPicker.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../../../packages/primitives/color-picker/src/ColorPicker.vue"],"sourcesContent":["<script lang=\"ts\">\nimport type { ColorPickerLabels } from \"@ecoma-io/loom-labels\";\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 COLOR_PICKER_LABELS: ColorPickerLabels = {\n area: \"Saturation and brightness\",\n areaRoleDescription: \"Colour picker\",\n areaThumb: \"Saturation and brightness\",\n areaThumbRoleDescription: \"Colour thumb\",\n // Differs from Reka's own \"Saturation 60, Brightness 80\" by the one capital,\n // which is the same trick the rest of the library uses to let a test assert\n // whose string reached the DOM rather than merely what it said.\n areaValue: ({ saturation, brightness }) =>\n `Saturation ${String(saturation)}, brightness ${String(brightness)}`,\n hue: \"Hue\",\n hex: \"Hex value\",\n presets: \"Presets\",\n swatch: ({ color }) => color,\n swatchRoleDescription: \"Colour swatch\",\n};\n</script>\n\n<script setup lang=\"ts\">\nimport { computed, nextTick, ref, useTemplateRef, watch } from \"vue\";\nimport {\n ColorAreaRoot,\n ColorAreaArea,\n ColorAreaThumb,\n ColorSliderRoot,\n ColorSliderTrack,\n ColorSliderThumb,\n ColorFieldRoot,\n ColorFieldInput,\n ColorSwatch,\n ColorSwatchPickerRoot,\n ColorSwatchPickerItem,\n colorToString,\n getChannelValue,\n isValidColor,\n normalizeColor,\n type Color,\n} from \"reka-ui\";\nimport { cn } from \"@ecoma-io/loom-core\";\nimport { optional } 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 * ColorPicker — choose one colour, as `#rrggbb`. A saturation/brightness\n * area, a hue slider, an editable hex field, and an optional row of presets.\n * Reach for it when the colour itself is the value being authored: a label\n * colour, a chart series, a theme override.\n *\n * When the choice is actually a small closed set — a status colour, a brand\n * palette — a Select or a RadioGroup names the options and this does not.\n * A picker offers sixteen million answers, which is the wrong control for a\n * question with six.\n *\n * Built on Reka UI's colour parts, which supply the whole semantic layer:\n * `role=\"slider\"` on both thumbs, the area's two-axis arrow stepping, the\n * listbox roving focus over the presets, and the parsing that turns typed text\n * into a colour. Every part models its value as a colour string and emits hex,\n * which is what lets this expose one plain `#rrggbb` rather than a channel\n * object.\n *\n * **Where the \"no raw colour values\" rule falls here.** The colour a person is\n * picking is *data*: the area's gradient, the hue track and every swatch fill\n * are bound from the model value at run time, and a token could not express\n * them. Everything that is *chrome* — the borders, the focus ring, the field,\n * the labels, the disabled state, the rings that keep the thumbs visible —\n * comes from `theme.css` and nothing else. A literal colour in this file is a\n * defect unless it is a value being picked.\n *\n * **The hex is the non-colour channel.** A control that communicates only in\n * colour is unusable by the readers most likely to need help choosing one, so\n * the hex value is always on screen as text and is itself the edit surface;\n * every swatch is named rather than left a bare square — by its hex unless\n * `labels.swatch` gives it words; and the disabled state is carried by\n * `aria-disabled` as well as by the appearance. It is also why the hex and the\n * saturation area are the parts of an unavailable picker that drain rather\n * than dim, while the hue track and presets keep a documented dim — their\n * fills are data colours no token can express. See the root's class list and\n * the comments on those parts.\n *\n * The event contract matches Slider and NumberField. `update:modelValue` is\n * transient — every position a thumb passes through — and `commit` fires once\n * per gesture, so one drag across the area is one undo entry rather than a\n * hundred.\n *\n * Inside a [Field](../Field/Field.vue) it wires itself through\n * `useFieldControl()`, and the row's answers land on two different nodes — see\n * the comment above `groupFieldAttrs`, which is where that split is decided.\n * **A row's label does not name the picker.** `<label for>` names a labelable\n * element and this renders a `div[role=\"group\"]`, so the row's label resolves\n * to it and announces nobody; `ariaLabel`/`ariaLabelledby` below are what name\n * the picker, exactly as they were before.\n *\n * There is no `readonly`, and a row's is ignored rather than approximated. A\n * colour that may be looked at but not changed is a swatch — the `ColorSwatch`\n * beside the hex value already is one — and none of the four parts has a\n * read-only state to put it in, so the honest options were a picker that looks\n * live and swallows every gesture, or none at all.\n */\nconst props = withDefaults(\n defineProps<{\n /** The chosen colour as `#rrggbb`. There is no alpha channel in this version. */\n modelValue?: string;\n /** Preset colours shown as a row of named swatches. Omit it and no row is rendered. */\n swatches?: string[];\n /** Unavailable: drains the picker's chrome, keeps the colour surfaces readable, and refuses the pointer, the keyboard and the field. Unset defers to a wrapping Field. */\n disabled?: boolean | undefined;\n /** The accessible name for the picker as a whole, when nothing visible already labels it. */\n ariaLabel?: string;\n /** The id of the visible element that labels the picker (a Field wrapper's label, say). */\n ariaLabelledby?: string;\n /**\n * Names for the parts, as any subset of `ColorPickerLabels` — the rest stay\n * as the host's `provideLoomLabels` vocabulary left them, and then as\n * Loom's English.\n *\n * `ariaLabel` above names the *picker*; this names what is inside it, and\n * six of its nine keys are the only thing standing between a reader and\n * Reka UI's own English.\n */\n labels?: LabelOverrides<ColorPickerLabels>;\n }>(),\n {\n // Not `false`: absent has to stay tellable from `false` for a Field above\n // to disable the row and for `:disabled=\"false\"` to overrule one that does.\n // Vue casts an absent Boolean prop with no declared default to `false`,\n // which would leave the context wired and inert.\n disabled: undefined,\n },\n);\n\nconst emit = defineEmits<{\n /** Transient: every colour a drag or an arrow step passes through. Not a checkpoint. */\n \"update:modelValue\": [value: string];\n /** Committed: once per gesture — drag release, arrow step, hex entry, preset click. */\n commit: [value: string];\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(\"colorPicker\", COLOR_PICKER_LABELS, () => props.labels);\n\n// The seed for an unset or unparseable model value. Reka's ColorArea, ColorField\n// and ColorSlider each fall back to this same string internally, so matching it\n// is what keeps the four parts agreeing about what \"no colour yet\" looks like\n// rather than each inventing its own. It is picked data, not a theme colour.\nconst FALLBACK = \"#000000\";\n\n// A colour a consumer supplied is parsed by Reka inside a render function, and\n// an unparseable one throws there — taking the host's page down, not just this\n// component. A library cannot do that with a prop, so every value entering\n// `current` is checked first. `isValidColor` is Reka's own parser rather than a\n// regex here, so what this accepts and what the parts accept cannot drift.\nfunction toColor(value: string | undefined): string {\n return value !== undefined && isValidColor(value) ? value : FALLBACK;\n}\n\n// The working colour, fed to all four parts. Seeded from the prop and advanced\n// on every tick, exactly as Slider's `lastValue` is: given a defined model value\n// Reka runs fully controlled, so a host that correctly withholds transient\n// values until commit would otherwise freeze the thumbs at the gesture's start.\nconst current = ref(toColor(props.modelValue));\n\n// The value the host last acknowledged. Every commit path compares against it,\n// which is what makes a gesture that ends where it started — a click that lands\n// on the thumb, an arrow at the edge of the area, the same hex retyped, the\n// already-selected preset clicked again — produce no checkpoint at all.\nconst lastCommitted = ref(current.value);\n\n// An incoming value equal to `current` is this component's own emit echoing\n// back through a `v-model`, and re-baselining on it would swallow the commit at\n// the end of the gesture that produced it. Anything else is the host moving the\n// colour itself, which is a new baseline by definition — which is why this\n// needs no \"is a gesture in flight?\" flag to tell the two apart.\nwatch(\n () => props.modelValue,\n (value) => {\n const next = toColor(value);\n if (next === current.value) return;\n current.value = next;\n lastCommitted.value = next;\n },\n);\n\n// Every one of Reka's parts writes a hex string back into its own model, but\n// each types its update as `string | Color` because that union is what it will\n// *accept* coming in. Narrowing it here rather than casting keeps the object\n// half real: a future part that emits one still resolves to hex instead of\n// stringifying to \"[object Object]\" and failing to parse two frames later.\nfunction applyFromPart(value: string | Color): void {\n apply(typeof value === \"string\" ? value : colorToString(value, \"hex\"));\n}\n\nfunction apply(next: string): void {\n const value = toColor(next);\n if (value === current.value) return;\n current.value = value;\n emit(\"update:modelValue\", value);\n}\n\n/**\n * The area thumb's `aria-valuetext`, which Reka would otherwise build from its\n * own English channel names — \"Saturation 60, Brightness 80\", said again on\n * every arrow key.\n *\n * The two numbers are recomputed here rather than read out of Reka, because\n * Reka exposes neither: `ColorAreaRoot` yields only `style` to its slot and\n * keeps `xValue`/`yValue` in a context this component cannot inject. What it\n * does export is the arithmetic — `getChannelValue` and `normalizeColor` are\n * the same two functions `ColorAreaRoot` calls, applied to the same `current`\n * this component hands it as `model-value`, with the same `Math.round`. So the\n * number here and the `aria-valuenow` beside it agree by construction rather\n * than by coincidence, which is what makes replacing this string safe: Reka\n * re-derives its own pair from the model on the next tick after any gesture,\n * to this identical formula.\n */\nconst areaValueText = computed(() => {\n const color = normalizeColor(current.value);\n return text.value.areaValue({\n saturation: Math.round(getChannelValue(color, \"saturation\")),\n brightness: Math.round(getChannelValue(color, \"brightness\")),\n });\n});\n\nfunction onFieldCommit(value: string | Color): void {\n applyFromPart(value);\n commitCurrent();\n}\n\nfunction commitCurrent(): void {\n if (current.value === lastCommitted.value) return;\n lastCommitted.value = current.value;\n emit(\"commit\", current.value);\n}\n\n// Reka commits the area on pointer release only — `ColorAreaArea` calls its\n// root's `commitValues` from `pointerup` and not from its own key handler — so\n// an arrow-stepped colour would never reach a host's undo stack. Deferring by a\n// tick is what makes this independent of whether Vue runs this listener before\n// or after Reka's on the same element: by then the step has been applied and\n// `current` holds it. `commitCurrent` swallows the no-op at the axis limits.\nconst AREA_STEP_KEYS = new Set([\n \"ArrowLeft\",\n \"ArrowRight\",\n \"ArrowUp\",\n \"ArrowDown\",\n \"PageUp\",\n \"PageDown\",\n \"Home\",\n \"End\",\n]);\n\nfunction onAreaKeydown(event: KeyboardEvent): void {\n if (field.disabled || !AREA_STEP_KEYS.has(event.key)) return;\n void nextTick(commitCurrent);\n}\n\n// A preset that will not parse is dropped rather than rendered: it would be an\n// invisible square that sets an unusable value, and an empty row would leave a\n// `role=\"listbox\"` with no options, which is an ARIA violation of its own. The\n// row is therefore rendered only when something survives this.\nconst presets = computed(() => (props.swatches ?? []).filter((swatch) => isValidColor(swatch)));\n\nfunction onPresetPick(value: unknown): void {\n if (typeof value !== \"string\") return;\n apply(value);\n commitCurrent();\n}\n\n// Unlike Slider and Select, `class` and the remaining fallthrough attributes go\n// to the same node. The picker has four interactive parts and no single one of\n// them is what an `aria-describedby` or a `data-testid` is about — the group\n// around them is. `class` still needs the `cn()` merge rather than Vue's plain\n// concatenation, so it is bound separately from the spread.\ndefineOptions({ inheritAttrs: false });\nconst { attrs, rest: groupAttrs } = useSplitAttrs();\n\n/**\n * Two of this control's four parts are Reka roots that the platform cannot\n * disable: the saturation area and the hue slider render `<span role=\"slider\"\n * tabindex=\"0\">`, and `<fieldset disabled>` reaches only `<input>`, `<button>`,\n * `<select>` and `<textarea>`. Measured in jsdom, both still took an arrow key\n * inside a disabled group and moved the colour — while the hex `<input>` beside\n * them went properly inert, so the picker was half unavailable and half not.\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// `id` and `aria-describedby` arrive as fallthrough attrs rather than props, so\n// they are handed in as this caller's own values: a caller who sets either\n// still beats the row, and the row's description is merged into theirs rather\n// than replacing it. `name`, `required` and `invalid` are absent because this\n// component has no prop for any of them — the row's answer stands unopposed.\nconst field = useFieldControl(() => ({\n id: attrs.id as string | undefined,\n describedBy: attrs[\"aria-describedby\"] as string | undefined,\n // The fieldset beats the prop in both directions, exactly as it does for the\n // hex input inside this very control.\n disabled: groupDisabled.value ? true : props.disabled,\n}));\n\n/**\n * The half of the resolved bag the group takes, and the reason there are two\n * halves at all.\n *\n * A row describes *the picker*, and no one of the four parts is the picker —\n * the colour is authored across all of them — so the group around them is what\n * carries the identity and the description, exactly as a `data-testid` does.\n *\n * `name` and `aria-required` cannot follow them there. ARIA allows neither on\n * `role=\"group\"`, and `aria-allowed-attr` is a WCAG 4.1.2 rule\n * `e2e/accessibility.e2e.ts` runs over every docs page, so shipping the whole\n * bag here would turn that gate red. They go to the hex field instead, which is\n * the picker's one real form control: a native `<input>` holding exactly the\n * `#rrggbb` this component emits, so — unlike NumberField's spinbutton, which\n * holds a *formatted* number and would post its grouping separators — a `name`\n * on it submits the model value itself. `aria-invalid` rides along with them,\n * because a state announced on entering a group is a state most readers meet\n * once, while the field is where an error about the value is actually read.\n */\nconst groupFieldAttrs = computed(() =>\n optional({ id: field.id, \"aria-describedby\": field.attrs[\"aria-describedby\"] }),\n);\n\n// Both thumbs sit on a surface whose colour is the value being chosen, so they\n// have to read against white, against black and against every hue in between. A\n// single-colour thumb cannot: the light ring vanishes on a pale fill and the\n// dark one vanishes on a dark fill. The pair — a `background` band inside a\n// `foreground` hairline — always leaves one of the two in contrast.\nconst THUMB =\n \"block size-6 rounded-full border-2 border-background bg-transparent ring-1 ring-foreground shadow-sm \" +\n \"transition-transform duration-fast ease-spring hover:scale-110 active:scale-95 \" +\n \"focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo \" +\n \"data-[disabled]:pointer-events-none\";\n</script>\n\n<template>\n <div\n ref=\"root\"\n v-bind=\"{ ...groupAttrs, ...groupFieldAttrs }\"\n role=\"group\"\n :aria-label=\"ariaLabel\"\n :aria-labelledby=\"ariaLabelledby\"\n :aria-disabled=\"field.disabled || undefined\"\n :data-disabled=\"field.disabled || undefined\"\n :class=\"\n cn(\n 'flex w-full max-w-xs flex-col gap-3',\n // No `opacity` on the group, and the split below is the whole reason.\n // A dim here ran over everything the picker holds, the hex among it:\n // measured on the built site, `opacity-50` put the hex value at 3.06:1\n // — the same 3.08:1 the text input's own dim produced before it was\n // drained, and the same failure axe does not raise because it exempts\n // a disabled control under 1.4.3.\n //\n // So the parts part ways. The saturation area drains to the neutral\n // well like every other unavailable control (its gradient is this\n // component's own inline binding, so unavailability can withhold it);\n // the hue track and the preset swatches keep a dim because their fills\n // are data colours no token can express; and the hex field takes the\n // drained fill, muted text and slackened rim every other control in\n // the library wears, because it is text and it is the one thing a\n // reader still needs from a picker they cannot use.\n field.disabled && 'cursor-not-allowed',\n attrs.class as string,\n )\n \"\n >\n <!-- Saturation across, brightness up. `style` is Reka's own gradient for\n those two axes at the current hue — the picked colour rendered as a\n surface, which is data and not a token. -->\n <ColorAreaRoot\n v-slot=\"{ style }\"\n :model-value=\"current\"\n color-space=\"hsb\"\n x-channel=\"saturation\"\n y-channel=\"brightness\"\n :disabled=\"field.disabled\"\n @update:model-value=\"applyFromPart\"\n @change-end=\"commitCurrent\"\n >\n <!-- Reka gives this `role=\"application\"`, which hands every key straight\n to the area rather than to the screen reader's own navigation. That\n only works if the region says what it is, so it is named here; the\n thumb inside carries the per-axis values.\n\n Both `aria-roledescription`s below replace one Reka writes in English\n inside its own render function. They reach the DOM as fallthrough\n attributes, which Vue merges last, so each is a replacement rather\n than a second phrase — and removing one falls back to Reka's English\n rather than to nothing, which is the failure no test of Loom's own\n strings would catch.\n\n `aria-valuetext` on the thumb is the third of them and the one a\n reader hears most, since it is re-announced on every arrow key.\n `areaValueText` explains why replacing it does not risk contradicting\n the `aria-valuenow` beside it. -->\n <!-- The gradient is Loom's own inline binding, so unavailability can\n take the surface back: with the picker disabled the gradient is\n withheld and the area falls to the neutral well, drained like every\n other unavailable control rather than faded through. -->\n <ColorAreaArea\n :style=\"field.disabled ? undefined : style\"\n :aria-label=\"text.area\"\n :aria-roledescription=\"text.areaRoleDescription\"\n class=\"relative h-40 w-full rounded-md border border-border bg-background data-[disabled]:bg-muted\"\n @keydown=\"onAreaKeydown\"\n >\n <ColorAreaThumb\n :aria-label=\"text.areaThumb\"\n :aria-roledescription=\"text.areaThumbRoleDescription\"\n :aria-valuetext=\"areaValueText\"\n :class=\"THUMB\"\n />\n </ColorAreaArea>\n </ColorAreaRoot>\n\n <ColorSliderRoot\n :model-value=\"current\"\n channel=\"hue\"\n color-space=\"hsb\"\n :disabled=\"field.disabled\"\n class=\"relative flex w-full touch-none items-center py-1\"\n @update:model-value=\"applyFromPart\"\n @change-end=\"commitCurrent\"\n >\n <!-- The one dim left on a *tokenless* surface, and it stays because it\n must: Reka paints the spectrum as an inline `style` inside its own\n component (verified against its source — the track's background\n never passes through a slot), and no class can outrank an inline\n style. The hue under the thumb is data, not chrome, so draining it\n to a token would be lying about what is there. -->\n <ColorSliderTrack\n class=\"relative h-3 w-full grow rounded-full border border-border data-[disabled]:opacity-50\"\n />\n <!-- Reka names this from its channel — \"Hue\" — so the binding replaces\n that rather than adding to it. -->\n <ColorSliderThumb :aria-label=\"text.hue\" :class=\"THUMB\" />\n </ColorSliderRoot>\n\n <!-- The hex is the picker's text channel, so it is always on screen and it\n is the edit surface too. Typing writes the model on blur and on Enter\n rather than per keystroke, so a half-typed value is never emitted and\n text that will not parse is reverted to the current colour; the arrow\n keys nudge it a step at a time. Both paths arrive here already at a\n boundary, which is why the field's update is itself the checkpoint. -->\n <ColorFieldRoot\n :model-value=\"current\"\n :disabled=\"field.disabled\"\n class=\"flex h-9 items-center gap-2 rounded-md border border-input bg-background px-3 text-sm text-foreground transition-[color,background-color,border-color,box-shadow] duration-fast ease-out focus-within:outline-2 focus-within:outline-offset-2 focus-within:outline-ring focus-within:shadow-halo data-[disabled]:cursor-not-allowed data-[disabled]:border-border data-[disabled]:bg-muted data-[disabled]:text-muted-foreground\"\n @update:model-value=\"onFieldCommit\"\n >\n <!-- `label` is Reka's own documented prop for this, so it is set rather\n than bound over: left unset the swatch names itself through a\n `getColorName` that answers \"vibrant red\" in English and is not\n exported for Loom to delegate to. The roledescription is a\n fallthrough replacement, as on the area above. -->\n <ColorSwatch\n :color=\"current\"\n :label=\"text.swatch({ color: current })\"\n :aria-roledescription=\"text.swatchRoleDescription\"\n :style=\"{ backgroundColor: current }\"\n class=\"size-6 shrink-0 rounded-sm border border-border\"\n />\n <!-- The row's three form-control answers, which the group cannot hold —\n see `groupFieldAttrs`. `aria-label` stays: it names the *field*, not\n the picker, and a row's label never reached this element anyway. -->\n <ColorFieldInput\n :aria-label=\"text.hex\"\n :name=\"field.name\"\n :aria-required=\"field.required || undefined\"\n :aria-invalid=\"field.invalid || undefined\"\n class=\"tabular min-w-0 flex-1 self-stretch bg-transparent outline-none disabled:cursor-not-allowed\"\n />\n </ColorFieldRoot>\n\n <!-- One tab stop, not one per swatch: Reka's swatch picker is a listbox\n with roving focus, so arrows move between presets and Enter or Space\n chooses. `replace` rather than Reka's default `toggle`: a row of\n presets is a choice, not a set of switches, so clicking the one\n already showing must re-affirm the colour rather than clear it to\n nothing. `onPresetPick`'s string check holds the same line from the\n other side, for the empty selection `toggle` would emit. -->\n <ColorSwatchPickerRoot\n v-if=\"presets.length > 0\"\n :model-value=\"current\"\n :disabled=\"field.disabled\"\n :aria-disabled=\"field.disabled || undefined\"\n selection-behavior=\"replace\"\n :aria-label=\"text.presets\"\n class=\"flex flex-wrap gap-2 data-[disabled]:opacity-50\"\n @update:model-value=\"onPresetPick\"\n >\n <!-- Each item names itself from Reka's English `getColorName` unless\n this binding replaces it, so a row of presets is where that\n vocabulary leaks in bulk. -->\n <!-- Each swatch's fill is a preset the host supplied, bound inline right\n here — data colours no token can express (the same constraint as\n the hue track above). Withholding the fill when unavailable would\n blank the palette instead of draining chrome around it, so the row\n keeps the dim: the one honest treatment for content that *is*\n colour. -->\n <ColorSwatchPickerItem\n v-for=\"preset in presets\"\n :key=\"preset\"\n :value=\"preset\"\n :disabled=\"field.disabled\"\n :aria-label=\"text.swatch({ color: preset })\"\n :style=\"{ backgroundColor: preset }\"\n class=\"size-6 cursor-pointer rounded-sm border border-border transition-transform duration-fast ease-spring hover:scale-110 active:scale-95 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo aria-selected:ring-2 aria-selected:ring-primary aria-selected:ring-offset-2 aria-selected:ring-offset-background data-[disabled]:pointer-events-none\"\n />\n </ColorSwatchPickerRoot>\n </div>\n</template>\n"],"mappings":"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"}
|