@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
package/dist/packages/primitives/slider/src/Slider.vue_vue_type_script_setup_true_lang.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Slider.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../../../packages/primitives/slider/src/Slider.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, ref, useTemplateRef, watch } from \"vue\";\nimport { SliderRoot, SliderTrack, SliderRange, SliderThumb } from \"reka-ui\";\nimport { cn } 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\";\n\n/**\n * Slider — one continuous value inside a bounded range. Reach for it when the\n * range itself is the information: a volume, a ratio, a share of something\n * whole. A number that happens to be numeric but has no meaningful ceiling —\n * a coordinate, an angle — belongs in a NumberField instead.\n *\n * Built on Reka UI's Slider for the `role=\"slider\"` semantics, the pointer\n * drag and the arrow / Home / End stepping. Single-thumb only: Reka models the\n * value as an array, and this exposes a scalar.\n *\n * Two things are added here.\n *\n * The first is the drag buffer, and without it the component silently drops\n * changes. Given a defined model value Reka runs fully controlled, and its\n * release-time \"did this change?\" check compares against whatever it was last\n * fed — not against what it emitted. A host that correctly withholds transient\n * values until commit therefore leaves that check reading the pre-drag value\n * for the whole gesture, so it always answers no and the commit never fires.\n * `lastValue` below feeds Reka's own transient ticks back into its model, which\n * is exactly the fix NumberField applies for the same reason. Keyboard steps\n * need no buffer: Reka updates and commits inside one synchronous call, so it\n * compares against a value that is still old either way.\n *\n * The second is the abort path. Reka has no drag cancellation of its own — it\n * handles pointerdown, move and up, and commits whenever the release value\n * differs from the one it snapshotted — so Escape or a browser-issued\n * `pointercancel` mid-drag would still write one checkpoint on release. The\n * bail-out mirrors NumberField's: reset `lastValue` to the committed value, so\n * Reka's own comparison sees no change and never commits, and swallow the\n * still-captured pointer's remaining ticks until it releases.\n *\n * Inside a [Field](../Field/Field.vue) it wires itself through\n * `useFieldControl()`: the row's id, the id of its hint or error line,\n * `required` and `invalid` all reach the thumb — which is the `role=\"slider\"`\n * element, and therefore the thing the row is talking about — and the row's\n * `name` reaches a hidden input, so\n * `<Field label=\"Volume\" error=\"…\"><Slider /></Field>` needs no attributes at\n * the call site. `disabled` still wins wherever it is set, in both directions,\n * which is why it defaults to `undefined` rather than `false`.\n *\n * **A row's label does not name it.** `<label for>` names a labelable element\n * and the thumb is a `span[role=\"slider\"]`, so the row's label resolves to it\n * and announces nobody. `aria-label`/`aria-labelledby` are still what name this\n * control, exactly as they were before — and they were always routed to the\n * thumb for the same reason the rest of this bag is.\n *\n * There is no `readonly`, and a row's is ignored rather than approximated. The\n * whole control is the drag: a track that shows a value and refuses to move is\n * a [Progress](../Progress/Progress.vue) bar wearing a thumb, and painting one\n * as live while swallowing every gesture is the state worse than either.\n */\nconst props = withDefaults(\n defineProps<{\n /** The current value. Transient drag positions are reported before it changes. */\n modelValue?: number;\n /** The floor of the range, and where Home lands. */\n min?: number;\n /** The ceiling of the range, and where End lands. */\n max?: number;\n /** The granularity of one arrow-key step and of the drag's own snapping. */\n step?: number;\n /** Unavailable: dims the track and refuses both the pointer and the keyboard. Unset defers to a wrapping Field. */\n disabled?: boolean | undefined;\n }>(),\n {\n min: 0,\n max: 1,\n step: 0.01,\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 position the thumb passes through during a drag. Not a checkpoint. */\n \"update:modelValue\": [value: number];\n /** Committed: once at the end of a gesture — drag release, or a keyboard step. */\n commit: [value: number];\n}>();\n\n// The root renders a real element, and it is the one a caller's `class` has to\n// land on — sizing and layout (`flex-1` to grow in a toolbar) are dead weight\n// on the thumb, which is a 16px absolutely-positioned circle no flex rule\n// reaches. Every other fallthrough attribute goes the other way, onto the\n// thumb: `aria-labelledby` describes the `role=\"slider\"` element, not the box\n// around it.\ndefineOptions({ inheritAttrs: false });\nconst { attrs, rest: thumbAttrs } = useSplitAttrs();\n\n/**\n * The one control in the library the platform cannot disable for us.\n *\n * `<fieldset disabled>` reaches `<input>`, `<button>`, `<select>` and\n * `<textarea>` and stops there, and Reka renders this thumb as a\n * `<span role=\"slider\" tabindex=\"0\">`. Measured in jsdom, a Slider inside a\n * disabled group kept its tab stop and still moved its value on Home and End —\n * identical behaviour to an available one. Painting it unavailable without\n * this would produce the worse defect rather than fix the visible one: a\n * control that looks unreachable and answers the keyboard anyway.\n *\n * It is read off the DOM rather than taken from the Field context because\n * `Fieldset.vue` deliberately publishes no `disabled` there — see\n * `../../lib/ancestor-disabled.ts` for why a read cannot drift from the\n * attribute the way a second declaration would.\n */\nconst root = useTemplateRef<{ $el?: Element }>(\"root\");\nconst groupDisabled = useAncestorDisabled(() => root.value?.$el);\n\n// `id` and `aria-describedby` reach this control as fallthrough attrs rather\n// than props, so they are read off `attrs` and handed in as this caller's own\n// values — a caller who sets either still beats the row, and the row's\n// description is merged into theirs rather than replacing it. `name`,\n// `required` and `invalid` are absent from the object because there is no prop\n// to oppose the row with; the row's answer stands unopposed, which is what\n// wrapping the slider in a Field asked for.\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 a\n // native control: an `<input :disabled=\"false\">` inside a disabled group is\n // disabled too, so a Slider that said the same must not be the one exception.\n disabled: groupDisabled.value ? true : props.disabled,\n}));\n\n// The resolved bag lands on the thumb for the same reason every other\n// fallthrough attribute does — it is the `role=\"slider\"` element, and an id, a\n// description or an `aria-invalid` describes that, not the box around it.\n//\n// `name` is the one key that goes the other way: a name on a thumb submits\n// nothing, so it drives the hidden input inside the root instead. Removed from\n// a copy rather than listed positively, so a key added to the resolved bag\n// later reaches the thumb without anyone remembering to come back here.\nconst thumbFieldAttrs = computed(() => {\n const aria: Record<string, unknown> = { ...field.attrs };\n delete aria.name;\n return aria;\n});\n\n// What the Reka root is fed as its own model value: seeded from the prop, then\n// advanced on every tick Reka emits, so its release-time check sees the drag's\n// real end position rather than the frozen prop.\nconst lastValue = ref(props.modelValue);\nwatch(\n () => props.modelValue,\n (value) => {\n lastValue.value = value;\n },\n);\n\nconst values = computed(() => (lastValue.value === undefined ? [] : [lastValue.value]));\n\nfunction onUpdate(next: number[] | undefined) {\n const value = next?.[0];\n if (value === undefined || aborted) return;\n lastValue.value = value;\n emit(\"update:modelValue\", value);\n}\n\nfunction onCommit(next: number[]) {\n if (next[0] !== undefined && !aborted) emit(\"commit\", next[0]);\n}\n\n// The abort path. Its window listeners live for the duration of one pointer\n// gesture and no longer.\nlet aborted = false;\nlet teardownDrag: (() => void) | undefined;\n\nfunction resetToCommitted() {\n if (lastValue.value === props.modelValue) return;\n lastValue.value = props.modelValue;\n // One transient tick carrying the committed value, so the host can restore\n // its pre-drag preview. Still never a checkpoint.\n if (props.modelValue !== undefined) emit(\"update:modelValue\", props.modelValue);\n}\n\nfunction onRootPointerDown() {\n if (field.disabled) return;\n aborted = false;\n const onDragKeydown = (keyEvent: KeyboardEvent) => {\n if (keyEvent.key !== \"Escape\" || aborted) return;\n keyEvent.preventDefault();\n keyEvent.stopPropagation();\n // Reka keeps the pointer captured until release, so `aborted` is what\n // stops the remaining move ticks from resurrecting the gesture.\n aborted = true;\n resetToCommitted();\n };\n const onPointerUp = () => {\n // This runs after Reka's own element-level release handling, so a\n // swallowed gesture has already settled by the time the abort re-arms.\n teardownDrag?.();\n aborted = false;\n };\n const onPointerCancel = () => {\n teardownDrag?.();\n aborted = false; // a cancelled pointer emits no further ticks\n resetToCommitted();\n };\n window.addEventListener(\"pointerup\", onPointerUp);\n window.addEventListener(\"pointercancel\", onPointerCancel);\n window.addEventListener(\"keydown\", onDragKeydown, true);\n teardownDrag = () => {\n window.removeEventListener(\"pointerup\", onPointerUp);\n window.removeEventListener(\"pointercancel\", onPointerCancel);\n window.removeEventListener(\"keydown\", onDragKeydown, true);\n teardownDrag = undefined;\n };\n}\n\nonBeforeUnmount(() => teardownDrag?.());\n</script>\n\n<template>\n <SliderRoot\n ref=\"root\"\n :model-value=\"values\"\n :min=\"min\"\n :max=\"max\"\n :step=\"step\"\n :disabled=\"field.disabled\"\n :class=\"\n cn(\n // Unavailability is painted in measured greys, never as an alpha over\n // the available state: the filled range and the thumb's rim *are* the\n // value, and `opacity-50` here took the range from 7.53:1 to 2.36:1\n // on the page ground — below WCAG 1.4.11's 3:1 floor for a graphical\n // object required to understand the control. The two parts drain to\n // their own tokens below; `aria-valuenow` announces the number, but\n // nothing re-paints it for a sighted reader, so the pixels stay.\n 'relative flex w-full touch-none items-center py-2 data-[disabled]:cursor-not-allowed',\n attrs.class as string,\n )\n \"\n @pointerdown=\"onRootPointerDown\"\n @update:model-value=\"onUpdate\"\n @value-commit=\"onCommit\"\n >\n <!-- Reka would mint this itself from a `name` on the root, but it models\n the value as an array and posts it as `volume[0]`. This control\n exposes a scalar and a row's `name` has to post one: a field that\n spells itself differently depending on which control its row holds is\n exactly the surprise the Field context exists to remove.\n\n `lastValue` and not `modelValue`, so what is submitted is what the\n thumb is showing: a host that withholds transient values until commit\n leaves the prop behind for the length of a gesture. -->\n <input\n v-if=\"field.name !== undefined\"\n type=\"hidden\"\n :name=\"field.name\"\n :value=\"lastValue\"\n :disabled=\"field.disabled\"\n />\n <SliderTrack class=\"relative h-1.5 w-full grow rounded-full bg-muted\">\n <!-- The filled range is a value a person set, so it is painted flat in\n the primary colour rather than in a gradient. Unavailable, it\n falls to the neutral well like every other control's value, keyed\n off Reka's own `data-disabled` on this node: `muted-foreground` is\n 5.25:1 on the page ground and 4.67:1 against the `bg-muted` track\n it sits on, both measured. -->\n <SliderRange\n class=\"absolute h-full rounded-full bg-primary data-[disabled]:bg-muted-foreground\"\n />\n </SliderTrack>\n <!-- The thumb's position is the value, so its rim drains with the range —\n `muted-foreground` at 5.25:1 on the page ground — while its fill,\n which is the page's own ground, needs no dim. -->\n <SliderThumb\n v-bind=\"{ ...thumbAttrs, ...thumbFieldAttrs }\"\n class=\"block h-6 w-6 rounded-full border-2 border-primary bg-background shadow-sm 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 data-[disabled]:pointer-events-none data-[disabled]:border-muted-foreground\"\n />\n </SliderRoot>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Slider.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../../../packages/primitives/slider/src/Slider.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, ref, useTemplateRef, watch } from \"vue\";\nimport { SliderRoot, SliderTrack, SliderRange, SliderThumb } from \"reka-ui\";\nimport { cn } 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\";\n\n/**\n * Slider — one continuous value inside a bounded range. Reach for it when the\n * range itself is the information: a volume, a ratio, a share of something\n * whole. A number that happens to be numeric but has no meaningful ceiling —\n * a coordinate, an angle — belongs in a NumberField instead.\n *\n * Built on Reka UI's Slider for the `role=\"slider\"` semantics, the pointer\n * drag and the arrow / Home / End stepping. Single-thumb only: Reka models the\n * value as an array, and this exposes a scalar.\n *\n * Two things are added here.\n *\n * The first is the drag buffer, and without it the component silently drops\n * changes. Given a defined model value Reka runs fully controlled, and its\n * release-time \"did this change?\" check compares against whatever it was last\n * fed — not against what it emitted. A host that correctly withholds transient\n * values until commit therefore leaves that check reading the pre-drag value\n * for the whole gesture, so it always answers no and the commit never fires.\n * `lastValue` below feeds Reka's own transient ticks back into its model, which\n * is exactly the fix NumberField applies for the same reason. Keyboard steps\n * need no buffer: Reka updates and commits inside one synchronous call, so it\n * compares against a value that is still old either way.\n *\n * The second is the abort path. Reka has no drag cancellation of its own — it\n * handles pointerdown, move and up, and commits whenever the release value\n * differs from the one it snapshotted — so Escape or a browser-issued\n * `pointercancel` mid-drag would still write one checkpoint on release. The\n * bail-out mirrors NumberField's: reset `lastValue` to where the gesture\n * started, so Reka's own comparison sees no change and never commits, and\n * swallow the still-captured pointer's remaining ticks until it releases. The\n * gesture's own start value rather than the prop, because an uncontrolled\n * host never feeds the prop back — resetting to it blanked the thumb to an\n * empty value set.\n *\n * Inside a [Field](../Field/Field.vue) it wires itself through\n * `useFieldControl()`: the row's id, the id of its hint or error line,\n * `required` and `invalid` all reach the thumb — which is the `role=\"slider\"`\n * element, and therefore the thing the row is talking about — and the row's\n * `name` reaches a hidden input, so\n * `<Field label=\"Volume\" error=\"…\"><Slider /></Field>` needs no attributes at\n * the call site. `disabled` still wins wherever it is set, in both directions,\n * which is why it defaults to `undefined` rather than `false`.\n *\n * **A row's label does not name it.** `<label for>` names a labelable element\n * and the thumb is a `span[role=\"slider\"]`, so the row's label resolves to it\n * and announces nobody. `aria-label`/`aria-labelledby` are still what name this\n * control, exactly as they were before — and they were always routed to the\n * thumb for the same reason the rest of this bag is.\n *\n * There is no `readonly`, and a row's is ignored rather than approximated. The\n * whole control is the drag: a track that shows a value and refuses to move is\n * a [Progress](../Progress/Progress.vue) bar wearing a thumb, and painting one\n * as live while swallowing every gesture is the state worse than either.\n */\nconst props = withDefaults(\n defineProps<{\n /** The current value. Transient drag positions are reported before it changes. */\n modelValue?: number;\n /** The floor of the range, and where Home lands. */\n min?: number;\n /** The ceiling of the range, and where End lands. */\n max?: number;\n /** The granularity of one arrow-key step and of the drag's own snapping. */\n step?: number;\n /** Unavailable: dims the track and refuses both the pointer and the keyboard. Unset defers to a wrapping Field. */\n disabled?: boolean | undefined;\n }>(),\n {\n min: 0,\n max: 1,\n step: 0.01,\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 position the thumb passes through during a drag. Not a checkpoint. */\n \"update:modelValue\": [value: number];\n /** Committed: once at the end of a gesture — drag release, or a keyboard step. */\n commit: [value: number];\n}>();\n\n// The root renders a real element, and it is the one a caller's `class` has to\n// land on — sizing and layout (`flex-1` to grow in a toolbar) are dead weight\n// on the thumb, which is a 16px absolutely-positioned circle no flex rule\n// reaches. Every other fallthrough attribute goes the other way, onto the\n// thumb: `aria-labelledby` describes the `role=\"slider\"` element, not the box\n// around it.\ndefineOptions({ inheritAttrs: false });\nconst { attrs, rest: thumbAttrs } = useSplitAttrs();\n\n/**\n * The one control in the library the platform cannot disable for us.\n *\n * `<fieldset disabled>` reaches `<input>`, `<button>`, `<select>` and\n * `<textarea>` and stops there, and Reka renders this thumb as a\n * `<span role=\"slider\" tabindex=\"0\">`. Measured in jsdom, a Slider inside a\n * disabled group kept its tab stop and still moved its value on Home and End —\n * identical behaviour to an available one. Painting it unavailable without\n * this would produce the worse defect rather than fix the visible one: a\n * control that looks unreachable and answers the keyboard anyway.\n *\n * It is read off the DOM rather than taken from the Field context because\n * `Fieldset.vue` deliberately publishes no `disabled` there — see\n * `../../lib/ancestor-disabled.ts` for why a read cannot drift from the\n * attribute the way a second declaration would.\n */\nconst root = useTemplateRef<{ $el?: Element }>(\"root\");\nconst groupDisabled = useAncestorDisabled(() => root.value?.$el);\n\n// `id` and `aria-describedby` reach this control as fallthrough attrs rather\n// than props, so they are read off `attrs` and handed in as this caller's own\n// values — a caller who sets either still beats the row, and the row's\n// description is merged into theirs rather than replacing it. `name`,\n// `required` and `invalid` are absent from the object because there is no prop\n// to oppose the row with; the row's answer stands unopposed, which is what\n// wrapping the slider in a Field asked for.\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 a\n // native control: an `<input :disabled=\"false\">` inside a disabled group is\n // disabled too, so a Slider that said the same must not be the one exception.\n disabled: groupDisabled.value ? true : props.disabled,\n}));\n\n// The resolved bag lands on the thumb for the same reason every other\n// fallthrough attribute does — it is the `role=\"slider\"` element, and an id, a\n// description or an `aria-invalid` describes that, not the box around it.\n//\n// `name` is the one key that goes the other way: a name on a thumb submits\n// nothing, so it drives the hidden input inside the root instead. Removed from\n// a copy rather than listed positively, so a key added to the resolved bag\n// later reaches the thumb without anyone remembering to come back here.\nconst thumbFieldAttrs = computed(() => {\n const aria: Record<string, unknown> = { ...field.attrs };\n delete aria.name;\n return aria;\n});\n\n// What the Reka root is fed as its own model value: seeded from the prop, then\n// advanced on every tick Reka emits, so its release-time check sees the drag's\n// real end position rather than the frozen prop.\nconst lastValue = ref(props.modelValue);\nwatch(\n () => props.modelValue,\n (value) => {\n lastValue.value = value;\n },\n);\n\nconst values = computed(() => (lastValue.value === undefined ? [] : [lastValue.value]));\n\nfunction onUpdate(next: number[] | undefined) {\n const value = next?.[0];\n if (value === undefined || aborted) return;\n lastValue.value = value;\n emit(\"update:modelValue\", value);\n}\n\nfunction onCommit(next: number[]) {\n if (next[0] !== undefined && !aborted) emit(\"commit\", next[0]);\n}\n\n// The abort path. Its window listeners live for the duration of one pointer\n// gesture and no longer.\nlet aborted = false;\nlet teardownDrag: (() => void) | undefined;\n\nfunction onRootPointerDown() {\n if (field.disabled) return;\n // Disarm before arming: a second concurrent pointerdown used to overwrite\n // `teardownDrag` instead of running it, so the first pointer's release tore\n // *this* gesture down mid-drag and its capture-phase keydown stayed on the\n // window swallowing every later Escape. Only after the old handlers are off\n // does the latch clear, so nothing stale observes the fresh gesture.\n teardownDrag?.();\n aborted = false;\n // What an abort restores: where this gesture set out from — captured now,\n // before any tick — rather than the prop. Mirrors NumberField's abort.\n const startValue = lastValue.value;\n\n const resetToStart = () => {\n if (lastValue.value === startValue) return;\n lastValue.value = startValue;\n // One transient tick carrying the restored value, so the host can roll\n // back its pre-drag preview. Still never a checkpoint.\n if (startValue !== undefined) emit(\"update:modelValue\", startValue);\n };\n const onDragKeydown = (keyEvent: KeyboardEvent) => {\n if (keyEvent.key !== \"Escape\" || aborted) return;\n keyEvent.preventDefault();\n keyEvent.stopPropagation();\n // Reka keeps the pointer captured until release, so `aborted` is what\n // stops the remaining move ticks from resurrecting the gesture.\n aborted = true;\n resetToStart();\n };\n const onPointerUp = () => {\n // This runs after Reka's own element-level release handling, so a\n // swallowed gesture has already settled by the time the abort re-arms.\n teardownDrag?.();\n aborted = false;\n };\n const onPointerCancel = () => {\n teardownDrag?.();\n aborted = false; // a cancelled pointer emits no further ticks\n resetToStart();\n };\n window.addEventListener(\"pointerup\", onPointerUp);\n window.addEventListener(\"pointercancel\", onPointerCancel);\n window.addEventListener(\"keydown\", onDragKeydown, true);\n teardownDrag = () => {\n window.removeEventListener(\"pointerup\", onPointerUp);\n window.removeEventListener(\"pointercancel\", onPointerCancel);\n window.removeEventListener(\"keydown\", onDragKeydown, true);\n teardownDrag = undefined;\n };\n}\n\nonBeforeUnmount(() => teardownDrag?.());\n</script>\n\n<template>\n <SliderRoot\n ref=\"root\"\n :model-value=\"values\"\n :min=\"min\"\n :max=\"max\"\n :step=\"step\"\n :disabled=\"field.disabled\"\n :class=\"\n cn(\n // Unavailability is painted in measured greys, never as an alpha over\n // the available state: the filled range and the thumb's rim *are* the\n // value, and `opacity-50` here took the range from 7.53:1 to 2.36:1\n // on the page ground — below WCAG 1.4.11's 3:1 floor for a graphical\n // object required to understand the control. The two parts drain to\n // their own tokens below; `aria-valuenow` announces the number, but\n // nothing re-paints it for a sighted reader, so the pixels stay.\n 'relative flex w-full touch-none items-center py-2 data-[disabled]:cursor-not-allowed',\n attrs.class as string,\n )\n \"\n @pointerdown=\"onRootPointerDown\"\n @update:model-value=\"onUpdate\"\n @value-commit=\"onCommit\"\n >\n <!-- Reka would mint this itself from a `name` on the root, but it models\n the value as an array and posts it as `volume[0]`. This control\n exposes a scalar and a row's `name` has to post one: a field that\n spells itself differently depending on which control its row holds is\n exactly the surprise the Field context exists to remove.\n\n `lastValue` and not `modelValue`, so what is submitted is what the\n thumb is showing: a host that withholds transient values until commit\n leaves the prop behind for the length of a gesture. -->\n <input\n v-if=\"field.name !== undefined\"\n type=\"hidden\"\n :name=\"field.name\"\n :value=\"lastValue\"\n :disabled=\"field.disabled\"\n />\n <SliderTrack class=\"relative h-1.5 w-full grow rounded-full bg-muted\">\n <!-- The filled range is a value a person set, so it is painted flat in\n the primary colour rather than in a gradient. Unavailable, it\n falls to the neutral well like every other control's value, keyed\n off Reka's own `data-disabled` on this node: `muted-foreground` is\n 5.25:1 on the page ground and 4.67:1 against the `bg-muted` track\n it sits on, both measured. -->\n <SliderRange\n class=\"absolute h-full rounded-full bg-primary data-[disabled]:bg-muted-foreground\"\n />\n </SliderTrack>\n <!-- The thumb's position is the value, so its rim drains with the range —\n `muted-foreground` at 5.25:1 on the page ground — while its fill,\n which is the page's own ground, needs no dim. -->\n <SliderThumb\n v-bind=\"{ ...thumbAttrs, ...thumbFieldAttrs }\"\n class=\"block h-6 w-6 rounded-full border-2 border-primary bg-background shadow-sm 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 data-[disabled]:pointer-events-none data-[disabled]:border-muted-foreground\"\n />\n </SliderRoot>\n</template>\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Stepper.js","names":[],"sources":["../../../../../packages/primitives/stepper/src/Stepper.vue"],"sourcesContent":["<script lang=\"ts\">\nimport type { StepperLabels } 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 *\n * `group` is capitalised where Reka's is not, which is what lets\n * `Stepper.test.ts` assert whose string reached the DOM rather than merely\n * what it said.\n */\nexport const STEPPER_LABELS: StepperLabels = {\n group: \"Progress\",\n position: ({ step, stepCount }) => `Step ${String(step)} of ${String(stepCount)}`,\n completed: ({ title }) => `${title} (completed)`,\n};\n\n/** One step in the spine. Its `title` is also the accessible name of that step's trigger. */\nexport interface StepperStep {\n /** The step's label, shown next to its indicator and read out as the trigger's name. */\n title: string;\n /** A line under the title saying what the step asks for. Omit it for a bare spine. */\n description?: string;\n /** Present but unreachable: the indicator greys and the title mutes, and neither pointer nor keyboard can select it. */\n disabled?: boolean;\n}\n\n/** The axis the spine runs along, which also decides which arrow keys move between steps. */\nexport type StepperOrientation = \"horizontal\" | \"vertical\";\n</script>\n\n<script setup lang=\"ts\">\nimport { computed, ref } from \"vue\";\nimport {\n StepperDescription,\n StepperIndicator,\n StepperItem,\n StepperRoot,\n StepperSeparator,\n StepperTitle,\n StepperTrigger,\n} from \"reka-ui\";\nimport { Check } from \"@lucide/vue\";\nimport { cn } from \"@ecoma-io/loom-core\";\nimport { optional } from \"@ecoma-io/loom-core\";\nimport { useSplitAttrs } from \"@ecoma-io/loom-core\";\nimport { useLabels, type LabelOverrides } from \"@ecoma-io/loom-labels\";\n\n/**\n * Stepper — the progress spine of a multi-step flow: a checkout, an\n * onboarding sequence, a wizard. It says how many steps there are, which one\n * a reader is on, and which are behind them; the step's own content is the\n * host's, rendered next to or under the spine.\n *\n * It is **not** a number stepper. A numeric value with increment and\n * decrement buttons is NumberField. The word is genuinely ambiguous and both\n * controls answer to it, so the two are worth naming together: this one is\n * about position in a flow, that one is about a quantity.\n *\n * Progress shows one bar for one task whose extent is a percentage — reach\n * for it when the stages have no names worth showing. Tabs switches between\n * panels that have no order at all; a stepper's steps are ordered by\n * definition, which is why it carries a connector and Tabs carries none.\n *\n * Built on Reka UI's Stepper, which supplies the item state machine\n * (completed / active / inactive), the `linear` reachability rule and\n * arrow-key navigation along the orientation's axis.\n *\n * Three things are added on top of it.\n *\n * The first is the roving tab stop. Reka gives *every* focusable trigger\n * `tabindex=\"0\"`, so a five-step spine would be five Tab stops — the defect\n * the accessibility bar names outright. The `tabindex` bound below overrides\n * Reka's, leaving exactly one trigger tabbable at a time (the one last\n * focused, else the current step); Reka's own arrow-key handler still moves\n * real focus between them, which `tabindex=\"-1\"` does not prevent.\n *\n * The second is where `aria-current` sits. Reka puts `aria-current=\"true\"` on\n * the item wrapper, a `div` with no role that a reader never lands on, so the\n * marking is not conveyed at the moment it matters. It is moved here onto the\n * trigger — the element that takes focus — and given the value the WAI-ARIA\n * pattern asks for on a step in a process.\n *\n * The third is the live region. Reka renders one of its own on the root and\n * writes \"Step N of M\" into it as a **text node inside its render function** —\n * not a prop, not a slot, not an attribute — which makes it the one string in\n * this library that no binding on Loom's side can replace. So Loom renders its\n * own alongside it and takes Reka's out of the accessibility tree from\n * `src/styles/global.css`, which carries that reasoning and the coupling it\n * creates. `e2e/stepper.e2e.ts` is what keeps the coupling honest: it asserts\n * that a Loom stepper has exactly one live region and that its words are\n * Loom's.\n */\nconst props = withDefaults(\n defineProps<{\n /** The current step, 1-based. Omit it and Stepper owns its own position. */\n modelValue?: number;\n /** The ordered steps. Their index decides their number; there is no id to keep. */\n steps: StepperStep[];\n /** The axis the spine runs along; vertical moves the titles beside the indicators. */\n orientation?: StepperOrientation;\n /** Locks the flow to its furthest point: a reader may go back, or one step on, never jump ahead. */\n linear?: boolean;\n /**\n * Names for everything the spine says out loud, as any subset of\n * `StepperLabels` — the rest stay as the host's `provideLoomLabels`\n * vocabulary left them, and then as Loom's English.\n *\n * A whole application's language belongs in that vocabulary rather than\n * here. This is the per-instance correction, and the key it exists for is\n * `group`: a page with two flows on it needs each named for what it steps\n * through.\n */\n labels?: LabelOverrides<StepperLabels>;\n }>(),\n { orientation: \"horizontal\", linear: false },\n);\n\nconst emit = defineEmits<{\n /** The step chosen, 1-based. Fires for a trigger click and for Enter/Space on one. */\n \"update:modelValue\": [value: number];\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(\"stepper\", STEPPER_LABELS, () => props.labels);\n\n// The root renders a real element and it is the one every fallthrough\n// attribute belongs on: it is the `role=\"group\"` the whole spine lives in, so\n// an `aria-label` naming the flow lands there. It is spread *after*\n// `text.group` in the template for that reason — the vocabulary supplies the\n// name a spine has when nobody names it, and a caller who does name one still\n// wins. `class` is pulled out of the spread and merged through `cn()` instead,\n// so a caller's layout utility resolves against the root's own rather than\n// merely being concatenated after it.\ndefineOptions({ inheritAttrs: false });\nconst { attrs, rest: rootAttrs } = useSplitAttrs();\n\n/**\n * The two layouts, side by side rather than as template branches that drift\n * apart. `satisfies` is what stops an orientation being added to the type and\n * forgotten here.\n *\n * Horizontal hangs the connector off the item box (`relative`) rather than\n * off the rail: `left-1/2 w-full` then spans exactly the distance between two\n * indicator centres, since the items are equal-width flex children. It is\n * drawn behind them — the trigger is `relative`, so it and every later item's\n * trigger paint over a line that runs under the circles.\n */\nconst LAYOUTS = {\n horizontal: {\n root: \"flex w-full items-start\",\n item: \"relative flex flex-1 flex-col items-center gap-2 text-center\",\n rail: \"\",\n separator: \"absolute left-1/2 top-4 h-0.5 w-full -translate-y-1/2\",\n fill: \"origin-left scale-x-0\",\n filled: \"scale-x-100\",\n text: \"flex flex-col gap-0.5\",\n },\n vertical: {\n root: \"flex flex-col\",\n item: \"flex gap-3\",\n rail: \"flex flex-col items-center self-stretch\",\n // `order-1` rather than a second template branch: the connector has to be\n // declared before the trigger so the trigger paints over it, and has to sit\n // below the trigger once the rail is a column.\n separator: \"order-1 my-1 w-0.5 flex-1\",\n fill: \"origin-top scale-y-0\",\n filled: \"scale-y-100\",\n text: \"flex flex-col gap-0.5\",\n },\n} satisfies Record<StepperOrientation, Record<string, string>>;\n\nconst layout = computed(() => LAYOUTS[props.orientation]);\n\n/** The step that last held focus, and so owns the spine's single tab stop. */\nconst focused = ref<number | null>(null);\n\n/**\n * Reka's own focusability rule, mirrored: a linear stepper refuses focus to\n * anything past one step ahead of where the reader is. It has to be repeated\n * rather than read off the DOM, because the tab stop is decided while the\n * `tabindex` attributes are still being rendered — and a tab stop parked on a\n * step Reka will not focus leaves the whole spine unreachable by Tab.\n */\nfunction focusable(step: number, current: number): boolean {\n if (props.steps[step - 1]?.disabled) return false;\n return props.linear ? step <= current + 1 : true;\n}\n\n/**\n * The one step whose trigger is tabbable. Everything else is `tabindex=\"-1\"`.\n *\n * Reka types the value it hands its own slot as possibly absent even though\n * `StepperRoot` defaults it to 1, so the fallback here is that declaration\n * being honoured rather than a state this can reach.\n */\nfunction tabStop(current: number | undefined): number {\n const at = current ?? 1;\n if (focused.value !== null && focusable(focused.value, at)) return focused.value;\n if (focusable(at, at)) return at;\n return props.steps.findIndex((_, index) => focusable(index + 1, at)) + 1;\n}\n\n/**\n * Reka points every trigger's `aria-describedby` at a description id whether\n * or not that description was rendered, and a reference resolving to nothing\n * is worse than no reference: it claims a description exists. Binding the key\n * as `undefined` is what takes it back off, since an attribute set to\n * `undefined` is removed rather than merged.\n */\nfunction describedBy(step: StepperStep): Record<string, undefined> {\n return step.description === undefined ? { \"aria-describedby\": undefined } : {};\n}\n\n/** Reka reports its position as possibly absent; this component's model is a step number or nothing at all. */\nfunction onUpdate(value: number | undefined): void {\n if (value !== undefined) emit(\"update:modelValue\", value);\n}\n</script>\n\n<template>\n <StepperRoot\n v-slot=\"{ modelValue: current }\"\n v-bind=\"{ 'aria-label': text.group, ...rootAttrs, ...optional({ modelValue }) }\"\n data-loom-stepper\n :orientation=\"orientation\"\n :linear=\"linear\"\n :class=\"cn(layout.root, attrs.class as string)\"\n @update:model-value=\"onUpdate\"\n >\n <StepperItem\n v-for=\"(step, index) in steps\"\n :key=\"index\"\n v-slot=\"{ state }\"\n :step=\"index + 1\"\n :disabled=\"step.disabled ?? false\"\n :aria-current=\"undefined\"\n :class=\"layout.item\"\n >\n <div :class=\"layout.rail\">\n <!-- Declared before the trigger so the trigger paints over it: the\n connector runs from this indicator's centre to the next one's. -->\n <StepperSeparator\n v-if=\"index < steps.length - 1\"\n :class=\"cn('overflow-hidden rounded-full bg-border', layout.separator)\"\n >\n <span\n :class=\"\n cn(\n 'block h-full w-full bg-primary transition-transform ease-out',\n layout.fill,\n state === 'completed' && layout.filled,\n )\n \"\n />\n </StepperSeparator>\n\n <StepperTrigger\n v-bind=\"describedBy(step)\"\n :tabindex=\"tabStop(current) === index + 1 ? 0 : -1\"\n :aria-current=\"state === 'active' ? 'step' : undefined\"\n :class=\"\n cn(\n 'relative flex h-8 w-8 shrink-0 items-center justify-center rounded-full border text-xs font-medium',\n 'transition-colors ease-out',\n 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo',\n // Unavailable is a *colour*, and the whole distinction lives on\n // the indicator. It used to be `opacity-50` on the item, which\n // took the title and the description down with it:\n // `--color-muted-foreground` is 5.76:1 on white and 2.11:1 once\n // composited at half alpha, so the one thing that had to stay\n // readable was the one thing the fade broke. A grey-filled disc\n // against the inactive step's white one says the same thing and\n // costs nothing, and every string below is a measured pair.\n //\n // Keyed off the prop and NOT off `data-[disabled]:`, because in\n // a linear flow Reka marks every step past the next one disabled\n // — painting all of them unavailable reads as broken rather than\n // as later, and a step that is merely ahead already says so by\n // being inactive. The branch also keeps the two apart in the\n // cascade: the inactive rules carry an attribute selector, so a\n // plain `bg-muted` alongside them would lose.\n step.disabled\n ? 'border-border-strong bg-muted text-muted-foreground'\n : [\n 'data-[state=inactive]:border-input data-[state=inactive]:bg-background data-[state=inactive]:text-muted-foreground',\n 'data-[state=inactive]:enabled:hover:bg-subtle',\n ],\n 'data-[state=active]:border-primary data-[state=active]:bg-primary-muted data-[state=active]:text-primary-text',\n 'data-[state=completed]:border-primary data-[state=completed]:bg-primary data-[state=completed]:text-primary-foreground',\n 'disabled:cursor-not-allowed',\n )\n \"\n @focus=\"focused = index + 1\"\n >\n <StepperIndicator class=\"flex items-center justify-center\">\n <!-- Three states, none of them colour alone: the check is a shape\n change, the number is text, and the current step carries\n `aria-current` above. -->\n <Check v-if=\"state === 'completed'\" class=\"h-4 w-4 animate-scale-in\" />\n <template v-else>{{ index + 1 }}</template>\n </StepperIndicator>\n </StepperTrigger>\n </div>\n\n <div\n :class=\"cn(layout.text, orientation === 'vertical' && index < steps.length - 1 && 'pb-6')\"\n >\n <!-- `as=\"span\"`, not Reka's default `h4`: a step label is not a\n section heading, and a component cannot know what heading level\n the page it lands in has room for. -->\n <!-- The title mutes rather than fades: `--color-muted-foreground` is a\n measured 5.76:1 on the card it sits on, two steps back from\n `--color-foreground` and still comfortably readable. The\n description below is already that colour and stays there — an\n unreachable step's description is the one line a reader most needs\n in order to find out why it is unreachable. -->\n <StepperTitle\n as=\"span\"\n :class=\"\n cn('text-sm font-medium', step.disabled ? 'text-muted-foreground' : 'text-foreground')\n \"\n >\n <!-- ARIA has a value for \"you are here\" and none for \"done\", and the\n check glyph is invisible to a screen reader. This element is what\n `aria-labelledby` names the trigger with, so the word has to join\n the name from inside it.\n Two nodes rather than the title plus a trailing \"(completed)\"\n span, because a suffix is Loom deciding where a qualifier sits\n relative to the thing it qualifies, and that is a property of the\n language. The visible half is `aria-hidden` and excluded from the\n name computation; the hidden half carries the whole finished\n sentence the vocabulary returned. -->\n <template v-if=\"state === 'completed'\">\n <span aria-hidden=\"true\">{{ step.title }}</span>\n <span class=\"sr-only\">{{ text.completed({ title: step.title }) }}</span>\n </template>\n <template v-else>{{ step.title }}</template>\n </StepperTitle>\n <StepperDescription v-if=\"step.description\" class=\"text-xs text-muted-foreground\">\n {{ step.description }}\n </StepperDescription>\n </div>\n </StepperItem>\n\n <!-- Loom's own position announcement, standing in for the one `StepperRoot`\n renders as a text node its render function hard-codes in English.\n `data-loom-live` is what the rule in `global.css` selects *around* when\n it removes Reka's from the accessibility tree, so the two are told\n apart by what Loom marked rather than by DOM order.\n The count comes from `steps` rather than from Reka's registry, which\n fills in over a tick as each trigger mounts — the same number, one\n render sooner, which matters for a region a screen reader reads on\n arrival. -->\n <span data-loom-live role=\"status\" aria-live=\"polite\" aria-atomic=\"true\" class=\"sr-only\">{{\n text.position({ step: current ?? 1, stepCount: steps.length })\n }}</span>\n </StepperRoot>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"Stepper.js","names":[],"sources":["../../../../../packages/primitives/stepper/src/Stepper.vue"],"sourcesContent":["<script lang=\"ts\">\nimport type { StepperLabels } 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 *\n * `group` is capitalised where Reka's is not, which is what lets\n * `Stepper.test.ts` assert whose string reached the DOM rather than merely\n * what it said.\n */\nexport const STEPPER_LABELS: StepperLabels = {\n group: \"Progress\",\n position: ({ step, stepCount }) => `Step ${String(step)} of ${String(stepCount)}`,\n step: ({ step }) => `Step ${String(step)}:`,\n completed: ({ title }) => `${title} (completed)`,\n};\n\n/** One step in the spine. Its `title` is also the accessible name of that step's trigger. */\nexport interface StepperStep {\n /** The step's label, shown next to its indicator and read out as the trigger's name. */\n title: string;\n /** A line under the title saying what the step asks for. Omit it for a bare spine. */\n description?: string;\n /** Present but unreachable: the indicator greys and the title mutes, and neither pointer nor keyboard can select it. */\n disabled?: boolean;\n}\n\n/** The axis the spine runs along, which also decides which arrow keys move between steps. */\nexport type StepperOrientation = \"horizontal\" | \"vertical\";\n</script>\n\n<script setup lang=\"ts\">\nimport { computed, ref } from \"vue\";\nimport {\n StepperDescription,\n StepperIndicator,\n StepperItem,\n StepperRoot,\n StepperSeparator,\n StepperTitle,\n StepperTrigger,\n} from \"reka-ui\";\nimport { Check } from \"@lucide/vue\";\nimport { cn } from \"@ecoma-io/loom-core\";\nimport { optional } from \"@ecoma-io/loom-core\";\nimport { useSplitAttrs } from \"@ecoma-io/loom-core\";\nimport { useLabels, type LabelOverrides } from \"@ecoma-io/loom-labels\";\n\n/**\n * Stepper — the progress spine of a multi-step flow: a checkout, an\n * onboarding sequence, a wizard. It says how many steps there are, which one\n * a reader is on, and which are behind them; the step's own content is the\n * host's, rendered next to or under the spine.\n *\n * It is **not** a number stepper. A numeric value with increment and\n * decrement buttons is NumberField. The word is genuinely ambiguous and both\n * controls answer to it, so the two are worth naming together: this one is\n * about position in a flow, that one is about a quantity.\n *\n * Progress shows one bar for one task whose extent is a percentage — reach\n * for it when the stages have no names worth showing. Tabs switches between\n * panels that have no order at all; a stepper's steps are ordered by\n * definition, which is why it carries a connector and Tabs carries none.\n *\n * Built on Reka UI's Stepper, which supplies the item state machine\n * (completed / active / inactive), the `linear` reachability rule and\n * arrow-key navigation along the orientation's axis.\n *\n * Three things are added on top of it.\n *\n * The first is the roving tab stop. Reka gives *every* focusable trigger\n * `tabindex=\"0\"`, so a five-step spine would be five Tab stops — the defect\n * the accessibility bar names outright. The `tabindex` bound below overrides\n * Reka's, leaving exactly one trigger tabbable at a time (the one last\n * focused, else the current step); Reka's own arrow-key handler still moves\n * real focus between them, which `tabindex=\"-1\"` does not prevent.\n *\n * The second is where `aria-current` sits. Reka puts `aria-current=\"true\"` on\n * the item wrapper, a `div` with no role that a reader never lands on, so the\n * marking is not conveyed at the moment it matters. It is moved here onto the\n * trigger — the element that takes focus — and given the value the WAI-ARIA\n * pattern asks for on a step in a process.\n *\n * The third is the live region. Reka renders one of its own on the root and\n * writes \"Step N of M\" into it as a **text node inside its render function** —\n * not a prop, not a slot, not an attribute — which makes it the one string in\n * this library that no binding on Loom's side can replace. So Loom renders its\n * own alongside it and takes Reka's out of the accessibility tree from\n * `src/styles/global.css`, which carries that reasoning and the coupling it\n * creates. `e2e/stepper.e2e.ts` is what keeps the coupling honest: it asserts\n * that a Loom stepper has exactly one live region and that its words are\n * Loom's.\n */\nconst props = withDefaults(\n defineProps<{\n /** The current step, 1-based. Omit it and Stepper owns its own position. */\n modelValue?: number;\n /** The ordered steps. Their index decides their number; there is no id to keep. */\n steps: StepperStep[];\n /** The axis the spine runs along; vertical moves the titles beside the indicators. */\n orientation?: StepperOrientation;\n /** Locks the flow to its furthest point: a reader may go back, or one step on, never jump ahead. */\n linear?: boolean;\n /**\n * Names for everything the spine says out loud, as any subset of\n * `StepperLabels` — the rest stay as the host's `provideLoomLabels`\n * vocabulary left them, and then as Loom's English.\n *\n * A whole application's language belongs in that vocabulary rather than\n * here. This is the per-instance correction, and the key it exists for is\n * `group`: a page with two flows on it needs each named for what it steps\n * through.\n */\n labels?: LabelOverrides<StepperLabels>;\n }>(),\n { orientation: \"horizontal\", linear: false },\n);\n\nconst emit = defineEmits<{\n /** The step chosen, 1-based. Fires for a trigger click and for Enter/Space on one. */\n \"update:modelValue\": [value: number];\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(\"stepper\", STEPPER_LABELS, () => props.labels);\n\n// The root renders a real element and it is the one every fallthrough\n// attribute belongs on: it is the `role=\"group\"` the whole spine lives in, so\n// an `aria-label` naming the flow lands there. It is spread *after*\n// `text.group` in the template for that reason — the vocabulary supplies the\n// name a spine has when nobody names it, and a caller who does name one still\n// wins. `class` is pulled out of the spread and merged through `cn()` instead,\n// so a caller's layout utility resolves against the root's own rather than\n// merely being concatenated after it.\ndefineOptions({ inheritAttrs: false });\nconst { attrs, rest: rootAttrs } = useSplitAttrs();\n\n/**\n * The two layouts, side by side rather than as template branches that drift\n * apart. `satisfies` is what stops an orientation being added to the type and\n * forgotten here.\n *\n * Horizontal hangs the connector off the item box (`relative`) rather than\n * off the rail: `left-1/2 w-full` then spans exactly the distance between two\n * indicator centres, since the items are equal-width flex children. It is\n * drawn behind them — the trigger is `relative`, so it and every later item's\n * trigger paint over a line that runs under the circles.\n */\nconst LAYOUTS = {\n horizontal: {\n root: \"flex w-full items-start\",\n item: \"relative flex flex-1 flex-col items-center gap-2 text-center\",\n rail: \"\",\n separator: \"absolute left-1/2 top-4 h-0.5 w-full -translate-y-1/2\",\n fill: \"origin-left scale-x-0\",\n filled: \"scale-x-100\",\n text: \"flex flex-col gap-0.5\",\n },\n vertical: {\n root: \"flex flex-col\",\n item: \"flex gap-3\",\n rail: \"flex flex-col items-center self-stretch\",\n // `order-1` rather than a second template branch: the connector has to be\n // declared before the trigger so the trigger paints over it, and has to sit\n // below the trigger once the rail is a column.\n separator: \"order-1 my-1 w-0.5 flex-1\",\n fill: \"origin-top scale-y-0\",\n filled: \"scale-y-100\",\n text: \"flex flex-col gap-0.5\",\n },\n} satisfies Record<StepperOrientation, Record<string, string>>;\n\nconst layout = computed(() => LAYOUTS[props.orientation]);\n\n/** The step that last held focus, and so owns the spine's single tab stop. */\nconst focused = ref<number | null>(null);\n\n/**\n * Reka's own focusability rule, mirrored: a linear stepper refuses focus to\n * anything past one step ahead of where the reader is. It has to be repeated\n * rather than read off the DOM, because the tab stop is decided while the\n * `tabindex` attributes are still being rendered — and a tab stop parked on a\n * step Reka will not focus leaves the whole spine unreachable by Tab.\n */\nfunction focusable(step: number, current: number): boolean {\n if (props.steps[step - 1]?.disabled) return false;\n return props.linear ? step <= current + 1 : true;\n}\n\n/**\n * The one step whose trigger is tabbable. Everything else is `tabindex=\"-1\"`.\n *\n * Reka types the value it hands its own slot as possibly absent even though\n * `StepperRoot` defaults it to 1, so the fallback here is that declaration\n * being honoured rather than a state this can reach.\n */\nfunction tabStop(current: number | undefined): number {\n const at = current ?? 1;\n if (focused.value !== null && focusable(focused.value, at)) return focused.value;\n if (focusable(at, at)) return at;\n return props.steps.findIndex((_, index) => focusable(index + 1, at)) + 1;\n}\n\n/**\n * Reka points every trigger's `aria-describedby` at a description id whether\n * or not that description was rendered, and a reference resolving to nothing\n * is worse than no reference: it claims a description exists. Binding the key\n * as `undefined` is what takes it back off, since an attribute set to\n * `undefined` is removed rather than merged.\n */\nfunction describedBy(step: StepperStep): Record<string, undefined> {\n return step.description === undefined ? { \"aria-describedby\": undefined } : {};\n}\n\n/** Reka reports its position as possibly absent; this component's model is a step number or nothing at all. */\nfunction onUpdate(value: number | undefined): void {\n if (value !== undefined) emit(\"update:modelValue\", value);\n}\n</script>\n\n<template>\n <StepperRoot\n v-slot=\"{ modelValue: current }\"\n v-bind=\"{ 'aria-label': text.group, ...rootAttrs, ...optional({ modelValue }) }\"\n data-loom-stepper\n :orientation=\"orientation\"\n :linear=\"linear\"\n :class=\"cn(layout.root, attrs.class as string)\"\n @update:model-value=\"onUpdate\"\n >\n <StepperItem\n v-for=\"(step, index) in steps\"\n :key=\"index\"\n v-slot=\"{ state }\"\n :step=\"index + 1\"\n :disabled=\"step.disabled ?? false\"\n :aria-current=\"undefined\"\n :class=\"layout.item\"\n >\n <div :class=\"layout.rail\">\n <!-- Declared before the trigger so the trigger paints over it: the\n connector runs from this indicator's centre to the next one's. -->\n <StepperSeparator\n v-if=\"index < steps.length - 1\"\n :class=\"cn('overflow-hidden rounded-full bg-border', layout.separator)\"\n >\n <span\n :class=\"\n cn(\n 'block h-full w-full bg-primary transition-transform ease-out',\n layout.fill,\n state === 'completed' && layout.filled,\n )\n \"\n />\n </StepperSeparator>\n\n <StepperTrigger\n v-bind=\"describedBy(step)\"\n :tabindex=\"tabStop(current) === index + 1 ? 0 : -1\"\n :aria-current=\"state === 'active' ? 'step' : undefined\"\n :class=\"\n cn(\n 'relative flex h-8 w-8 shrink-0 items-center justify-center rounded-full border text-xs font-medium',\n 'transition-colors ease-out',\n 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo',\n // Unavailable is a *colour*, and the whole distinction lives on\n // the indicator. It used to be `opacity-50` on the item, which\n // took the title and the description down with it:\n // `--color-muted-foreground` is 5.76:1 on white and 2.11:1 once\n // composited at half alpha, so the one thing that had to stay\n // readable was the one thing the fade broke. A grey-filled disc\n // against the inactive step's white one says the same thing and\n // costs nothing, and every string below is a measured pair.\n //\n // Keyed off the prop and NOT off `data-[disabled]:`, because in\n // a linear flow Reka marks every step past the next one disabled\n // — painting all of them unavailable reads as broken rather than\n // as later, and a step that is merely ahead already says so by\n // being inactive. The branch also keeps the two apart in the\n // cascade: the inactive rules carry an attribute selector, so a\n // plain `bg-muted` alongside them would lose.\n step.disabled\n ? 'border-border-strong bg-muted text-muted-foreground'\n : [\n 'data-[state=inactive]:border-input data-[state=inactive]:bg-background data-[state=inactive]:text-muted-foreground',\n 'data-[state=inactive]:enabled:hover:bg-subtle',\n ],\n 'data-[state=active]:border-primary data-[state=active]:bg-primary-muted data-[state=active]:text-primary-text',\n 'data-[state=completed]:border-primary data-[state=completed]:bg-primary data-[state=completed]:text-primary-foreground',\n 'disabled:cursor-not-allowed',\n )\n \"\n @focus=\"focused = index + 1\"\n >\n <StepperIndicator class=\"flex items-center justify-center\">\n <!-- Three states, none of them colour alone: the check is a shape\n change, the number is text, and the current step carries\n `aria-current` above. -->\n <Check v-if=\"state === 'completed'\" class=\"h-4 w-4 animate-scale-in\" />\n <template v-else>{{ index + 1 }}</template>\n </StepperIndicator>\n </StepperTrigger>\n </div>\n\n <div\n :class=\"cn(layout.text, orientation === 'vertical' && index < steps.length - 1 && 'pb-6')\"\n >\n <!-- `as=\"span\"`, not Reka's default `h4`: a step label is not a\n section heading, and a component cannot know what heading level\n the page it lands in has room for. -->\n <!-- The title mutes rather than fades: `--color-muted-foreground` is a\n measured 5.76:1 on the card it sits on, two steps back from\n `--color-foreground` and still comfortably readable. The\n description below is already that colour and stays there — an\n unreachable step's description is the one line a reader most needs\n in order to find out why it is unreachable. -->\n <StepperTitle\n as=\"span\"\n :class=\"\n cn('text-sm font-medium', step.disabled ? 'text-muted-foreground' : 'text-foreground')\n \"\n >\n <!-- ARIA has a value for \"you are here\" and none for \"done\", and the\n check glyph is invisible to a screen reader. This element is what\n `aria-labelledby` names the trigger with, so the word has to join\n the name from inside it.\n Two nodes rather than the title plus a trailing \"(completed)\"\n span, because a suffix is Loom deciding where a qualifier sits\n relative to the thing it qualifies, and that is a property of the\n language. The visible half is `aria-hidden` and excluded from the\n name computation; the hidden half carries the whole finished\n sentence the vocabulary returned. -->\n <!-- The position leads the name for the same reason: the trigger's\n visible text is the step's number, and WCAG 2.5.3 (Label in\n Name) makes a control's visible text part of its accessible\n name. Measured 2026-08-26, `label-content-name-mismatch` fired\n on every non-completed trigger until the number joined the\n name — a voice user saying \"Step 2\" has to land on the same\n trigger one saying \"Shipping\" does. -->\n <span class=\"sr-only\">{{ text.step({ step: index + 1 }) }}</span>\n <template v-if=\"state === 'completed'\">\n <span aria-hidden=\"true\">{{ step.title }}</span>\n <span class=\"sr-only\">{{ text.completed({ title: step.title }) }}</span>\n </template>\n <template v-else>{{ step.title }}</template>\n </StepperTitle>\n <StepperDescription v-if=\"step.description\" class=\"text-xs text-muted-foreground\">\n {{ step.description }}\n </StepperDescription>\n </div>\n </StepperItem>\n\n <!-- Loom's own position announcement, standing in for the one `StepperRoot`\n renders as a text node its render function hard-codes in English.\n `data-loom-live` is what the rule in `global.css` selects *around* when\n it removes Reka's from the accessibility tree, so the two are told\n apart by what Loom marked rather than by DOM order.\n The count comes from `steps` rather than from Reka's registry, which\n fills in over a tick as each trigger mounts — the same number, one\n render sooner, which matters for a region a screen reader reads on\n arrival. -->\n <span data-loom-live role=\"status\" aria-live=\"polite\" aria-atomic=\"true\" class=\"sr-only\">{{\n text.position({ step: current ?? 1, stepCount: steps.length })\n }}</span>\n </StepperRoot>\n</template>\n"],"mappings":""}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type LabelOverrides } from "
|
|
2
|
-
import type { StepperLabels } from "
|
|
1
|
+
import { type LabelOverrides } from "../../../labels/src/index";
|
|
2
|
+
import type { StepperLabels } from "../../../labels/src/index";
|
|
3
3
|
/**
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -8,9 +8,10 @@ import { Fragment, computed, createBlock, createCommentVNode, createElementBlock
|
|
|
8
8
|
import { Check } from "@lucide/vue";
|
|
9
9
|
import { StepperDescription, StepperIndicator, StepperItem, StepperRoot, StepperSeparator, StepperTitle, StepperTrigger } from "reka-ui";
|
|
10
10
|
//#region packages/primitives/stepper/src/Stepper.vue?vue&type=script&setup=true&lang.ts
|
|
11
|
-
var _hoisted_1 = {
|
|
12
|
-
var _hoisted_2 = {
|
|
13
|
-
var _hoisted_3 = {
|
|
11
|
+
var _hoisted_1 = { class: "sr-only" };
|
|
12
|
+
var _hoisted_2 = { "aria-hidden": "true" };
|
|
13
|
+
var _hoisted_3 = { class: "sr-only" };
|
|
14
|
+
var _hoisted_4 = {
|
|
14
15
|
"data-loom-live": "",
|
|
15
16
|
role: "status",
|
|
16
17
|
"aria-live": "polite",
|
|
@@ -30,6 +31,7 @@ var _hoisted_3 = {
|
|
|
30
31
|
var STEPPER_LABELS = {
|
|
31
32
|
group: "Progress",
|
|
32
33
|
position: ({ step, stepCount }) => `Step ${String(step)} of ${String(stepCount)}`,
|
|
34
|
+
step: ({ step }) => `Step ${String(step)}:`,
|
|
33
35
|
completed: ({ title }) => `${title} (completed)`
|
|
34
36
|
};
|
|
35
37
|
var Stepper_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
|
|
@@ -172,7 +174,7 @@ var Stepper_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCo
|
|
|
172
174
|
as: "span",
|
|
173
175
|
class: normalizeClass(unref(cn)("text-sm font-medium", step.disabled ? "text-muted-foreground" : "text-foreground"))
|
|
174
176
|
}, {
|
|
175
|
-
default: withCtx(() => [state === "completed" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createElementVNode("span",
|
|
177
|
+
default: withCtx(() => [createElementVNode("span", _hoisted_1, toDisplayString(unref(text).step({ step: index + 1 })), 1), state === "completed" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createElementVNode("span", _hoisted_2, toDisplayString(step.title), 1), createElementVNode("span", _hoisted_3, toDisplayString(unref(text).completed({ title: step.title })), 1)], 64)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [createTextVNode(toDisplayString(step.title), 1)], 64))]),
|
|
176
178
|
_: 2
|
|
177
179
|
}, 1032, ["class"]), step.description ? (openBlock(), createBlock(unref(StepperDescription), {
|
|
178
180
|
key: 0,
|
|
@@ -187,7 +189,7 @@ var Stepper_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCo
|
|
|
187
189
|
"disabled",
|
|
188
190
|
"class"
|
|
189
191
|
]);
|
|
190
|
-
}), 128)), createElementVNode("span",
|
|
192
|
+
}), 128)), createElementVNode("span", _hoisted_4, toDisplayString(unref(text).position({
|
|
191
193
|
step: current ?? 1,
|
|
192
194
|
stepCount: __props.steps.length
|
|
193
195
|
})), 1)]),
|
package/dist/packages/primitives/stepper/src/Stepper.vue_vue_type_script_setup_true_lang.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Stepper.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../../../packages/primitives/stepper/src/Stepper.vue"],"sourcesContent":["<script lang=\"ts\">\nimport type { StepperLabels } 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 *\n * `group` is capitalised where Reka's is not, which is what lets\n * `Stepper.test.ts` assert whose string reached the DOM rather than merely\n * what it said.\n */\nexport const STEPPER_LABELS: StepperLabels = {\n group: \"Progress\",\n position: ({ step, stepCount }) => `Step ${String(step)} of ${String(stepCount)}`,\n completed: ({ title }) => `${title} (completed)`,\n};\n\n/** One step in the spine. Its `title` is also the accessible name of that step's trigger. */\nexport interface StepperStep {\n /** The step's label, shown next to its indicator and read out as the trigger's name. */\n title: string;\n /** A line under the title saying what the step asks for. Omit it for a bare spine. */\n description?: string;\n /** Present but unreachable: the indicator greys and the title mutes, and neither pointer nor keyboard can select it. */\n disabled?: boolean;\n}\n\n/** The axis the spine runs along, which also decides which arrow keys move between steps. */\nexport type StepperOrientation = \"horizontal\" | \"vertical\";\n</script>\n\n<script setup lang=\"ts\">\nimport { computed, ref } from \"vue\";\nimport {\n StepperDescription,\n StepperIndicator,\n StepperItem,\n StepperRoot,\n StepperSeparator,\n StepperTitle,\n StepperTrigger,\n} from \"reka-ui\";\nimport { Check } from \"@lucide/vue\";\nimport { cn } from \"@ecoma-io/loom-core\";\nimport { optional } from \"@ecoma-io/loom-core\";\nimport { useSplitAttrs } from \"@ecoma-io/loom-core\";\nimport { useLabels, type LabelOverrides } from \"@ecoma-io/loom-labels\";\n\n/**\n * Stepper — the progress spine of a multi-step flow: a checkout, an\n * onboarding sequence, a wizard. It says how many steps there are, which one\n * a reader is on, and which are behind them; the step's own content is the\n * host's, rendered next to or under the spine.\n *\n * It is **not** a number stepper. A numeric value with increment and\n * decrement buttons is NumberField. The word is genuinely ambiguous and both\n * controls answer to it, so the two are worth naming together: this one is\n * about position in a flow, that one is about a quantity.\n *\n * Progress shows one bar for one task whose extent is a percentage — reach\n * for it when the stages have no names worth showing. Tabs switches between\n * panels that have no order at all; a stepper's steps are ordered by\n * definition, which is why it carries a connector and Tabs carries none.\n *\n * Built on Reka UI's Stepper, which supplies the item state machine\n * (completed / active / inactive), the `linear` reachability rule and\n * arrow-key navigation along the orientation's axis.\n *\n * Three things are added on top of it.\n *\n * The first is the roving tab stop. Reka gives *every* focusable trigger\n * `tabindex=\"0\"`, so a five-step spine would be five Tab stops — the defect\n * the accessibility bar names outright. The `tabindex` bound below overrides\n * Reka's, leaving exactly one trigger tabbable at a time (the one last\n * focused, else the current step); Reka's own arrow-key handler still moves\n * real focus between them, which `tabindex=\"-1\"` does not prevent.\n *\n * The second is where `aria-current` sits. Reka puts `aria-current=\"true\"` on\n * the item wrapper, a `div` with no role that a reader never lands on, so the\n * marking is not conveyed at the moment it matters. It is moved here onto the\n * trigger — the element that takes focus — and given the value the WAI-ARIA\n * pattern asks for on a step in a process.\n *\n * The third is the live region. Reka renders one of its own on the root and\n * writes \"Step N of M\" into it as a **text node inside its render function** —\n * not a prop, not a slot, not an attribute — which makes it the one string in\n * this library that no binding on Loom's side can replace. So Loom renders its\n * own alongside it and takes Reka's out of the accessibility tree from\n * `src/styles/global.css`, which carries that reasoning and the coupling it\n * creates. `e2e/stepper.e2e.ts` is what keeps the coupling honest: it asserts\n * that a Loom stepper has exactly one live region and that its words are\n * Loom's.\n */\nconst props = withDefaults(\n defineProps<{\n /** The current step, 1-based. Omit it and Stepper owns its own position. */\n modelValue?: number;\n /** The ordered steps. Their index decides their number; there is no id to keep. */\n steps: StepperStep[];\n /** The axis the spine runs along; vertical moves the titles beside the indicators. */\n orientation?: StepperOrientation;\n /** Locks the flow to its furthest point: a reader may go back, or one step on, never jump ahead. */\n linear?: boolean;\n /**\n * Names for everything the spine says out loud, as any subset of\n * `StepperLabels` — the rest stay as the host's `provideLoomLabels`\n * vocabulary left them, and then as Loom's English.\n *\n * A whole application's language belongs in that vocabulary rather than\n * here. This is the per-instance correction, and the key it exists for is\n * `group`: a page with two flows on it needs each named for what it steps\n * through.\n */\n labels?: LabelOverrides<StepperLabels>;\n }>(),\n { orientation: \"horizontal\", linear: false },\n);\n\nconst emit = defineEmits<{\n /** The step chosen, 1-based. Fires for a trigger click and for Enter/Space on one. */\n \"update:modelValue\": [value: number];\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(\"stepper\", STEPPER_LABELS, () => props.labels);\n\n// The root renders a real element and it is the one every fallthrough\n// attribute belongs on: it is the `role=\"group\"` the whole spine lives in, so\n// an `aria-label` naming the flow lands there. It is spread *after*\n// `text.group` in the template for that reason — the vocabulary supplies the\n// name a spine has when nobody names it, and a caller who does name one still\n// wins. `class` is pulled out of the spread and merged through `cn()` instead,\n// so a caller's layout utility resolves against the root's own rather than\n// merely being concatenated after it.\ndefineOptions({ inheritAttrs: false });\nconst { attrs, rest: rootAttrs } = useSplitAttrs();\n\n/**\n * The two layouts, side by side rather than as template branches that drift\n * apart. `satisfies` is what stops an orientation being added to the type and\n * forgotten here.\n *\n * Horizontal hangs the connector off the item box (`relative`) rather than\n * off the rail: `left-1/2 w-full` then spans exactly the distance between two\n * indicator centres, since the items are equal-width flex children. It is\n * drawn behind them — the trigger is `relative`, so it and every later item's\n * trigger paint over a line that runs under the circles.\n */\nconst LAYOUTS = {\n horizontal: {\n root: \"flex w-full items-start\",\n item: \"relative flex flex-1 flex-col items-center gap-2 text-center\",\n rail: \"\",\n separator: \"absolute left-1/2 top-4 h-0.5 w-full -translate-y-1/2\",\n fill: \"origin-left scale-x-0\",\n filled: \"scale-x-100\",\n text: \"flex flex-col gap-0.5\",\n },\n vertical: {\n root: \"flex flex-col\",\n item: \"flex gap-3\",\n rail: \"flex flex-col items-center self-stretch\",\n // `order-1` rather than a second template branch: the connector has to be\n // declared before the trigger so the trigger paints over it, and has to sit\n // below the trigger once the rail is a column.\n separator: \"order-1 my-1 w-0.5 flex-1\",\n fill: \"origin-top scale-y-0\",\n filled: \"scale-y-100\",\n text: \"flex flex-col gap-0.5\",\n },\n} satisfies Record<StepperOrientation, Record<string, string>>;\n\nconst layout = computed(() => LAYOUTS[props.orientation]);\n\n/** The step that last held focus, and so owns the spine's single tab stop. */\nconst focused = ref<number | null>(null);\n\n/**\n * Reka's own focusability rule, mirrored: a linear stepper refuses focus to\n * anything past one step ahead of where the reader is. It has to be repeated\n * rather than read off the DOM, because the tab stop is decided while the\n * `tabindex` attributes are still being rendered — and a tab stop parked on a\n * step Reka will not focus leaves the whole spine unreachable by Tab.\n */\nfunction focusable(step: number, current: number): boolean {\n if (props.steps[step - 1]?.disabled) return false;\n return props.linear ? step <= current + 1 : true;\n}\n\n/**\n * The one step whose trigger is tabbable. Everything else is `tabindex=\"-1\"`.\n *\n * Reka types the value it hands its own slot as possibly absent even though\n * `StepperRoot` defaults it to 1, so the fallback here is that declaration\n * being honoured rather than a state this can reach.\n */\nfunction tabStop(current: number | undefined): number {\n const at = current ?? 1;\n if (focused.value !== null && focusable(focused.value, at)) return focused.value;\n if (focusable(at, at)) return at;\n return props.steps.findIndex((_, index) => focusable(index + 1, at)) + 1;\n}\n\n/**\n * Reka points every trigger's `aria-describedby` at a description id whether\n * or not that description was rendered, and a reference resolving to nothing\n * is worse than no reference: it claims a description exists. Binding the key\n * as `undefined` is what takes it back off, since an attribute set to\n * `undefined` is removed rather than merged.\n */\nfunction describedBy(step: StepperStep): Record<string, undefined> {\n return step.description === undefined ? { \"aria-describedby\": undefined } : {};\n}\n\n/** Reka reports its position as possibly absent; this component's model is a step number or nothing at all. */\nfunction onUpdate(value: number | undefined): void {\n if (value !== undefined) emit(\"update:modelValue\", value);\n}\n</script>\n\n<template>\n <StepperRoot\n v-slot=\"{ modelValue: current }\"\n v-bind=\"{ 'aria-label': text.group, ...rootAttrs, ...optional({ modelValue }) }\"\n data-loom-stepper\n :orientation=\"orientation\"\n :linear=\"linear\"\n :class=\"cn(layout.root, attrs.class as string)\"\n @update:model-value=\"onUpdate\"\n >\n <StepperItem\n v-for=\"(step, index) in steps\"\n :key=\"index\"\n v-slot=\"{ state }\"\n :step=\"index + 1\"\n :disabled=\"step.disabled ?? false\"\n :aria-current=\"undefined\"\n :class=\"layout.item\"\n >\n <div :class=\"layout.rail\">\n <!-- Declared before the trigger so the trigger paints over it: the\n connector runs from this indicator's centre to the next one's. -->\n <StepperSeparator\n v-if=\"index < steps.length - 1\"\n :class=\"cn('overflow-hidden rounded-full bg-border', layout.separator)\"\n >\n <span\n :class=\"\n cn(\n 'block h-full w-full bg-primary transition-transform ease-out',\n layout.fill,\n state === 'completed' && layout.filled,\n )\n \"\n />\n </StepperSeparator>\n\n <StepperTrigger\n v-bind=\"describedBy(step)\"\n :tabindex=\"tabStop(current) === index + 1 ? 0 : -1\"\n :aria-current=\"state === 'active' ? 'step' : undefined\"\n :class=\"\n cn(\n 'relative flex h-8 w-8 shrink-0 items-center justify-center rounded-full border text-xs font-medium',\n 'transition-colors ease-out',\n 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo',\n // Unavailable is a *colour*, and the whole distinction lives on\n // the indicator. It used to be `opacity-50` on the item, which\n // took the title and the description down with it:\n // `--color-muted-foreground` is 5.76:1 on white and 2.11:1 once\n // composited at half alpha, so the one thing that had to stay\n // readable was the one thing the fade broke. A grey-filled disc\n // against the inactive step's white one says the same thing and\n // costs nothing, and every string below is a measured pair.\n //\n // Keyed off the prop and NOT off `data-[disabled]:`, because in\n // a linear flow Reka marks every step past the next one disabled\n // — painting all of them unavailable reads as broken rather than\n // as later, and a step that is merely ahead already says so by\n // being inactive. The branch also keeps the two apart in the\n // cascade: the inactive rules carry an attribute selector, so a\n // plain `bg-muted` alongside them would lose.\n step.disabled\n ? 'border-border-strong bg-muted text-muted-foreground'\n : [\n 'data-[state=inactive]:border-input data-[state=inactive]:bg-background data-[state=inactive]:text-muted-foreground',\n 'data-[state=inactive]:enabled:hover:bg-subtle',\n ],\n 'data-[state=active]:border-primary data-[state=active]:bg-primary-muted data-[state=active]:text-primary-text',\n 'data-[state=completed]:border-primary data-[state=completed]:bg-primary data-[state=completed]:text-primary-foreground',\n 'disabled:cursor-not-allowed',\n )\n \"\n @focus=\"focused = index + 1\"\n >\n <StepperIndicator class=\"flex items-center justify-center\">\n <!-- Three states, none of them colour alone: the check is a shape\n change, the number is text, and the current step carries\n `aria-current` above. -->\n <Check v-if=\"state === 'completed'\" class=\"h-4 w-4 animate-scale-in\" />\n <template v-else>{{ index + 1 }}</template>\n </StepperIndicator>\n </StepperTrigger>\n </div>\n\n <div\n :class=\"cn(layout.text, orientation === 'vertical' && index < steps.length - 1 && 'pb-6')\"\n >\n <!-- `as=\"span\"`, not Reka's default `h4`: a step label is not a\n section heading, and a component cannot know what heading level\n the page it lands in has room for. -->\n <!-- The title mutes rather than fades: `--color-muted-foreground` is a\n measured 5.76:1 on the card it sits on, two steps back from\n `--color-foreground` and still comfortably readable. The\n description below is already that colour and stays there — an\n unreachable step's description is the one line a reader most needs\n in order to find out why it is unreachable. -->\n <StepperTitle\n as=\"span\"\n :class=\"\n cn('text-sm font-medium', step.disabled ? 'text-muted-foreground' : 'text-foreground')\n \"\n >\n <!-- ARIA has a value for \"you are here\" and none for \"done\", and the\n check glyph is invisible to a screen reader. This element is what\n `aria-labelledby` names the trigger with, so the word has to join\n the name from inside it.\n Two nodes rather than the title plus a trailing \"(completed)\"\n span, because a suffix is Loom deciding where a qualifier sits\n relative to the thing it qualifies, and that is a property of the\n language. The visible half is `aria-hidden` and excluded from the\n name computation; the hidden half carries the whole finished\n sentence the vocabulary returned. -->\n <template v-if=\"state === 'completed'\">\n <span aria-hidden=\"true\">{{ step.title }}</span>\n <span class=\"sr-only\">{{ text.completed({ title: step.title }) }}</span>\n </template>\n <template v-else>{{ step.title }}</template>\n </StepperTitle>\n <StepperDescription v-if=\"step.description\" class=\"text-xs text-muted-foreground\">\n {{ step.description }}\n </StepperDescription>\n </div>\n </StepperItem>\n\n <!-- Loom's own position announcement, standing in for the one `StepperRoot`\n renders as a text node its render function hard-codes in English.\n `data-loom-live` is what the rule in `global.css` selects *around* when\n it removes Reka's from the accessibility tree, so the two are told\n apart by what Loom marked rather than by DOM order.\n The count comes from `steps` rather than from Reka's registry, which\n fills in over a tick as each trigger mounts — the same number, one\n render sooner, which matters for a region a screen reader reads on\n arrival. -->\n <span data-loom-live role=\"status\" aria-live=\"polite\" aria-atomic=\"true\" class=\"sr-only\">{{\n text.position({ step: current ?? 1, stepCount: steps.length })\n }}</span>\n </StepperRoot>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAaA,IAAa,iBAAgC;CAC3C,OAAO;CACP,WAAW,EAAE,MAAM,gBAAgB,QAAQ,OAAO,IAAI,EAAE,MAAM,OAAO,SAAS;CAC9E,YAAY,EAAE,YAAY,GAAG,MAAM;AACrC;;;;;;;;;;;;;;;;EA8EA,MAAM,QAAQ;EAyBd,MAAM,OAAO;EAQb,MAAM,OAAO,UAAU,WAAW,sBAAsB,MAAM,MAAM;EAWpE,MAAM,EAAE,OAAO,MAAM,cAAc,cAAc;;;;;;;;;;;;EAajD,MAAM,UAAU;GACd,YAAY;IACV,MAAM;IACN,MAAM;IACN,MAAM;IACN,WAAW;IACX,MAAM;IACN,QAAQ;IACR,MAAM;GACR;GACA,UAAU;IACR,MAAM;IACN,MAAM;IACN,MAAM;IAIN,WAAW;IACX,MAAM;IACN,QAAQ;IACR,MAAM;GACR;EACF;EAEA,MAAM,SAAS,eAAe,QAAQ,MAAM,YAAY;;EAGxD,MAAM,UAAU,IAAmB,IAAI;;;;;;;;EASvC,SAAS,UAAU,MAAc,SAA0B;GACzD,IAAI,MAAM,MAAM,OAAO,EAAE,EAAE,UAAU,OAAO;GAC5C,OAAO,MAAM,SAAS,QAAQ,UAAU,IAAI;EAC9C;;;;;;;;EASA,SAAS,QAAQ,SAAqC;GACpD,MAAM,KAAK,WAAW;GACtB,IAAI,QAAQ,UAAU,QAAQ,UAAU,QAAQ,OAAO,EAAE,GAAG,OAAO,QAAQ;GAC3E,IAAI,UAAU,IAAI,EAAE,GAAG,OAAO;GAC9B,OAAO,MAAM,MAAM,WAAW,GAAG,UAAU,UAAU,QAAQ,GAAG,EAAE,CAAC,IAAI;EACzE;;;;;;;;EASA,SAAS,YAAY,MAA8C;GACjE,OAAO,KAAK,gBAAgB,KAAA,IAAY,EAAE,oBAAoB,KAAA,EAAU,IAAI,CAAC;EAC/E;;EAGA,SAAS,SAAS,OAAiC;GACjD,IAAI,UAAU,KAAA,GAAW,KAAK,qBAAqB,KAAK;EAC1D;;GAIE,OAAA,UAAA,GAAA,YAwIc,MAAA,WAAA,GAxId,WAwIc;IAAA,cAtIY,MAAA,IAAA,CAAI,CAAC;IAAK,GAAK,MAAA,SAAA;IAAS,GAAK,MAAA,QAAA,CAAQ,CAAA,EAAA,YAAG,QAAA,WAAU,CAAA;GAAA,GAAA;IAC1E,qBAAA;IACC,aAAa,QAAA;IACb,QAAQ,QAAA;IACR,OAAO,MAAA,EAAA,CAAE,CAAC,OAAA,MAAO,MAAM,MAAA,KAAA,CAAK,CAAC,KAAK;IAClC,uBAAoB;;IAGnB,SAAA,SAA8B,EAAA,YATV,cAAO,EAQ7B,UAAA,IAAA,GAAA,mBAiHc,UAAA,MAAA,WAhHY,QAAA,QAAhB,MAAM,UAAK;KADrB,OAAA,UAAA,GAAA,YAiHc,MAAA,WAAA,GAAA;MA/GX,KAAK;MAEL,MAAM,QAAK;MACX,UAAU,KAAK,YAAQ;MACvB,gBAAc,KAAA;MACd,OAAK,eAAE,OAAA,MAAO,IAAI;;MAEnB,SAAA,SAgEM,EAtEI,YAAK,CAMf,mBAgEM,OAAA,EAhEA,OAAK,eAAE,OAAA,MAAO,IAAI,EAAA,GAAA,CAId,QAAQ,QAAA,MAAM,SAAM,KAD5B,UAAA,GAAA,YAamB,MAAA,gBAAA,GAAA;;OAXhB,OAAK,eAAE,MAAA,EAAA,CAAE,CAAA,0CAA2C,OAAA,MAAO,SAAS,CAAA;;OAErE,SAAA,cAQE,CARF,mBAQE,QAAA,EAPC,OAAK,eAAiB,MAAA,EAAA,CAAE,CAAA,gEAAkG,OAAA,MAAO,MAAsB,UAAK,eAAoB,OAAA,MAAO,MAAA,CAAA,EAAA,GAAA,MAAA,CAAA,CAAA,CAAA;;MAU5L,GAAA,MAAA,CAAA,OAAA,CAAA,KAAA,mBAAA,IAAA,IAAA,GAAA,YA6CiB,MAAA,cAAA,GA7CjB,WA6CiB,EAAA,SAAA,KAAA,GA5CP,YAAY,IAAI,GAAA;OACvB,UAAU,QAAQ,OAAO,MAAM,QAAK,IAAA,IAAA;OACpC,gBAAc,UAAK,WAAA,SAAyB,KAAA;OAC5C,OAAoB,MAAA,EAAA,CAAE,CAAA,sGAAA,8BAAA,+GAAu7C,KAAK,WAAA,wDAAA,CAAA,sHAAA,+CAAA,GAAA,iHAAA,0HAAA,6BAAA;OAgCl9C,UAAK,WAAE,QAAA,QAAU,QAAK;;OAEvB,SAAA,cAMmB,CANnB,YAMmB,MAAA,gBAAA,GAAA,EAND,OAAM,mCAAkC,GAAA;QAIxD,SAAA,cAAuE,CAA1D,UAAK,eAAlB,UAAA,GAAA,YAAuE,MAAA,KAAA,GAAA;;SAAnC,OAAM;QAC1C,CAAA,MAAA,UAAA,GAAA,mBAA2C,UAAA,EAAA,KAAA,EAAA,GAAA,CAAvB,gBAAA,gBAAA,QAAK,CAAA,GAAA,CAAA,CAAA,GAAA,EAAA,EAAA,CAAA;;;;;;;;;MAK/B,CAAA,CAAA,GAAA,CAAA,GAAA,mBAqCM,OAAA,EApCH,OAAK,eAAE,MAAA,EAAA,CAAE,CAAC,OAAA,MAAO,MAAM,QAAA,gBAAW,cAAmB,QAAQ,QAAA,MAAM,SAAM,KAAA,MAAA,CAAA,EAAA,GAAA,CAW1E,YAqBe,MAAA,YAAA,GAAA;OApBb,IAAG;OACF,OAAK,eAAe,MAAA,EAAA,CAAE,CAAA,uBAAwB,KAAK,WAAQ,0BAAA,iBAAA,CAAA;;OAc5D,SAAA,cAGW,CAHK,UAAK,eAArB,UAAA,GAAA,mBAGW,UAAA,EAAA,KAAA,EAAA,GAAA,CAFT,mBAAgD,QAAhD,YAAgD,gBAApB,KAAK,KAAK,GAAA,CAAA,GACtC,mBAAwE,QAAxE,YAAwE,gBAA/C,MAAA,IAAA,CAAI,CAAC,UAAS,EAAA,OAAU,KAAK,MAAK,CAAA,CAAA,GAAA,CAAA,CAAA,GAAA,EAAA,MAE7D,UAAA,GAAA,mBAA4C,UAAA,EAAA,KAAA,EAAA,GAAA,CAAxB,gBAAA,gBAAA,KAAK,KAAK,GAAA,CAAA,CAAA,GAAA,EAAA,EAAA,CAAA;;MAEN,GAAA,MAAA,CAAA,OAAA,CAAA,GAAA,KAAK,eAA/B,UAAA,GAAA,YAEqB,MAAA,kBAAA,GAAA;;OAFuB,OAAM;;OAChD,SAAA,cAAsB,CAAnB,gBAAA,gBAAA,KAAK,WAAW,GAAA,CAAA,CAAA,CAAA;;;;;;;;;IAczB,CAAA,GAAA,GAAA,IAAA,mBAES,QAFT,YAES,gBADP,MAAA,IAAA,CAAI,CAAC,SAAQ;KAAA,MAAS,WAAO;KAAA,WAAkB,QAAA,MAAM;IAAM,CAAA,CAAA,GAAA,CAAA,CAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"Stepper.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../../../packages/primitives/stepper/src/Stepper.vue"],"sourcesContent":["<script lang=\"ts\">\nimport type { StepperLabels } 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 *\n * `group` is capitalised where Reka's is not, which is what lets\n * `Stepper.test.ts` assert whose string reached the DOM rather than merely\n * what it said.\n */\nexport const STEPPER_LABELS: StepperLabels = {\n group: \"Progress\",\n position: ({ step, stepCount }) => `Step ${String(step)} of ${String(stepCount)}`,\n step: ({ step }) => `Step ${String(step)}:`,\n completed: ({ title }) => `${title} (completed)`,\n};\n\n/** One step in the spine. Its `title` is also the accessible name of that step's trigger. */\nexport interface StepperStep {\n /** The step's label, shown next to its indicator and read out as the trigger's name. */\n title: string;\n /** A line under the title saying what the step asks for. Omit it for a bare spine. */\n description?: string;\n /** Present but unreachable: the indicator greys and the title mutes, and neither pointer nor keyboard can select it. */\n disabled?: boolean;\n}\n\n/** The axis the spine runs along, which also decides which arrow keys move between steps. */\nexport type StepperOrientation = \"horizontal\" | \"vertical\";\n</script>\n\n<script setup lang=\"ts\">\nimport { computed, ref } from \"vue\";\nimport {\n StepperDescription,\n StepperIndicator,\n StepperItem,\n StepperRoot,\n StepperSeparator,\n StepperTitle,\n StepperTrigger,\n} from \"reka-ui\";\nimport { Check } from \"@lucide/vue\";\nimport { cn } from \"@ecoma-io/loom-core\";\nimport { optional } from \"@ecoma-io/loom-core\";\nimport { useSplitAttrs } from \"@ecoma-io/loom-core\";\nimport { useLabels, type LabelOverrides } from \"@ecoma-io/loom-labels\";\n\n/**\n * Stepper — the progress spine of a multi-step flow: a checkout, an\n * onboarding sequence, a wizard. It says how many steps there are, which one\n * a reader is on, and which are behind them; the step's own content is the\n * host's, rendered next to or under the spine.\n *\n * It is **not** a number stepper. A numeric value with increment and\n * decrement buttons is NumberField. The word is genuinely ambiguous and both\n * controls answer to it, so the two are worth naming together: this one is\n * about position in a flow, that one is about a quantity.\n *\n * Progress shows one bar for one task whose extent is a percentage — reach\n * for it when the stages have no names worth showing. Tabs switches between\n * panels that have no order at all; a stepper's steps are ordered by\n * definition, which is why it carries a connector and Tabs carries none.\n *\n * Built on Reka UI's Stepper, which supplies the item state machine\n * (completed / active / inactive), the `linear` reachability rule and\n * arrow-key navigation along the orientation's axis.\n *\n * Three things are added on top of it.\n *\n * The first is the roving tab stop. Reka gives *every* focusable trigger\n * `tabindex=\"0\"`, so a five-step spine would be five Tab stops — the defect\n * the accessibility bar names outright. The `tabindex` bound below overrides\n * Reka's, leaving exactly one trigger tabbable at a time (the one last\n * focused, else the current step); Reka's own arrow-key handler still moves\n * real focus between them, which `tabindex=\"-1\"` does not prevent.\n *\n * The second is where `aria-current` sits. Reka puts `aria-current=\"true\"` on\n * the item wrapper, a `div` with no role that a reader never lands on, so the\n * marking is not conveyed at the moment it matters. It is moved here onto the\n * trigger — the element that takes focus — and given the value the WAI-ARIA\n * pattern asks for on a step in a process.\n *\n * The third is the live region. Reka renders one of its own on the root and\n * writes \"Step N of M\" into it as a **text node inside its render function** —\n * not a prop, not a slot, not an attribute — which makes it the one string in\n * this library that no binding on Loom's side can replace. So Loom renders its\n * own alongside it and takes Reka's out of the accessibility tree from\n * `src/styles/global.css`, which carries that reasoning and the coupling it\n * creates. `e2e/stepper.e2e.ts` is what keeps the coupling honest: it asserts\n * that a Loom stepper has exactly one live region and that its words are\n * Loom's.\n */\nconst props = withDefaults(\n defineProps<{\n /** The current step, 1-based. Omit it and Stepper owns its own position. */\n modelValue?: number;\n /** The ordered steps. Their index decides their number; there is no id to keep. */\n steps: StepperStep[];\n /** The axis the spine runs along; vertical moves the titles beside the indicators. */\n orientation?: StepperOrientation;\n /** Locks the flow to its furthest point: a reader may go back, or one step on, never jump ahead. */\n linear?: boolean;\n /**\n * Names for everything the spine says out loud, as any subset of\n * `StepperLabels` — the rest stay as the host's `provideLoomLabels`\n * vocabulary left them, and then as Loom's English.\n *\n * A whole application's language belongs in that vocabulary rather than\n * here. This is the per-instance correction, and the key it exists for is\n * `group`: a page with two flows on it needs each named for what it steps\n * through.\n */\n labels?: LabelOverrides<StepperLabels>;\n }>(),\n { orientation: \"horizontal\", linear: false },\n);\n\nconst emit = defineEmits<{\n /** The step chosen, 1-based. Fires for a trigger click and for Enter/Space on one. */\n \"update:modelValue\": [value: number];\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(\"stepper\", STEPPER_LABELS, () => props.labels);\n\n// The root renders a real element and it is the one every fallthrough\n// attribute belongs on: it is the `role=\"group\"` the whole spine lives in, so\n// an `aria-label` naming the flow lands there. It is spread *after*\n// `text.group` in the template for that reason — the vocabulary supplies the\n// name a spine has when nobody names it, and a caller who does name one still\n// wins. `class` is pulled out of the spread and merged through `cn()` instead,\n// so a caller's layout utility resolves against the root's own rather than\n// merely being concatenated after it.\ndefineOptions({ inheritAttrs: false });\nconst { attrs, rest: rootAttrs } = useSplitAttrs();\n\n/**\n * The two layouts, side by side rather than as template branches that drift\n * apart. `satisfies` is what stops an orientation being added to the type and\n * forgotten here.\n *\n * Horizontal hangs the connector off the item box (`relative`) rather than\n * off the rail: `left-1/2 w-full` then spans exactly the distance between two\n * indicator centres, since the items are equal-width flex children. It is\n * drawn behind them — the trigger is `relative`, so it and every later item's\n * trigger paint over a line that runs under the circles.\n */\nconst LAYOUTS = {\n horizontal: {\n root: \"flex w-full items-start\",\n item: \"relative flex flex-1 flex-col items-center gap-2 text-center\",\n rail: \"\",\n separator: \"absolute left-1/2 top-4 h-0.5 w-full -translate-y-1/2\",\n fill: \"origin-left scale-x-0\",\n filled: \"scale-x-100\",\n text: \"flex flex-col gap-0.5\",\n },\n vertical: {\n root: \"flex flex-col\",\n item: \"flex gap-3\",\n rail: \"flex flex-col items-center self-stretch\",\n // `order-1` rather than a second template branch: the connector has to be\n // declared before the trigger so the trigger paints over it, and has to sit\n // below the trigger once the rail is a column.\n separator: \"order-1 my-1 w-0.5 flex-1\",\n fill: \"origin-top scale-y-0\",\n filled: \"scale-y-100\",\n text: \"flex flex-col gap-0.5\",\n },\n} satisfies Record<StepperOrientation, Record<string, string>>;\n\nconst layout = computed(() => LAYOUTS[props.orientation]);\n\n/** The step that last held focus, and so owns the spine's single tab stop. */\nconst focused = ref<number | null>(null);\n\n/**\n * Reka's own focusability rule, mirrored: a linear stepper refuses focus to\n * anything past one step ahead of where the reader is. It has to be repeated\n * rather than read off the DOM, because the tab stop is decided while the\n * `tabindex` attributes are still being rendered — and a tab stop parked on a\n * step Reka will not focus leaves the whole spine unreachable by Tab.\n */\nfunction focusable(step: number, current: number): boolean {\n if (props.steps[step - 1]?.disabled) return false;\n return props.linear ? step <= current + 1 : true;\n}\n\n/**\n * The one step whose trigger is tabbable. Everything else is `tabindex=\"-1\"`.\n *\n * Reka types the value it hands its own slot as possibly absent even though\n * `StepperRoot` defaults it to 1, so the fallback here is that declaration\n * being honoured rather than a state this can reach.\n */\nfunction tabStop(current: number | undefined): number {\n const at = current ?? 1;\n if (focused.value !== null && focusable(focused.value, at)) return focused.value;\n if (focusable(at, at)) return at;\n return props.steps.findIndex((_, index) => focusable(index + 1, at)) + 1;\n}\n\n/**\n * Reka points every trigger's `aria-describedby` at a description id whether\n * or not that description was rendered, and a reference resolving to nothing\n * is worse than no reference: it claims a description exists. Binding the key\n * as `undefined` is what takes it back off, since an attribute set to\n * `undefined` is removed rather than merged.\n */\nfunction describedBy(step: StepperStep): Record<string, undefined> {\n return step.description === undefined ? { \"aria-describedby\": undefined } : {};\n}\n\n/** Reka reports its position as possibly absent; this component's model is a step number or nothing at all. */\nfunction onUpdate(value: number | undefined): void {\n if (value !== undefined) emit(\"update:modelValue\", value);\n}\n</script>\n\n<template>\n <StepperRoot\n v-slot=\"{ modelValue: current }\"\n v-bind=\"{ 'aria-label': text.group, ...rootAttrs, ...optional({ modelValue }) }\"\n data-loom-stepper\n :orientation=\"orientation\"\n :linear=\"linear\"\n :class=\"cn(layout.root, attrs.class as string)\"\n @update:model-value=\"onUpdate\"\n >\n <StepperItem\n v-for=\"(step, index) in steps\"\n :key=\"index\"\n v-slot=\"{ state }\"\n :step=\"index + 1\"\n :disabled=\"step.disabled ?? false\"\n :aria-current=\"undefined\"\n :class=\"layout.item\"\n >\n <div :class=\"layout.rail\">\n <!-- Declared before the trigger so the trigger paints over it: the\n connector runs from this indicator's centre to the next one's. -->\n <StepperSeparator\n v-if=\"index < steps.length - 1\"\n :class=\"cn('overflow-hidden rounded-full bg-border', layout.separator)\"\n >\n <span\n :class=\"\n cn(\n 'block h-full w-full bg-primary transition-transform ease-out',\n layout.fill,\n state === 'completed' && layout.filled,\n )\n \"\n />\n </StepperSeparator>\n\n <StepperTrigger\n v-bind=\"describedBy(step)\"\n :tabindex=\"tabStop(current) === index + 1 ? 0 : -1\"\n :aria-current=\"state === 'active' ? 'step' : undefined\"\n :class=\"\n cn(\n 'relative flex h-8 w-8 shrink-0 items-center justify-center rounded-full border text-xs font-medium',\n 'transition-colors ease-out',\n 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo',\n // Unavailable is a *colour*, and the whole distinction lives on\n // the indicator. It used to be `opacity-50` on the item, which\n // took the title and the description down with it:\n // `--color-muted-foreground` is 5.76:1 on white and 2.11:1 once\n // composited at half alpha, so the one thing that had to stay\n // readable was the one thing the fade broke. A grey-filled disc\n // against the inactive step's white one says the same thing and\n // costs nothing, and every string below is a measured pair.\n //\n // Keyed off the prop and NOT off `data-[disabled]:`, because in\n // a linear flow Reka marks every step past the next one disabled\n // — painting all of them unavailable reads as broken rather than\n // as later, and a step that is merely ahead already says so by\n // being inactive. The branch also keeps the two apart in the\n // cascade: the inactive rules carry an attribute selector, so a\n // plain `bg-muted` alongside them would lose.\n step.disabled\n ? 'border-border-strong bg-muted text-muted-foreground'\n : [\n 'data-[state=inactive]:border-input data-[state=inactive]:bg-background data-[state=inactive]:text-muted-foreground',\n 'data-[state=inactive]:enabled:hover:bg-subtle',\n ],\n 'data-[state=active]:border-primary data-[state=active]:bg-primary-muted data-[state=active]:text-primary-text',\n 'data-[state=completed]:border-primary data-[state=completed]:bg-primary data-[state=completed]:text-primary-foreground',\n 'disabled:cursor-not-allowed',\n )\n \"\n @focus=\"focused = index + 1\"\n >\n <StepperIndicator class=\"flex items-center justify-center\">\n <!-- Three states, none of them colour alone: the check is a shape\n change, the number is text, and the current step carries\n `aria-current` above. -->\n <Check v-if=\"state === 'completed'\" class=\"h-4 w-4 animate-scale-in\" />\n <template v-else>{{ index + 1 }}</template>\n </StepperIndicator>\n </StepperTrigger>\n </div>\n\n <div\n :class=\"cn(layout.text, orientation === 'vertical' && index < steps.length - 1 && 'pb-6')\"\n >\n <!-- `as=\"span\"`, not Reka's default `h4`: a step label is not a\n section heading, and a component cannot know what heading level\n the page it lands in has room for. -->\n <!-- The title mutes rather than fades: `--color-muted-foreground` is a\n measured 5.76:1 on the card it sits on, two steps back from\n `--color-foreground` and still comfortably readable. The\n description below is already that colour and stays there — an\n unreachable step's description is the one line a reader most needs\n in order to find out why it is unreachable. -->\n <StepperTitle\n as=\"span\"\n :class=\"\n cn('text-sm font-medium', step.disabled ? 'text-muted-foreground' : 'text-foreground')\n \"\n >\n <!-- ARIA has a value for \"you are here\" and none for \"done\", and the\n check glyph is invisible to a screen reader. This element is what\n `aria-labelledby` names the trigger with, so the word has to join\n the name from inside it.\n Two nodes rather than the title plus a trailing \"(completed)\"\n span, because a suffix is Loom deciding where a qualifier sits\n relative to the thing it qualifies, and that is a property of the\n language. The visible half is `aria-hidden` and excluded from the\n name computation; the hidden half carries the whole finished\n sentence the vocabulary returned. -->\n <!-- The position leads the name for the same reason: the trigger's\n visible text is the step's number, and WCAG 2.5.3 (Label in\n Name) makes a control's visible text part of its accessible\n name. Measured 2026-08-26, `label-content-name-mismatch` fired\n on every non-completed trigger until the number joined the\n name — a voice user saying \"Step 2\" has to land on the same\n trigger one saying \"Shipping\" does. -->\n <span class=\"sr-only\">{{ text.step({ step: index + 1 }) }}</span>\n <template v-if=\"state === 'completed'\">\n <span aria-hidden=\"true\">{{ step.title }}</span>\n <span class=\"sr-only\">{{ text.completed({ title: step.title }) }}</span>\n </template>\n <template v-else>{{ step.title }}</template>\n </StepperTitle>\n <StepperDescription v-if=\"step.description\" class=\"text-xs text-muted-foreground\">\n {{ step.description }}\n </StepperDescription>\n </div>\n </StepperItem>\n\n <!-- Loom's own position announcement, standing in for the one `StepperRoot`\n renders as a text node its render function hard-codes in English.\n `data-loom-live` is what the rule in `global.css` selects *around* when\n it removes Reka's from the accessibility tree, so the two are told\n apart by what Loom marked rather than by DOM order.\n The count comes from `steps` rather than from Reka's registry, which\n fills in over a tick as each trigger mounts — the same number, one\n render sooner, which matters for a region a screen reader reads on\n arrival. -->\n <span data-loom-live role=\"status\" aria-live=\"polite\" aria-atomic=\"true\" class=\"sr-only\">{{\n text.position({ step: current ?? 1, stepCount: steps.length })\n }}</span>\n </StepperRoot>\n</template>\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { default, STEPPER_LABELS } from "./Stepper.vue";
|
|
2
2
|
export type { StepperStep, StepperOrientation } from "./Stepper.vue";
|
|
3
|
-
export type { StepperLabels } from "
|
|
3
|
+
export type { StepperLabels } from "../../../labels/src/index";
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Switch.js","names":[],"sources":["../../../../../packages/primitives/switch/src/Switch.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { SwitchRoot, SwitchThumb } from \"reka-ui\";\nimport { cn } from \"@ecoma-io/loom-core\";\nimport { useSplitAttrs } from \"@ecoma-io/loom-core\";\nimport { useFieldControl } from \"@ecoma-io/loom-labels\";\n\n/**\n * Switch — toggles a boolean setting that takes effect immediately, with no\n * \"Save\" step. Built on Reka UI's Switch for role=\"switch\" + aria-checked +\n * Space/Enter. Label and description live on the surrounding setting row —\n * wire them in with `aria-labelledby`, since Switch renders a button, not a\n * labelable input.\n *\n * Inside a [Field](../Field/Field.vue) that row is the wrapper itself, and the\n * wiring stops being the caller's job: `useFieldControl()` puts the row's id on\n * the button — labelable, so the row's `<label for>` names the control that has\n * no name of its own — and brings the row's description, `name`, `required` and\n * `invalid` with it.\n *\n * There is no `readonly` here, and a row's is ignored rather than approximated.\n * A switch that cannot be flipped is disabled; one that looks live and refuses\n * the flip is the only state worse than either.\n */\nconst props = withDefaults(\n defineProps<{\n /** Whether the setting is currently on. Omit to let the switch own its own state. */\n modelValue?: boolean | undefined;\n /** Blocks both click and keyboard input, and
|
|
1
|
+
{"version":3,"file":"Switch.js","names":[],"sources":["../../../../../packages/primitives/switch/src/Switch.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { SwitchRoot, SwitchThumb } from \"reka-ui\";\nimport { cn } from \"@ecoma-io/loom-core\";\nimport { useSplitAttrs } from \"@ecoma-io/loom-core\";\nimport { useFieldControl } from \"@ecoma-io/loom-labels\";\n\n/**\n * Switch — toggles a boolean setting that takes effect immediately, with no\n * \"Save\" step. Built on Reka UI's Switch for role=\"switch\" + aria-checked +\n * Space/Enter. Label and description live on the surrounding setting row —\n * wire them in with `aria-labelledby`, since Switch renders a button, not a\n * labelable input.\n *\n * Inside a [Field](../Field/Field.vue) that row is the wrapper itself, and the\n * wiring stops being the caller's job: `useFieldControl()` puts the row's id on\n * the button — labelable, so the row's `<label for>` names the control that has\n * no name of its own — and brings the row's description, `name`, `required` and\n * `invalid` with it.\n *\n * There is no `readonly` here, and a row's is ignored rather than approximated.\n * A switch that cannot be flipped is disabled; one that looks live and refuses\n * the flip is the only state worse than either.\n */\nconst props = withDefaults(\n defineProps<{\n /** Whether the setting is currently on. Omit to let the switch own its own state. */\n modelValue?: boolean | undefined;\n /** Blocks both click and keyboard input, and drains the control to the neutral well. Unset defers to a wrapping Field. */\n disabled?: boolean | undefined;\n }>(),\n {\n // Not `false` — see Checkbox: a concrete default claims host ownership and\n // leaves an unbound switch emitting updates while never moving.\n modelValue: undefined,\n // Not `false` either: absent has to stay tellable from `false` for a Field\n // above to disable the row and for `:disabled=\"false\"` to overrule one that\n // does. Vue casts an absent Boolean prop with no declared default to\n // `false`, which would leave the context wired and inert.\n disabled: undefined,\n },\n);\n\ndefineEmits<{ \"update:modelValue\": [value: boolean] }>();\n\ndefineOptions({ inheritAttrs: false });\nconst { attrs, rest: switchAttrs } = useSplitAttrs();\n\n// One rendered node, so the split is only about `class` — a caller's class\n// needs a Tailwind-aware merge rather than Vue's concatenating fallthrough.\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; `field.attrs` then spreads\n// **after** `switchAttrs`, and that position is the contract (see\n// TextField.vue). `name` in that bag reaches SwitchRoot's own `name` prop,\n// which is what mints the hidden input a `<form>` submits.\n//\n// `name`, `required` and `invalid` are omitted below because Switch has no prop\n// for any of them: the row's answer stands unopposed. `readonly` is omitted for\n// the reason the docblock gives.\n//\n// The resolved `required` then reaches the element through Reka's own prop\n// rather than the `aria-required` in `field.attrs` — see Checkbox.vue, which\n// carries the reasoning. SwitchRoot happens to spread the fallthrough last, so\n// the attribute would win here; going through the prop keeps the four\n// Reka-rooted controls one shape instead of four merge orders to re-derive.\nconst field = useFieldControl(() => ({\n id: attrs.id as string | undefined,\n describedBy: attrs[\"aria-describedby\"] as string | undefined,\n disabled: props.disabled,\n}));\n</script>\n\n<template>\n <SwitchRoot\n v-bind=\"{ modelValue, ...switchAttrs, ...field.attrs }\"\n :disabled=\"field.disabled\"\n :required=\"field.required\"\n :class=\"\n cn(\n 'relative inline-flex h-6 w-10 shrink-0 cursor-pointer items-center rounded-full border border-transparent',\n 'transition-[background-color,filter,box-shadow] duration-instant ease-out',\n 'hover:brightness-95',\n // Checked = a decision (Loom law): the track fills with primary.\n 'data-[state=checked]:bg-primary data-[state=unchecked]:bg-muted-foreground/30',\n // Focus draws the weave tight: the brand ring blooms.\n 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo',\n // Drained, not dimmed. `opacity-50` faded track and thumb together,\n // compositing both below their measured contrast — the same failure\n // Button records for its own dim. The unchecked track falls to\n // `bg-muted`, the well every unavailable control drains to, with the\n // rim Chip slackens to; a *checked* one keeps its primary fill,\n // because switched-on is information (Chip and Pagination keep the\n // wash a selected control already wears) and the native `disabled`\n // attribute carries unavailability to assistive tech regardless.\n // The compound `disabled:data-[state=unchecked]:` form is deliberate:\n // Tailwind sorts data variants after plain `disabled:`, so a bare\n // `disabled:bg-muted` would lose to `data-[state=unchecked]:bg-*` and\n // never fire.\n 'disabled:cursor-not-allowed disabled:data-[state=unchecked]:bg-muted disabled:data-[state=unchecked]:border-border',\n attrs.class as string,\n )\n \"\n @update:model-value=\"$emit('update:modelValue', $event)\"\n >\n <SwitchThumb\n style=\"transition: transform var(--duration-fast) var(--ease-spring)\"\n :class=\"\n cn(\n 'absolute top-1/2 start-0.5 block h-5 w-5 -translate-y-1/2 rounded-full bg-background shadow-sm',\n 'active:scale-x-[1.15] active:scale-y-[0.85]',\n // The anchor is the *inline* start edge, so the off state rests on\n // the reading-order side in every direction — physically left under\n // LTR (pixel-identical to the old `left-0.5`) and right under RTL,\n // where a physical `left` would pin both states to one edge and\n // make the motion read backwards.\n //\n // The travel is still a translate, not an inset change: animating an\n // inset relayouts the track on every frame, while a transform stays\n // on the compositor. Its sign is the one thing direction has left to\n // say — checked moves toward the inline-end edge, +x under LTR, -x\n // under RTL — and it is written through this custom property rather\n // than a second competing utility because Tailwind's `rtl:` wraps in\n // a zero-specificity `:where()`, which would leave the flip's winner\n // to stylesheet order. One rule writes the variable; everything else\n // reads the fallback, so LTR needs no rule at all (and survives even\n // a browser without `:dir()`).\n 'data-[state=checked]:translate-x-[var(--switch-travel-x,1rem)]',\n 'rtl:[--switch-travel-x:-1rem]',\n )\n \"\n />\n </SwitchRoot>\n</template>\n"],"mappings":""}
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
type __VLS_Props = {
|
|
19
19
|
/** Whether the setting is currently on. Omit to let the switch own its own state. */
|
|
20
20
|
modelValue?: boolean | undefined;
|
|
21
|
-
/** Blocks both click and keyboard input, and
|
|
21
|
+
/** Blocks both click and keyboard input, and drains the control to the neutral well. Unset defers to a wrapping Field. */
|
|
22
22
|
disabled?: boolean | undefined;
|
|
23
23
|
};
|
|
24
24
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Switch.vue.d.ts","sourceRoot":"","sources":["../../../../../packages/primitives/switch/src/Switch.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Switch.vue.d.ts","sourceRoot":"","sources":["../../../../../packages/primitives/switch/src/Switch.vue"],"names":[],"mappings":"AA6IA;;;;;;;;;;;;;;;;GAgBG;AACH,KAAK,WAAW,GAAG;IACf,qFAAqF;IACrF,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjC,0HAA0H;IAC1H,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAChC,CAAC;AA8NJ,QAAA,MAAM,YAAY;;;;;cA/NH,OAAO,GAAG,SAAS;gBAFjB,OAAO,GAAG,SAAS;6EAqOlC,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
|
|
@@ -53,12 +53,12 @@ var Switch_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCom
|
|
|
53
53
|
}, {
|
|
54
54
|
disabled: unref(field).disabled,
|
|
55
55
|
required: unref(field).required,
|
|
56
|
-
class: unref(cn)("relative inline-flex h-6 w-10 shrink-0 cursor-pointer items-center rounded-full border border-transparent", "transition-[background-color,filter,box-shadow] duration-instant ease-out", "hover:brightness-95", "data-[state=checked]:bg-primary data-[state=unchecked]:bg-muted-foreground/30", "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo", "disabled:cursor-not-allowed disabled:
|
|
56
|
+
class: unref(cn)("relative inline-flex h-6 w-10 shrink-0 cursor-pointer items-center rounded-full border border-transparent", "transition-[background-color,filter,box-shadow] duration-instant ease-out", "hover:brightness-95", "data-[state=checked]:bg-primary data-[state=unchecked]:bg-muted-foreground/30", "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo", "disabled:cursor-not-allowed disabled:data-[state=unchecked]:bg-muted disabled:data-[state=unchecked]:border-border", unref(attrs).class),
|
|
57
57
|
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => _ctx.$emit("update:modelValue", $event))
|
|
58
58
|
}), {
|
|
59
59
|
default: withCtx(() => [createVNode(unref(SwitchThumb), {
|
|
60
|
-
style: { "transition": "
|
|
61
|
-
class: normalizeClass(unref(cn)("absolute top-1/2
|
|
60
|
+
style: { "transition": "transform var(--duration-fast) var(--ease-spring)" },
|
|
61
|
+
class: normalizeClass(unref(cn)("absolute top-1/2 start-0.5 block h-5 w-5 -translate-y-1/2 rounded-full bg-background shadow-sm", "active:scale-x-[1.15] active:scale-y-[0.85]", "data-[state=checked]:translate-x-[var(--switch-travel-x,1rem)]", "rtl:[--switch-travel-x:-1rem]"))
|
|
62
62
|
}, null, 8, ["class"])]),
|
|
63
63
|
_: 1
|
|
64
64
|
}, 16, [
|
package/dist/packages/primitives/switch/src/Switch.vue_vue_type_script_setup_true_lang.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Switch.vue_vue_type_script_setup_true_lang.js","names":["$emit"],"sources":["../../../../../packages/primitives/switch/src/Switch.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { SwitchRoot, SwitchThumb } from \"reka-ui\";\nimport { cn } from \"@ecoma-io/loom-core\";\nimport { useSplitAttrs } from \"@ecoma-io/loom-core\";\nimport { useFieldControl } from \"@ecoma-io/loom-labels\";\n\n/**\n * Switch — toggles a boolean setting that takes effect immediately, with no\n * \"Save\" step. Built on Reka UI's Switch for role=\"switch\" + aria-checked +\n * Space/Enter. Label and description live on the surrounding setting row —\n * wire them in with `aria-labelledby`, since Switch renders a button, not a\n * labelable input.\n *\n * Inside a [Field](../Field/Field.vue) that row is the wrapper itself, and the\n * wiring stops being the caller's job: `useFieldControl()` puts the row's id on\n * the button — labelable, so the row's `<label for>` names the control that has\n * no name of its own — and brings the row's description, `name`, `required` and\n * `invalid` with it.\n *\n * There is no `readonly` here, and a row's is ignored rather than approximated.\n * A switch that cannot be flipped is disabled; one that looks live and refuses\n * the flip is the only state worse than either.\n */\nconst props = withDefaults(\n defineProps<{\n /** Whether the setting is currently on. Omit to let the switch own its own state. */\n modelValue?: boolean | undefined;\n /** Blocks both click and keyboard input, and
|
|
1
|
+
{"version":3,"file":"Switch.vue_vue_type_script_setup_true_lang.js","names":["$emit"],"sources":["../../../../../packages/primitives/switch/src/Switch.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { SwitchRoot, SwitchThumb } from \"reka-ui\";\nimport { cn } from \"@ecoma-io/loom-core\";\nimport { useSplitAttrs } from \"@ecoma-io/loom-core\";\nimport { useFieldControl } from \"@ecoma-io/loom-labels\";\n\n/**\n * Switch — toggles a boolean setting that takes effect immediately, with no\n * \"Save\" step. Built on Reka UI's Switch for role=\"switch\" + aria-checked +\n * Space/Enter. Label and description live on the surrounding setting row —\n * wire them in with `aria-labelledby`, since Switch renders a button, not a\n * labelable input.\n *\n * Inside a [Field](../Field/Field.vue) that row is the wrapper itself, and the\n * wiring stops being the caller's job: `useFieldControl()` puts the row's id on\n * the button — labelable, so the row's `<label for>` names the control that has\n * no name of its own — and brings the row's description, `name`, `required` and\n * `invalid` with it.\n *\n * There is no `readonly` here, and a row's is ignored rather than approximated.\n * A switch that cannot be flipped is disabled; one that looks live and refuses\n * the flip is the only state worse than either.\n */\nconst props = withDefaults(\n defineProps<{\n /** Whether the setting is currently on. Omit to let the switch own its own state. */\n modelValue?: boolean | undefined;\n /** Blocks both click and keyboard input, and drains the control to the neutral well. Unset defers to a wrapping Field. */\n disabled?: boolean | undefined;\n }>(),\n {\n // Not `false` — see Checkbox: a concrete default claims host ownership and\n // leaves an unbound switch emitting updates while never moving.\n modelValue: undefined,\n // Not `false` either: absent has to stay tellable from `false` for a Field\n // above to disable the row and for `:disabled=\"false\"` to overrule one that\n // does. Vue casts an absent Boolean prop with no declared default to\n // `false`, which would leave the context wired and inert.\n disabled: undefined,\n },\n);\n\ndefineEmits<{ \"update:modelValue\": [value: boolean] }>();\n\ndefineOptions({ inheritAttrs: false });\nconst { attrs, rest: switchAttrs } = useSplitAttrs();\n\n// One rendered node, so the split is only about `class` — a caller's class\n// needs a Tailwind-aware merge rather than Vue's concatenating fallthrough.\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; `field.attrs` then spreads\n// **after** `switchAttrs`, and that position is the contract (see\n// TextField.vue). `name` in that bag reaches SwitchRoot's own `name` prop,\n// which is what mints the hidden input a `<form>` submits.\n//\n// `name`, `required` and `invalid` are omitted below because Switch has no prop\n// for any of them: the row's answer stands unopposed. `readonly` is omitted for\n// the reason the docblock gives.\n//\n// The resolved `required` then reaches the element through Reka's own prop\n// rather than the `aria-required` in `field.attrs` — see Checkbox.vue, which\n// carries the reasoning. SwitchRoot happens to spread the fallthrough last, so\n// the attribute would win here; going through the prop keeps the four\n// Reka-rooted controls one shape instead of four merge orders to re-derive.\nconst field = useFieldControl(() => ({\n id: attrs.id as string | undefined,\n describedBy: attrs[\"aria-describedby\"] as string | undefined,\n disabled: props.disabled,\n}));\n</script>\n\n<template>\n <SwitchRoot\n v-bind=\"{ modelValue, ...switchAttrs, ...field.attrs }\"\n :disabled=\"field.disabled\"\n :required=\"field.required\"\n :class=\"\n cn(\n 'relative inline-flex h-6 w-10 shrink-0 cursor-pointer items-center rounded-full border border-transparent',\n 'transition-[background-color,filter,box-shadow] duration-instant ease-out',\n 'hover:brightness-95',\n // Checked = a decision (Loom law): the track fills with primary.\n 'data-[state=checked]:bg-primary data-[state=unchecked]:bg-muted-foreground/30',\n // Focus draws the weave tight: the brand ring blooms.\n 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo',\n // Drained, not dimmed. `opacity-50` faded track and thumb together,\n // compositing both below their measured contrast — the same failure\n // Button records for its own dim. The unchecked track falls to\n // `bg-muted`, the well every unavailable control drains to, with the\n // rim Chip slackens to; a *checked* one keeps its primary fill,\n // because switched-on is information (Chip and Pagination keep the\n // wash a selected control already wears) and the native `disabled`\n // attribute carries unavailability to assistive tech regardless.\n // The compound `disabled:data-[state=unchecked]:` form is deliberate:\n // Tailwind sorts data variants after plain `disabled:`, so a bare\n // `disabled:bg-muted` would lose to `data-[state=unchecked]:bg-*` and\n // never fire.\n 'disabled:cursor-not-allowed disabled:data-[state=unchecked]:bg-muted disabled:data-[state=unchecked]:border-border',\n attrs.class as string,\n )\n \"\n @update:model-value=\"$emit('update:modelValue', $event)\"\n >\n <SwitchThumb\n style=\"transition: transform var(--duration-fast) var(--ease-spring)\"\n :class=\"\n cn(\n 'absolute top-1/2 start-0.5 block h-5 w-5 -translate-y-1/2 rounded-full bg-background shadow-sm',\n 'active:scale-x-[1.15] active:scale-y-[0.85]',\n // The anchor is the *inline* start edge, so the off state rests on\n // the reading-order side in every direction — physically left under\n // LTR (pixel-identical to the old `left-0.5`) and right under RTL,\n // where a physical `left` would pin both states to one edge and\n // make the motion read backwards.\n //\n // The travel is still a translate, not an inset change: animating an\n // inset relayouts the track on every frame, while a transform stays\n // on the compositor. Its sign is the one thing direction has left to\n // say — checked moves toward the inline-end edge, +x under LTR, -x\n // under RTL — and it is written through this custom property rather\n // than a second competing utility because Tailwind's `rtl:` wraps in\n // a zero-specificity `:where()`, which would leave the flip's winner\n // to stylesheet order. One rule writes the variable; everything else\n // reads the fallback, so LTR needs no rule at all (and survives even\n // a browser without `:dir()`).\n 'data-[state=checked]:translate-x-[var(--switch-travel-x,1rem)]',\n 'rtl:[--switch-travel-x:-1rem]',\n )\n \"\n />\n </SwitchRoot>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuBA,MAAM,QAAQ;EAsBd,MAAM,EAAE,OAAO,MAAM,gBAAgB,cAAc;EAoBnD,MAAM,QAAQ,uBAAuB;GACnC,IAAI,MAAM;GACV,aAAa,MAAM;GACnB,UAAU,MAAM;EAClB,EAAE;;GAIA,OAAA,UAAA,GAAA,YA0Da,MAAA,UAAA,GA1Db,WA0Da;IAAA,YAzDD,QAAA;IAAU,GAAK,MAAA,WAAA;IAAW,GAAK,MAAA,KAAA,CAAK,CAAC;GAAK,GAAA;IACnD,UAAU,MAAA,KAAA,CAAK,CAAC;IAChB,UAAU,MAAA,KAAA,CAAK,CAAC;IAChB,OAAc,MAAA,EAAA,CAAE,CAAA,6GAAA,6EAAA,uBAAA,iFAAA,+GAAA,sHAAqiD,MAAA,KAAA,CAAK,CAAC,KAAA;IAyB3jD,uBAAkB,OAAA,OAAA,OAAA,MAAA,WAAEA,KAAAA,MAAK,qBAAsB,MAAM;;IAEtD,SAAA,cA0BE,CA1BF,YA0BE,MAAA,WAAA,GAAA;KAzBA,OAAA,EAAA,cAAA,oDAAA;KACC,OAAK,eAAW,MAAA,EAAA,CAAE,CAAA,kGAAA,+CAAA,kEAAA,+BAAA,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import Table_vue_vue_type_script_setup_true_lang_default, { TABLE_LABELS } from "./Table.vue_vue_type_script_setup_true_lang.js";
|
|
2
|
+
//#region packages/primitives/table/src/Table.vue
|
|
3
|
+
var Table_default = Table_vue_vue_type_script_setup_true_lang_default;
|
|
4
|
+
//#endregion
|
|
5
|
+
export { TABLE_LABELS, Table_default as default };
|
|
6
|
+
|
|
7
|
+
//# sourceMappingURL=Table.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Table.js","names":[],"sources":["../../../../../packages/primitives/table/src/Table.vue"],"sourcesContent":["<script lang=\"ts\">\nimport type { TableLabels } from \"@ecoma-io/loom-labels\";\n\n/**\n * Loom's English, co-located with the component so it tree-shakes with it,\n * and exported so a host can build a partial vocabulary against the real\n * thing rather than a transcription of it.\n */\nexport const TABLE_LABELS: TableLabels = {\n region: \"Data table\",\n sortedAscending: \"Sorted ascending\",\n sortedDescending: \"Sorted descending\",\n sort: \"Sort\",\n};\n\n/** The wrapper owns row padding so every cell under it tightens together. */\nexport type TableDensity = \"comfortable\" | \"compact\";\n\n/** Alignment vocabulary shared by headers and cells. */\nexport type TableAlign = \"left\" | \"center\" | \"right\";\n</script>\n\n<script setup lang=\"ts\">\nimport { onBeforeUnmount, onMounted, ref } from \"vue\";\nimport { useLabels, type LabelOverrides } from \"@ecoma-io/loom-labels\";\nimport { cn } from \"@ecoma-io/loom-core\";\n\nconst props = withDefaults(\n defineProps<{\n /**\n * The table's caption, rendered as a real `<caption>` — the accessible\n * name for the whole table and the first thing a screen reader says.\n */\n caption?: string;\n /** Row padding. Compact suits dense application chrome. */\n density?: TableDensity;\n /** Names what the table is when no caption fits visually; falls to the labels seam otherwise. */\n labels?: LabelOverrides<TableLabels>;\n }>(),\n { density: \"comfortable\" },\n);\n\n// `text`, not `labels`: the prop of that name is one of the three sources\n// this resolves, and a template reading the raw prop would be reading the\n// overrides rather than the answer.\nconst text = useLabels(\"table\", TABLE_LABELS, () => props.labels);\n\n// The region is focusable only while it can actually scroll: a Tab stop that\n// never moves is a dead one. Overflow is measured, not assumed — tables fit\n// their container most of the time — and re-measured whenever either side of\n// the ratio changes.\nconst region = ref<HTMLElement | null>(null);\nconst table = ref<HTMLElement | null>(null);\nconst scrollable = ref(false);\n\nfunction measure(): void {\n const el = region.value;\n if (el) scrollable.value = el.scrollWidth > el.clientWidth;\n}\n\nlet observer: ResizeObserver | undefined;\nonMounted(() => {\n measure();\n observer = new ResizeObserver(measure);\n if (table.value) observer.observe(table.value);\n window.addEventListener(\"resize\", measure, { passive: true });\n});\nonBeforeUnmount(() => {\n observer?.disconnect();\n window.removeEventListener(\"resize\", measure);\n});\n</script>\n\n<template>\n <!-- A scroll container, not the table itself: wide tables overflow their\n region instead of stretching the page (Loom's content-never-stretches\n law), and the region carries the caption as its accessible name so a\n screen reader announces what this scrollable thing IS before entering.\n Focusable only while it can actually scroll — measured below, since a\n focusable region that never scrolls is a dead Tab stop. -->\n <div\n ref=\"region\"\n role=\"region\"\n :aria-label=\"caption ?? text.region\"\n :tabindex=\"scrollable ? 0 : undefined\"\n class=\"w-full overflow-x-auto rounded-lg focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo\"\n >\n <table\n ref=\"table\"\n :data-density=\"density\"\n :class=\"\n cn(\n 'w-full border-collapse text-left text-sm',\n // Descendant styling is the wrapper's job: writing these per-cell\n // would re-litigate the hairline at every call site.\n '[&_th]:border-b [&_th]:border-border-strong [&_th]:px-3 [&_th]:py-2.5 [&_th]:text-xs [&_th]:font-semibold [&_th]:text-muted-foreground [&_th]:whitespace-nowrap',\n '[&_td]:border-b [&_td]:border-border [&_td]:px-3 [&_td]:align-top [&_td]:text-foreground',\n `[&[data-density='comfortable']_td]:py-3`,\n `[&[data-density='compact']_td]:py-1.5`,\n `[&[data-density='compact']_th]:py-1.5`,\n '[&_tbody_tr:last-child_td]:border-b-0',\n '[&_tfoot_td]:border-t [&_tfoot_td]:border-border-strong [&_tfoot_td]:font-medium',\n )\n \"\n >\n <caption v-if=\"caption\" class=\"sr-only\">\n {{\n caption\n }}\n </caption>\n <!-- @slot Real table markup: `<thead>`/`<tbody>`/`<tfoot>` rows built\n from `TableRow`, `TableHead` and `TableCell`. -->\n <slot />\n </table>\n </div>\n</template>\n"],"mappings":""}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { type LabelOverrides } from "../../../labels/src/index";
|
|
2
|
+
import type { TableLabels } from "../../../labels/src/index";
|
|
3
|
+
/**
|
|
4
|
+
* Loom's English, co-located with the component so it tree-shakes with it,
|
|
5
|
+
* and exported so a host can build a partial vocabulary against the real
|
|
6
|
+
* thing rather than a transcription of it.
|
|
7
|
+
*/
|
|
8
|
+
export declare const TABLE_LABELS: TableLabels;
|
|
9
|
+
/** The wrapper owns row padding so every cell under it tightens together. */
|
|
10
|
+
export type TableDensity = "comfortable" | "compact";
|
|
11
|
+
/** Alignment vocabulary shared by headers and cells. */
|
|
12
|
+
export type TableAlign = "left" | "center" | "right";
|
|
13
|
+
declare const _default: typeof __VLS_export;
|
|
14
|
+
export default _default;
|
|
15
|
+
declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<{
|
|
16
|
+
/**
|
|
17
|
+
* The table's caption, rendered as a real `<caption>` — the accessible
|
|
18
|
+
* name for the whole table and the first thing a screen reader says.
|
|
19
|
+
*/
|
|
20
|
+
caption?: string;
|
|
21
|
+
/** Row padding. Compact suits dense application chrome. */
|
|
22
|
+
density?: TableDensity;
|
|
23
|
+
/** Names what the table is when no caption fits visually; falls to the labels seam otherwise. */
|
|
24
|
+
labels?: LabelOverrides<TableLabels>;
|
|
25
|
+
}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{
|
|
26
|
+
/**
|
|
27
|
+
* The table's caption, rendered as a real `<caption>` — the accessible
|
|
28
|
+
* name for the whole table and the first thing a screen reader says.
|
|
29
|
+
*/
|
|
30
|
+
caption?: string;
|
|
31
|
+
/** Row padding. Compact suits dense application chrome. */
|
|
32
|
+
density?: TableDensity;
|
|
33
|
+
/** Names what the table is when no caption fits visually; falls to the labels seam otherwise. */
|
|
34
|
+
labels?: LabelOverrides<TableLabels>;
|
|
35
|
+
}> & Readonly<{}>, {
|
|
36
|
+
density: TableDensity;
|
|
37
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, {
|
|
38
|
+
default?: (props: {}) => any;
|
|
39
|
+
}>;
|
|
40
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
41
|
+
new (): {
|
|
42
|
+
$slots: S;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=Table.vue.d.ts.map
|