@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/pagination/src/Pagination.vue_vue_type_script_setup_true_lang.js
CHANGED
|
@@ -67,7 +67,7 @@ var Pagination_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defin
|
|
|
67
67
|
const edgeClass = cn(buttonVariants({
|
|
68
68
|
variant: "ghost",
|
|
69
69
|
size: "icon-sm"
|
|
70
|
-
}), "shrink-0 disabled:cursor-not-allowed disabled:
|
|
70
|
+
}), "shrink-0 disabled:cursor-not-allowed disabled:bg-muted disabled:text-muted-foreground disabled:shadow-none");
|
|
71
71
|
function pageClass(selected) {
|
|
72
72
|
return cn(buttonVariants({
|
|
73
73
|
variant: selected ? "primary" : "ghost",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Pagination.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../../../packages/primitives/pagination/src/Pagination.vue"],"sourcesContent":["<script lang=\"ts\">\nimport type { PaginationLabels } from \"@ecoma-io/loom-labels\";\nimport { cva } from \"class-variance-authority\";\n\n/**\n\n/**\n * Loom's English, co-located with the component so it tree-shakes with it: a\n * consumer who never imports Pagination ships none of these bytes.\n *\n * Exported so a host can build a partial vocabulary against the real thing\n * rather than a transcription of it.\n */\nexport const PAGINATION_LABELS: PaginationLabels = {\n nav: \"Pagination\",\n first: \"First page\",\n previous: \"Previous page\",\n next: \"Next page\",\n last: \"Last page\",\n page: ({ page }) => `Page ${String(page)}`,\n position: ({ page, pageCount }) => `Page ${String(page)} of ${String(pageCount)}`,\n ellipsis: \"More pages\",\n};\n\n/**\n * How much of the paging apparatus is rendered. All three drive the same\n * model and carry the same semantics — they differ only in how much room the\n * navigation is worth on the surface it sits on.\n *\n * • `full` — the numbered row with ellipses, plus first/prev/next/last.\n * For a table where jumping to a known page is a real task.\n * • `compact` — prev, \"Page 3 of 12\", next. The position stays legible\n * without spending a whole row on it.\n * • `simple` — prev and next alone, for a feed nobody navigates by index.\n */\nexport type PaginationVariant = \"full\" | \"compact\" | \"simple\";\n\nexport const paginationVariants = cva(\"inline-flex items-center\", {\n // `satisfies` keeps the two halves honest: the union above is the name a\n // consumer imports and the documentation prints, the map below is the\n // classes. Adding a member to one and not the other stops compiling.\n variants: {\n variant: {\n // The numbered row is a run of same-size squares and reads as one strip\n // at gap-1; the compact form is a sentence between two controls and\n // needs the wider gap to stop reading as a third button.\n full: \"gap-1\",\n compact: \"gap-2\",\n simple: \"gap-1\",\n } satisfies Record<PaginationVariant, string>,\n },\n defaultVariants: { variant: \"full\" },\n});\n</script>\n\n<script setup lang=\"ts\">\nimport { nextTick } from \"vue\";\nimport {\n PaginationRoot,\n PaginationList,\n PaginationListItem,\n PaginationFirst,\n PaginationPrev,\n PaginationNext,\n PaginationLast,\n PaginationEllipsis,\n} from \"reka-ui\";\nimport { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight } from \"@lucide/vue\";\nimport { buttonVariants } from \"@ecoma-io/loom-button\";\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 * Pagination — moving through a paged result set, one page at a time or by\n * jumping to a numbered one.\n *\n * It renders **buttons, never links**. Loom cannot know whether a consumer's\n * pages are addressable URLs, and an `<a>` with no `href` is not a link at\n * all — it is a div that lies to a screen reader and drops out of the tab\n * order. A product whose pages are real, crawlable URLs wants its own\n * `<a href>` row instead of this component; nothing here can be made to\n * produce one.\n *\n * Reach for a different control when the list is not paged: an infinite feed\n * wants a \"load more\" button, and a long list a reader scans rather than\n * indexes wants a virtualised scroller.\n *\n * Built on Reka UI's Pagination, which owns the arithmetic — the page count,\n * the sliding window of numbers around the current page, and where the\n * ellipses fall. That window is fiddly enough at the boundaries that\n * recomputing it here would only be a second, subtly different answer.\n */\nconst props = withDefaults(\n defineProps<{\n /**\n * The current page, 1-based. Leave it unset to let the component keep its\n * own page and simply report changes.\n */\n page?: number;\n /** How many items exist in total, across every page. */\n total: number;\n /** How many items one page holds. With `total`, this is what fixes the page count. */\n itemsPerPage?: number;\n /** How much of the control renders: the numbered row, a position readout, or arrows alone. */\n variant?: PaginationVariant;\n /** How many numbers sit either side of the current page, in the `full` variant. */\n siblingCount?: number;\n /** Pins page 1 and the last page into the numbered row, with ellipses standing in for the gap. */\n showEdges?: boolean;\n /** Unavailable: every control dims and refuses to move the page. */\n disabled?: boolean;\n /**\n * Names for everything this control says out loud, as any subset of\n * `PaginationLabels` — the rest stay as the host's `provideLoomLabels`\n * vocabulary left them, and then as Loom's English.\n *\n * This is the per-instance correction, not the place to localise an\n * application: the case it exists for is the two paginations above and\n * below one table, which must not share `labels.nav`.\n */\n labels?: LabelOverrides<PaginationLabels>;\n }>(),\n {\n itemsPerPage: 10,\n variant: \"full\",\n siblingCount: 1,\n // Reka defaults this off, which drops the ellipses entirely and lets the\n // numbered row float free of both ends. The anchored form is what people\n // mean by a full pagination, so Loom turns it on.\n showEdges: true,\n disabled: false,\n },\n);\n\nconst emit = defineEmits<{\n /** The 1-based page the reader asked for. A controlled host decides whether to honour it. */\n \"update:page\": [page: 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(\"pagination\", PAGINATION_LABELS, () => props.labels);\n\n// The root renders the `<nav>`, so every fallthrough attribute belongs on it —\n// there is no second node they could sensibly describe. `class` is pulled out\n// of that spread and merged through `cn()` instead: spreading it alongside the\n// nav's own `:class` only concatenates the two lists, so a caller's `gap-2`\n// would win or lose depending on which utility Tailwind happened to emit last.\ndefineOptions({ inheritAttrs: false });\nconst { attrs, rest: navAttrs } = useSplitAttrs();\n\n// The edge controls keep the dim, and they are the one place in this component\n// where it is still the right answer: their whole content is a chevron marked\n// `aria-hidden`, so there is no text for the alpha to take down with it and the\n// name a screen reader announces is an `aria-label` no paint can reach. WCAG\n// exempts an inactive control from 1.4.11 besides. Prev and First sit disabled\n// on page 1 for as long as a reader is on it, which is the other half of the\n// argument: a faded chevron is the conventional reading of \"no further this\n// way\", where a drained plate would draw the eye to the control that cannot be\n// used.\nconst edgeClass = cn(\n buttonVariants({ variant: \"ghost\", size: \"icon-sm\" }),\n // The edges assert `w-8`, a fixed 32px square, but they sit in a flex row\n // with `flex-shrink: 1` and no min-width, so a row narrower than its content\n // (a phone-width column) collapses them to the 16px chevron — a touch target\n // below WCAG 2.5.8's 24px floor. The page numbers already floor themselves\n // with `min-w-8`; the edges must refuse to shrink instead, leaving the row to\n // overflow rather than ever compressing a control's own target.\n \"shrink-0 disabled:cursor-not-allowed disabled:opacity-50\",\n);\n\n// The page buttons borrow Button's own variants rather than restating its\n// press language, so the row cannot drift from every other pressable thing in\n// the library. `min-w-8` with tabular figures is what keeps the row from\n// reflowing as the numbers under it grow a digit.\nfunction pageClass(selected: boolean): string {\n return cn(\n buttonVariants({ variant: selected ? \"primary\" : \"ghost\", size: \"sm\" }),\n \"min-w-8 px-2 tabular\",\n // No `opacity` here, unlike the edges above, because this button's content\n // *is* text — the page number, the one thing a reader needs from a pager\n // that is briefly out of service. `disabled:opacity-50` composited the\n // ghost variant's `--color-muted-foreground` down to 2.05:1 and the current\n // page's white-on-primary label down to 2.48:1; halving the alpha more than\n // halves the contrast. Unavailability is painted in measured colours\n // instead.\n //\n // The two branches drain to different wells on purpose, which is Chip's\n // rule applied to a row of numbers: an unselected page falls to the neutral\n // well at 4.67:1, and the current page keeps the primary wash it already wears\n // at 6.84:1. Which page a reader is on is information, and a disabled pager\n // that forgets it has answered the question by refusing to answer it.\n selected\n ? \"disabled:cursor-not-allowed disabled:bg-primary-muted disabled:text-primary-text disabled:shadow-none\"\n : \"disabled:cursor-not-allowed disabled:bg-muted disabled:text-muted-foreground\",\n );\n}\n\n/** Which edge control stands in for which, when the one that was pressed goes away. */\nconst MIRROR: Record<string, string | undefined> = {\n first: \"last\",\n prev: \"next\",\n next: \"prev\",\n last: \"first\",\n};\n\n// Reka disables Prev/First at page 1 and Next/Last at the last page, and that\n// is the honest state: a control that looks unavailable and still fires is\n// worse than one that is not there at all. The cost is real, though — a\n// browser blurs a button the instant it becomes disabled, so a reader holding\n// Enter on Next arrives at the last page with focus dumped on `<body>` and\n// their place in the document gone.\n//\n// So the control that fired the change hands focus on: to the current page\n// button where the variant has one — which announces \"Page 12, current page\",\n// the very thing the reader was trying to find out — and to its mirror control\n// otherwise, which is the nearest thing still able to move the page.\n//\n// Only for a keyboard activation. `detail === 0` is what separates a click\n// synthesised by Enter or Space from a pointer click, and a pointer user has\n// no focus position to lose; moving focus for them would raise a ring nobody\n// asked for.\nlet pressed: HTMLButtonElement | null = null;\n\nfunction rememberKeyboardPress(event: MouseEvent): void {\n const target = event.target as HTMLElement | null;\n pressed = event.detail === 0 ? (target?.closest<HTMLButtonElement>(\"button\") ?? null) : null;\n}\n\nfunction handOffFocus(): void {\n const origin = pressed;\n pressed = null;\n if (!origin?.disabled) return;\n\n // Only rescue focus that was actually lost. A browser leaves `<body>`\n // focused after disabling the button; jsdom leaves the button itself. Any\n // other active element means the reader has already moved on, and stealing\n // focus back from them would be the worse bug.\n const active = document.activeElement;\n if (active !== origin && active !== document.body) return;\n\n const nav = origin.closest(\"nav\");\n if (!nav) return;\n\n const mirror = MIRROR[origin.getAttribute(\"data-edge\") ?? \"\"];\n const target =\n nav.querySelector<HTMLButtonElement>('[aria-current=\"page\"]:not([disabled])') ??\n (mirror\n ? nav.querySelector<HTMLButtonElement>(`[data-edge=\"${mirror}\"]:not([disabled])`)\n : null);\n target?.focus();\n}\n\nfunction onPageChange(value: number): void {\n emit(\"update:page\", value);\n // After the re-render rather than before it: the button that was pressed\n // only becomes disabled once the new page has been applied.\n void nextTick(handOffFocus);\n}\n</script>\n\n<template>\n <PaginationRoot\n v-slot=\"{ page: current, pageCount }\"\n v-bind=\"{ ...navAttrs, ...optional({ page }) }\"\n :total=\"total\"\n :items-per-page=\"itemsPerPage\"\n :sibling-count=\"siblingCount\"\n :show-edges=\"showEdges\"\n :disabled=\"disabled\"\n :aria-label=\"text.nav\"\n :class=\"cn(paginationVariants({ variant }), attrs.class as string)\"\n @click=\"rememberKeyboardPress\"\n @update:page=\"onPageChange\"\n >\n <!-- Every `:aria-label` from here down replaces one Reka writes in English\n inside its own render function. It reaches the DOM node as a\n fallthrough attribute, which Vue merges last, so it is a replacement\n rather than a second name. Removing one does not fall back to nothing;\n it falls back to Reka's English, which is the failure this whole seam\n exists to close and which no test of Loom's own strings would catch. -->\n <PaginationFirst\n v-if=\"variant === 'full'\"\n data-edge=\"first\"\n :aria-label=\"text.first\"\n :class=\"edgeClass\"\n >\n <ChevronsLeft class=\"h-4 w-4\" aria-hidden=\"true\" />\n </PaginationFirst>\n\n <PaginationPrev data-edge=\"prev\" :aria-label=\"text.previous\" :class=\"edgeClass\">\n <ChevronLeft class=\"h-4 w-4\" aria-hidden=\"true\" />\n </PaginationPrev>\n\n <PaginationList v-if=\"variant === 'full'\" v-slot=\"{ items }\" class=\"flex items-center gap-1\">\n <!-- Keyed by page number, never by index. The row is furniture: a page\n that stays inside the window across a change keeps its own DOM node,\n so nothing remounts, nothing re-animates, and the numbers do not\n shuffle under a reader who has just pressed Next. -->\n <template\n v-for=\"(item, index) in items\"\n :key=\"item.type === 'page' ? `page-${item.value}` : `ellipsis-${index}`\"\n >\n <PaginationListItem\n v-if=\"item.type === 'page'\"\n :value=\"item.value\"\n :aria-label=\"text.page({ page: item.value })\"\n :class=\"pageClass(item.value === current)\"\n />\n <!-- The ellipsis is not a control, so it renders as a span rather than\n Reka's default div-with-a-glyph inside a row of buttons: nothing to\n focus, nothing that looks pressable, and the glyph itself hidden\n from assistive technology because \"horizontal ellipsis\" is not what\n it means. The words are what it means. -->\n <PaginationEllipsis\n v-else\n as=\"span\"\n class=\"inline-flex h-8 min-w-8 select-none items-center justify-center text-sm text-muted-foreground\"\n >\n <span aria-hidden=\"true\">…</span>\n <span class=\"sr-only\">{{ text.ellipsis }}</span>\n </PaginationEllipsis>\n </template>\n </PaginationList>\n\n <!-- The position, for the two variants that have no numbered row to read it\n off. `role=\"status\"` because pressing Next in those variants otherwise\n changes nothing a screen reader would notice — focus stays put and no\n `aria-current` moves. The `full` variant deliberately has no live\n region: its number row already carries the state, and announcing it\n again on top of the focus hand-off below would say everything twice. -->\n <!-- One string rather than three nodes with the numbers between them: a\n language that puts the count before the word, or drops the preposition\n entirely, cannot reorder markup this component emits. `tabular` moves\n from the two number spans to the whole readout, which is the only real\n cost — the \"of\" between them is now tabular too, and the row of digits\n it was steadying is not rendered in either of these variants. -->\n <span\n v-if=\"variant !== 'full'\"\n role=\"status\"\n :class=\"variant === 'compact' ? 'px-1 text-sm tabular text-muted-foreground' : 'sr-only'\"\n >\n {{ text.position({ page: current, pageCount }) }}\n </span>\n\n <PaginationNext data-edge=\"next\" :aria-label=\"text.next\" :class=\"edgeClass\">\n <ChevronRight class=\"h-4 w-4\" aria-hidden=\"true\" />\n </PaginationNext>\n\n <PaginationLast\n v-if=\"variant === 'full'\"\n data-edge=\"last\"\n :aria-label=\"text.last\"\n :class=\"edgeClass\"\n >\n <ChevronsRight class=\"h-4 w-4\" aria-hidden=\"true\" />\n </PaginationLast>\n </PaginationRoot>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAaA,IAAa,oBAAsC;CACjD,KAAK;CACL,OAAO;CACP,UAAU;CACV,MAAM;CACN,MAAM;CACN,OAAO,EAAE,WAAW,QAAQ,OAAO,IAAI;CACvC,WAAW,EAAE,MAAM,gBAAgB,QAAQ,OAAO,IAAI,EAAE,MAAM,OAAO,SAAS;CAC9E,UAAU;AACZ;AAeA,IAAa,qBAAqB,IAAI,4BAA4B;CAIhE,UAAU,EACR,SAAS;EAIP,MAAM;EACN,SAAS;EACT,QAAQ;CACV,EACF;CACA,iBAAiB,EAAE,SAAS,OAAO;AACrC,CAAC;;;;;;;;;;;;;;;;;;;;;;EA0CD,MAAM,QAAQ;EA0Cd,MAAM,OAAO;EAQb,MAAM,OAAO,UAAU,cAAc,yBAAyB,MAAM,MAAM;EAQ1E,MAAM,EAAE,OAAO,MAAM,aAAa,cAAc;EAWhD,MAAM,YAAY,GAChB,eAAe;GAAE,SAAS;GAAS,MAAM;EAAU,CAAC,GAOpD,0DACF;EAMA,SAAS,UAAU,UAA2B;GAC5C,OAAO,GACL,eAAe;IAAE,SAAS,WAAW,YAAY;IAAS,MAAM;GAAK,CAAC,GACtE,wBAcA,WACI,0GACA,8EACN;EACF;;EAGA,MAAM,SAA6C;GACjD,OAAO;GACP,MAAM;GACN,MAAM;GACN,MAAM;EACR;EAkBA,IAAI,UAAoC;EAExC,SAAS,sBAAsB,OAAyB;GACtD,MAAM,SAAS,MAAM;GACrB,UAAU,MAAM,WAAW,IAAK,QAAQ,QAA2B,QAAQ,KAAK,OAAQ;EAC1F;EAEA,SAAS,eAAqB;GAC5B,MAAM,SAAS;GACf,UAAU;GACV,IAAI,CAAC,QAAQ,UAAU;GAMvB,MAAM,SAAS,SAAS;GACxB,IAAI,WAAW,UAAU,WAAW,SAAS,MAAM;GAEnD,MAAM,MAAM,OAAO,QAAQ,KAAK;GAChC,IAAI,CAAC,KAAK;GAEV,MAAM,SAAS,OAAO,OAAO,aAAa,WAAW,KAAK;GAM1D,CAJE,IAAI,cAAiC,yCAAuC,MAC3E,SACG,IAAI,cAAiC,eAAe,OAAO,mBAAmB,IAC9E,MAAA,EACE,MAAM;EAChB;EAEA,SAAS,aAAa,OAAqB;GACzC,KAAK,eAAe,KAAK;GAGzB,SAAc,YAAY;EAC5B;;GAIE,OAAA,UAAA,GAAA,YA+FiB,MAAA,cAAA,GA/FjB,WA+FiB;IAAA,GA7FF,MAAA,QAAA;IAAQ,GAAK,MAAA,QAAA,CAAQ,CAAA,EAAA,MAAG,QAAA,KAAI,CAAA;GAAA,GAAA;IACxC,OAAO,QAAA;IACP,kBAAgB,QAAA;IAChB,iBAAe,QAAA;IACf,cAAY,QAAA;IACZ,UAAU,QAAA;IACV,cAAY,MAAA,IAAA,CAAI,CAAC;IACjB,OAAO,MAAA,EAAA,CAAE,CAAC,MAAA,kBAAA,CAAkB,CAAA,EAAA,SAAG,QAAA,QAAO,CAAA,GAAK,MAAA,KAAA,CAAK,CAAC,KAAK;IACtD,SAAO;IACP,iBAAa;;IAQd,SAAA,SAOkB,EAAA,MAzBF,SAAS,gBAAS;KAmB1B,QAAA,YAAO,UADf,UAAA,GAAA,YAOkB,MAAA,eAAA,GAAA;;MALhB,aAAU;MACT,cAAY,MAAA,IAAA,CAAI,CAAC;MACjB,OAAK,eAAE,MAAA,SAAA,CAAS;;MAEjB,SAAA,cAAmD,CAAnD,YAAmD,MAAA,YAAA,GAAA;OAArC,OAAM;OAAU,eAAY;;;;KAG5C,YAEiB,MAAA,cAAA,GAAA;MAFD,aAAU;MAAQ,cAAY,MAAA,IAAA,CAAI,CAAC;MAAW,OAAK,eAAE,MAAA,SAAA,CAAS;;MAC5E,SAAA,cAAkD,CAAlD,YAAkD,MAAA,WAAA,GAAA;OAArC,OAAM;OAAU,eAAY;;;;KAGrB,QAAA,YAAO,UAA7B,UAAA,GAAA,YA6BiB,MAAA,cAAA,GAAA;;MA7B4C,OAAM;;MAM/D,SAAA,SAA8B,EANkB,YAAK,EAKvD,UAAA,IAAA,GAAA,mBAuBW,UAAA,MAAA,WAtBe,QAAhB,MAAM,UAAK;OACb,OAAA,UAAA,GAAA,mBAAA,UAAA,EAAA,KAAA,KAAK,SAAI,SAAA,QAAsB,KAAK,UAAK,YAAiB,QAAA,GAAA,CAGxD,KAAK,SAAI,UADjB,UAAA,GAAA,YAKE,MAAA,kBAAA,GAAA;;QAHC,OAAO,KAAK;QACZ,cAAY,MAAA,IAAA,CAAI,CAAC,KAAI,EAAA,MAAS,KAAK,MAAK,CAAA;QACxC,OAAK,eAAE,UAAU,KAAK,UAAU,OAAO,CAAA;;;;;OAO1C,CAAA,MAAA,UAAA,GAAA,YAOqB,MAAA,kBAAA,GAAA;;QALnB,IAAG;QACH,OAAM;;QAEN,SAAA,cAAiC,CAAjC,OAAA,OAAA,OAAA,KAAA,mBAAiC,QAAA,EAA3B,eAAY,OAAM,GAAC,KAAC,EAAA,IAC1B,mBAAgD,QAAhD,YAAgD,gBAAvB,MAAA,IAAA,CAAI,CAAC,QAAQ,GAAA,CAAA,CAAA,CAAA;;;;;;KAkBpC,QAAA,YAAO,UADf,UAAA,GAAA,mBAMO,QAAA;;MAJL,MAAK;MACJ,OAAK,eAAE,QAAA,YAAO,YAAA,+CAAA,SAAA;KAEZ,GAAA,gBAAA,MAAA,IAAA,CAAI,CAAC,SAAQ;MAAA,MAAS;MAAS;KAAS,CAAA,CAAA,GAAA,CAAA,KAAA,mBAAA,IAAA,IAAA;KAG7C,YAEiB,MAAA,cAAA,GAAA;MAFD,aAAU;MAAQ,cAAY,MAAA,IAAA,CAAI,CAAC;MAAO,OAAK,eAAE,MAAA,SAAA,CAAS;;MACxE,SAAA,cAAmD,CAAnD,YAAmD,MAAA,YAAA,GAAA;OAArC,OAAM;OAAU,eAAY;;;;KAIpC,QAAA,YAAO,UADf,UAAA,GAAA,YAOiB,MAAA,cAAA,GAAA;;MALf,aAAU;MACT,cAAY,MAAA,IAAA,CAAI,CAAC;MACjB,OAAK,eAAE,MAAA,SAAA,CAAS;;MAEjB,SAAA,cAAoD,CAApD,YAAoD,MAAA,aAAA,GAAA;OAArC,OAAM;OAAU,eAAY"}
|
|
1
|
+
{"version":3,"file":"Pagination.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../../../packages/primitives/pagination/src/Pagination.vue"],"sourcesContent":["<script lang=\"ts\">\nimport type { PaginationLabels } from \"@ecoma-io/loom-labels\";\nimport { cva } from \"class-variance-authority\";\n\n/**\n\n/**\n * Loom's English, co-located with the component so it tree-shakes with it: a\n * consumer who never imports Pagination ships none of these bytes.\n *\n * Exported so a host can build a partial vocabulary against the real thing\n * rather than a transcription of it.\n */\nexport const PAGINATION_LABELS: PaginationLabels = {\n nav: \"Pagination\",\n first: \"First page\",\n previous: \"Previous page\",\n next: \"Next page\",\n last: \"Last page\",\n page: ({ page }) => `Page ${String(page)}`,\n position: ({ page, pageCount }) => `Page ${String(page)} of ${String(pageCount)}`,\n ellipsis: \"More pages\",\n};\n\n/**\n * How much of the paging apparatus is rendered. All three drive the same\n * model and carry the same semantics — they differ only in how much room the\n * navigation is worth on the surface it sits on.\n *\n * • `full` — the numbered row with ellipses, plus first/prev/next/last.\n * For a table where jumping to a known page is a real task.\n * • `compact` — prev, \"Page 3 of 12\", next. The position stays legible\n * without spending a whole row on it.\n * • `simple` — prev and next alone, for a feed nobody navigates by index.\n */\nexport type PaginationVariant = \"full\" | \"compact\" | \"simple\";\n\nexport const paginationVariants = cva(\"inline-flex items-center\", {\n // `satisfies` keeps the two halves honest: the union above is the name a\n // consumer imports and the documentation prints, the map below is the\n // classes. Adding a member to one and not the other stops compiling.\n variants: {\n variant: {\n // The numbered row is a run of same-size squares and reads as one strip\n // at gap-1; the compact form is a sentence between two controls and\n // needs the wider gap to stop reading as a third button.\n full: \"gap-1\",\n compact: \"gap-2\",\n simple: \"gap-1\",\n } satisfies Record<PaginationVariant, string>,\n },\n defaultVariants: { variant: \"full\" },\n});\n</script>\n\n<script setup lang=\"ts\">\nimport { nextTick } from \"vue\";\nimport {\n PaginationRoot,\n PaginationList,\n PaginationListItem,\n PaginationFirst,\n PaginationPrev,\n PaginationNext,\n PaginationLast,\n PaginationEllipsis,\n} from \"reka-ui\";\nimport { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight } from \"@lucide/vue\";\nimport { buttonVariants } from \"@ecoma-io/loom-button\";\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 * Pagination — moving through a paged result set, one page at a time or by\n * jumping to a numbered one.\n *\n * It renders **buttons, never links**. Loom cannot know whether a consumer's\n * pages are addressable URLs, and an `<a>` with no `href` is not a link at\n * all — it is a div that lies to a screen reader and drops out of the tab\n * order. A product whose pages are real, crawlable URLs wants its own\n * `<a href>` row instead of this component; nothing here can be made to\n * produce one.\n *\n * Reach for a different control when the list is not paged: an infinite feed\n * wants a \"load more\" button, and a long list a reader scans rather than\n * indexes wants a virtualised scroller.\n *\n * Built on Reka UI's Pagination, which owns the arithmetic — the page count,\n * the sliding window of numbers around the current page, and where the\n * ellipses fall. That window is fiddly enough at the boundaries that\n * recomputing it here would only be a second, subtly different answer.\n */\nconst props = withDefaults(\n defineProps<{\n /**\n * The current page, 1-based. Leave it unset to let the component keep its\n * own page and simply report changes.\n */\n page?: number;\n /** How many items exist in total, across every page. */\n total: number;\n /** How many items one page holds. With `total`, this is what fixes the page count. */\n itemsPerPage?: number;\n /** How much of the control renders: the numbered row, a position readout, or arrows alone. */\n variant?: PaginationVariant;\n /** How many numbers sit either side of the current page, in the `full` variant. */\n siblingCount?: number;\n /** Pins page 1 and the last page into the numbered row, with ellipses standing in for the gap. */\n showEdges?: boolean;\n /** Unavailable: every control dims and refuses to move the page. */\n disabled?: boolean;\n /**\n * Names for everything this control says out loud, as any subset of\n * `PaginationLabels` — the rest stay as the host's `provideLoomLabels`\n * vocabulary left them, and then as Loom's English.\n *\n * This is the per-instance correction, not the place to localise an\n * application: the case it exists for is the two paginations above and\n * below one table, which must not share `labels.nav`.\n */\n labels?: LabelOverrides<PaginationLabels>;\n }>(),\n {\n itemsPerPage: 10,\n variant: \"full\",\n siblingCount: 1,\n // Reka defaults this off, which drops the ellipses entirely and lets the\n // numbered row float free of both ends. The anchored form is what people\n // mean by a full pagination, so Loom turns it on.\n showEdges: true,\n disabled: false,\n },\n);\n\nconst emit = defineEmits<{\n /** The 1-based page the reader asked for. A controlled host decides whether to honour it. */\n \"update:page\": [page: 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(\"pagination\", PAGINATION_LABELS, () => props.labels);\n\n// The root renders the `<nav>`, so every fallthrough attribute belongs on it —\n// there is no second node they could sensibly describe. `class` is pulled out\n// of that spread and merged through `cn()` instead: spreading it alongside the\n// nav's own `:class` only concatenates the two lists, so a caller's `gap-2`\n// would win or lose depending on which utility Tailwind happened to emit last.\ndefineOptions({ inheritAttrs: false });\nconst { attrs, rest: navAttrs } = useSplitAttrs();\n\n// The edge controls used to keep the dim on the theory that a chevron has no\n// text for an alpha to take down — but the library-wide rule settled since is\n// drained, not dimmed, full stop: the same well every unavailable control\n// wears, so a disabled pager reads as one treatment rather than two. WCAG\n// exempts an inactive control from 1.4.11 either way; what decides it here is\n// that a drained plate is how \"no further this way\" looks everywhere else in\n// Loom.\nconst edgeClass = cn(\n buttonVariants({ variant: \"ghost\", size: \"icon-sm\" }),\n // The edges assert `w-8`, a fixed 32px square, but they sit in a flex row\n // with `flex-shrink: 1` and no min-width, so a row narrower than its content\n // (a phone-width column) collapses them to the 16px chevron — a touch target\n // below WCAG 2.5.8's 24px floor. The page numbers already floor themselves\n // with `min-w-8`; the edges must refuse to shrink instead, leaving the row to\n // overflow rather than ever compressing a control's own target.\n \"shrink-0 disabled:cursor-not-allowed disabled:bg-muted disabled:text-muted-foreground disabled:shadow-none\",\n);\n\n// The page buttons borrow Button's own variants rather than restating its\n// press language, so the row cannot drift from every other pressable thing in\n// the library. `min-w-8` with tabular figures is what keeps the row from\n// reflowing as the numbers under it grow a digit.\nfunction pageClass(selected: boolean): string {\n return cn(\n buttonVariants({ variant: selected ? \"primary\" : \"ghost\", size: \"sm\" }),\n \"min-w-8 px-2 tabular\",\n // No `opacity` here, unlike the edges above, because this button's content\n // *is* text — the page number, the one thing a reader needs from a pager\n // that is briefly out of service. `disabled:opacity-50` composited the\n // ghost variant's `--color-muted-foreground` down to 2.05:1 and the current\n // page's white-on-primary label down to 2.48:1; halving the alpha more than\n // halves the contrast. Unavailability is painted in measured colours\n // instead.\n //\n // The two branches drain to different wells on purpose, which is Chip's\n // rule applied to a row of numbers: an unselected page falls to the neutral\n // well at 4.67:1, and the current page keeps the primary wash it already wears\n // at 6.84:1. Which page a reader is on is information, and a disabled pager\n // that forgets it has answered the question by refusing to answer it.\n selected\n ? \"disabled:cursor-not-allowed disabled:bg-primary-muted disabled:text-primary-text disabled:shadow-none\"\n : \"disabled:cursor-not-allowed disabled:bg-muted disabled:text-muted-foreground\",\n );\n}\n\n/** Which edge control stands in for which, when the one that was pressed goes away. */\nconst MIRROR: Record<string, string | undefined> = {\n first: \"last\",\n prev: \"next\",\n next: \"prev\",\n last: \"first\",\n};\n\n// Reka disables Prev/First at page 1 and Next/Last at the last page, and that\n// is the honest state: a control that looks unavailable and still fires is\n// worse than one that is not there at all. The cost is real, though — a\n// browser blurs a button the instant it becomes disabled, so a reader holding\n// Enter on Next arrives at the last page with focus dumped on `<body>` and\n// their place in the document gone.\n//\n// So the control that fired the change hands focus on: to the current page\n// button where the variant has one — which announces \"Page 12, current page\",\n// the very thing the reader was trying to find out — and to its mirror control\n// otherwise, which is the nearest thing still able to move the page.\n//\n// Only for a keyboard activation. `detail === 0` is what separates a click\n// synthesised by Enter or Space from a pointer click, and a pointer user has\n// no focus position to lose; moving focus for them would raise a ring nobody\n// asked for.\nlet pressed: HTMLButtonElement | null = null;\n\nfunction rememberKeyboardPress(event: MouseEvent): void {\n const target = event.target as HTMLElement | null;\n pressed = event.detail === 0 ? (target?.closest<HTMLButtonElement>(\"button\") ?? null) : null;\n}\n\nfunction handOffFocus(): void {\n const origin = pressed;\n pressed = null;\n if (!origin?.disabled) return;\n\n // Only rescue focus that was actually lost. A browser leaves `<body>`\n // focused after disabling the button; jsdom leaves the button itself. Any\n // other active element means the reader has already moved on, and stealing\n // focus back from them would be the worse bug.\n const active = document.activeElement;\n if (active !== origin && active !== document.body) return;\n\n const nav = origin.closest(\"nav\");\n if (!nav) return;\n\n const mirror = MIRROR[origin.getAttribute(\"data-edge\") ?? \"\"];\n const target =\n nav.querySelector<HTMLButtonElement>('[aria-current=\"page\"]:not([disabled])') ??\n (mirror\n ? nav.querySelector<HTMLButtonElement>(`[data-edge=\"${mirror}\"]:not([disabled])`)\n : null);\n target?.focus();\n}\n\nfunction onPageChange(value: number): void {\n emit(\"update:page\", value);\n // After the re-render rather than before it: the button that was pressed\n // only becomes disabled once the new page has been applied.\n void nextTick(handOffFocus);\n}\n</script>\n\n<template>\n <PaginationRoot\n v-slot=\"{ page: current, pageCount }\"\n v-bind=\"{ ...navAttrs, ...optional({ page }) }\"\n :total=\"total\"\n :items-per-page=\"itemsPerPage\"\n :sibling-count=\"siblingCount\"\n :show-edges=\"showEdges\"\n :disabled=\"disabled\"\n :aria-label=\"text.nav\"\n :class=\"cn(paginationVariants({ variant }), attrs.class as string)\"\n @click=\"rememberKeyboardPress\"\n @update:page=\"onPageChange\"\n >\n <!-- Every `:aria-label` from here down replaces one Reka writes in English\n inside its own render function. It reaches the DOM node as a\n fallthrough attribute, which Vue merges last, so it is a replacement\n rather than a second name. Removing one does not fall back to nothing;\n it falls back to Reka's English, which is the failure this whole seam\n exists to close and which no test of Loom's own strings would catch. -->\n <PaginationFirst\n v-if=\"variant === 'full'\"\n data-edge=\"first\"\n :aria-label=\"text.first\"\n :class=\"edgeClass\"\n >\n <ChevronsLeft class=\"h-4 w-4\" aria-hidden=\"true\" />\n </PaginationFirst>\n\n <PaginationPrev data-edge=\"prev\" :aria-label=\"text.previous\" :class=\"edgeClass\">\n <ChevronLeft class=\"h-4 w-4\" aria-hidden=\"true\" />\n </PaginationPrev>\n\n <PaginationList v-if=\"variant === 'full'\" v-slot=\"{ items }\" class=\"flex items-center gap-1\">\n <!-- Keyed by page number, never by index. The row is furniture: a page\n that stays inside the window across a change keeps its own DOM node,\n so nothing remounts, nothing re-animates, and the numbers do not\n shuffle under a reader who has just pressed Next. -->\n <template\n v-for=\"(item, index) in items\"\n :key=\"item.type === 'page' ? `page-${item.value}` : `ellipsis-${index}`\"\n >\n <PaginationListItem\n v-if=\"item.type === 'page'\"\n :value=\"item.value\"\n :aria-label=\"text.page({ page: item.value })\"\n :class=\"pageClass(item.value === current)\"\n />\n <!-- The ellipsis is not a control, so it renders as a span rather than\n Reka's default div-with-a-glyph inside a row of buttons: nothing to\n focus, nothing that looks pressable, and the glyph itself hidden\n from assistive technology because \"horizontal ellipsis\" is not what\n it means. The words are what it means. -->\n <PaginationEllipsis\n v-else\n as=\"span\"\n class=\"inline-flex h-8 min-w-8 select-none items-center justify-center text-sm text-muted-foreground\"\n >\n <span aria-hidden=\"true\">…</span>\n <span class=\"sr-only\">{{ text.ellipsis }}</span>\n </PaginationEllipsis>\n </template>\n </PaginationList>\n\n <!-- The position, for the two variants that have no numbered row to read it\n off. `role=\"status\"` because pressing Next in those variants otherwise\n changes nothing a screen reader would notice — focus stays put and no\n `aria-current` moves. The `full` variant deliberately has no live\n region: its number row already carries the state, and announcing it\n again on top of the focus hand-off below would say everything twice. -->\n <!-- One string rather than three nodes with the numbers between them: a\n language that puts the count before the word, or drops the preposition\n entirely, cannot reorder markup this component emits. `tabular` moves\n from the two number spans to the whole readout, which is the only real\n cost — the \"of\" between them is now tabular too, and the row of digits\n it was steadying is not rendered in either of these variants. -->\n <span\n v-if=\"variant !== 'full'\"\n role=\"status\"\n :class=\"variant === 'compact' ? 'px-1 text-sm tabular text-muted-foreground' : 'sr-only'\"\n >\n {{ text.position({ page: current, pageCount }) }}\n </span>\n\n <PaginationNext data-edge=\"next\" :aria-label=\"text.next\" :class=\"edgeClass\">\n <ChevronRight class=\"h-4 w-4\" aria-hidden=\"true\" />\n </PaginationNext>\n\n <PaginationLast\n v-if=\"variant === 'full'\"\n data-edge=\"last\"\n :aria-label=\"text.last\"\n :class=\"edgeClass\"\n >\n <ChevronsRight class=\"h-4 w-4\" aria-hidden=\"true\" />\n </PaginationLast>\n </PaginationRoot>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAaA,IAAa,oBAAsC;CACjD,KAAK;CACL,OAAO;CACP,UAAU;CACV,MAAM;CACN,MAAM;CACN,OAAO,EAAE,WAAW,QAAQ,OAAO,IAAI;CACvC,WAAW,EAAE,MAAM,gBAAgB,QAAQ,OAAO,IAAI,EAAE,MAAM,OAAO,SAAS;CAC9E,UAAU;AACZ;AAeA,IAAa,qBAAqB,IAAI,4BAA4B;CAIhE,UAAU,EACR,SAAS;EAIP,MAAM;EACN,SAAS;EACT,QAAQ;CACV,EACF;CACA,iBAAiB,EAAE,SAAS,OAAO;AACrC,CAAC;;;;;;;;;;;;;;;;;;;;;;EA0CD,MAAM,QAAQ;EA0Cd,MAAM,OAAO;EAQb,MAAM,OAAO,UAAU,cAAc,yBAAyB,MAAM,MAAM;EAQ1E,MAAM,EAAE,OAAO,MAAM,aAAa,cAAc;EAShD,MAAM,YAAY,GAChB,eAAe;GAAE,SAAS;GAAS,MAAM;EAAU,CAAC,GAOpD,4GACF;EAMA,SAAS,UAAU,UAA2B;GAC5C,OAAO,GACL,eAAe;IAAE,SAAS,WAAW,YAAY;IAAS,MAAM;GAAK,CAAC,GACtE,wBAcA,WACI,0GACA,8EACN;EACF;;EAGA,MAAM,SAA6C;GACjD,OAAO;GACP,MAAM;GACN,MAAM;GACN,MAAM;EACR;EAkBA,IAAI,UAAoC;EAExC,SAAS,sBAAsB,OAAyB;GACtD,MAAM,SAAS,MAAM;GACrB,UAAU,MAAM,WAAW,IAAK,QAAQ,QAA2B,QAAQ,KAAK,OAAQ;EAC1F;EAEA,SAAS,eAAqB;GAC5B,MAAM,SAAS;GACf,UAAU;GACV,IAAI,CAAC,QAAQ,UAAU;GAMvB,MAAM,SAAS,SAAS;GACxB,IAAI,WAAW,UAAU,WAAW,SAAS,MAAM;GAEnD,MAAM,MAAM,OAAO,QAAQ,KAAK;GAChC,IAAI,CAAC,KAAK;GAEV,MAAM,SAAS,OAAO,OAAO,aAAa,WAAW,KAAK;GAM1D,CAJE,IAAI,cAAiC,yCAAuC,MAC3E,SACG,IAAI,cAAiC,eAAe,OAAO,mBAAmB,IAC9E,MAAA,EACE,MAAM;EAChB;EAEA,SAAS,aAAa,OAAqB;GACzC,KAAK,eAAe,KAAK;GAGzB,SAAc,YAAY;EAC5B;;GAIE,OAAA,UAAA,GAAA,YA+FiB,MAAA,cAAA,GA/FjB,WA+FiB;IAAA,GA7FF,MAAA,QAAA;IAAQ,GAAK,MAAA,QAAA,CAAQ,CAAA,EAAA,MAAG,QAAA,KAAI,CAAA;GAAA,GAAA;IACxC,OAAO,QAAA;IACP,kBAAgB,QAAA;IAChB,iBAAe,QAAA;IACf,cAAY,QAAA;IACZ,UAAU,QAAA;IACV,cAAY,MAAA,IAAA,CAAI,CAAC;IACjB,OAAO,MAAA,EAAA,CAAE,CAAC,MAAA,kBAAA,CAAkB,CAAA,EAAA,SAAG,QAAA,QAAO,CAAA,GAAK,MAAA,KAAA,CAAK,CAAC,KAAK;IACtD,SAAO;IACP,iBAAa;;IAQd,SAAA,SAOkB,EAAA,MAzBF,SAAS,gBAAS;KAmB1B,QAAA,YAAO,UADf,UAAA,GAAA,YAOkB,MAAA,eAAA,GAAA;;MALhB,aAAU;MACT,cAAY,MAAA,IAAA,CAAI,CAAC;MACjB,OAAK,eAAE,MAAA,SAAA,CAAS;;MAEjB,SAAA,cAAmD,CAAnD,YAAmD,MAAA,YAAA,GAAA;OAArC,OAAM;OAAU,eAAY;;;;KAG5C,YAEiB,MAAA,cAAA,GAAA;MAFD,aAAU;MAAQ,cAAY,MAAA,IAAA,CAAI,CAAC;MAAW,OAAK,eAAE,MAAA,SAAA,CAAS;;MAC5E,SAAA,cAAkD,CAAlD,YAAkD,MAAA,WAAA,GAAA;OAArC,OAAM;OAAU,eAAY;;;;KAGrB,QAAA,YAAO,UAA7B,UAAA,GAAA,YA6BiB,MAAA,cAAA,GAAA;;MA7B4C,OAAM;;MAM/D,SAAA,SAA8B,EANkB,YAAK,EAKvD,UAAA,IAAA,GAAA,mBAuBW,UAAA,MAAA,WAtBe,QAAhB,MAAM,UAAK;OACb,OAAA,UAAA,GAAA,mBAAA,UAAA,EAAA,KAAA,KAAK,SAAI,SAAA,QAAsB,KAAK,UAAK,YAAiB,QAAA,GAAA,CAGxD,KAAK,SAAI,UADjB,UAAA,GAAA,YAKE,MAAA,kBAAA,GAAA;;QAHC,OAAO,KAAK;QACZ,cAAY,MAAA,IAAA,CAAI,CAAC,KAAI,EAAA,MAAS,KAAK,MAAK,CAAA;QACxC,OAAK,eAAE,UAAU,KAAK,UAAU,OAAO,CAAA;;;;;OAO1C,CAAA,MAAA,UAAA,GAAA,YAOqB,MAAA,kBAAA,GAAA;;QALnB,IAAG;QACH,OAAM;;QAEN,SAAA,cAAiC,CAAjC,OAAA,OAAA,OAAA,KAAA,mBAAiC,QAAA,EAA3B,eAAY,OAAM,GAAC,KAAC,EAAA,IAC1B,mBAAgD,QAAhD,YAAgD,gBAAvB,MAAA,IAAA,CAAI,CAAC,QAAQ,GAAA,CAAA,CAAA,CAAA;;;;;;KAkBpC,QAAA,YAAO,UADf,UAAA,GAAA,mBAMO,QAAA;;MAJL,MAAK;MACJ,OAAK,eAAE,QAAA,YAAO,YAAA,+CAAA,SAAA;KAEZ,GAAA,gBAAA,MAAA,IAAA,CAAI,CAAC,SAAQ;MAAA,MAAS;MAAS;KAAS,CAAA,CAAA,GAAA,CAAA,KAAA,mBAAA,IAAA,IAAA;KAG7C,YAEiB,MAAA,cAAA,GAAA;MAFD,aAAU;MAAQ,cAAY,MAAA,IAAA,CAAI,CAAC;MAAO,OAAK,eAAE,MAAA,SAAA,CAAS;;MACxE,SAAA,cAAmD,CAAnD,YAAmD,MAAA,YAAA,GAAA;OAArC,OAAM;OAAU,eAAY;;;;KAIpC,QAAA,YAAO,UADf,UAAA,GAAA,YAOiB,MAAA,cAAA,GAAA;;MALf,aAAU;MACT,cAAY,MAAA,IAAA,CAAI,CAAC;MACjB,OAAK,eAAE,MAAA,SAAA,CAAS;;MAEjB,SAAA,cAAoD,CAApD,YAAoD,MAAA,aAAA,GAAA;OAArC,OAAM;OAAU,eAAY"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { default, paginationVariants, PAGINATION_LABELS } from "./Pagination.vue";
|
|
2
2
|
export type { PaginationVariant } from "./Pagination.vue";
|
|
3
|
-
export type { PaginationLabels } from "
|
|
3
|
+
export type { PaginationLabels } from "../../../labels/src/index";
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Popover.js","names":[],"sources":["../../../../../packages/primitives/popover/src/Popover.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Which edge of the trigger the panel prefers. It is a preference and not a\n * guarantee: Reka flips the panel to the opposite edge when it would collide\n * with the viewport, which is why a caller sets the side it *wants* rather\n * than the side it will get.\n *\n * The members mirror Reka's own `Side`. Nothing enforces that in this\n * declaration — the template binding does: give this union a member Reka does\n * not accept and `:side=\"side\"` stops type-checking. Declaring it here rather\n * than aliasing `PopoverContentProps[\"side\"]` is what puts the four values in\n * the generated props table, because the documentation reads syntax and an\n * indexed access type has none to read.\n */\nexport type PopoverSide = \"top\" | \"right\" | \"bottom\" | \"left\";\n\n/** Where the panel sits along that edge. */\nexport type PopoverAlign = \"start\" | \"center\" | \"end\";\n</script>\n\n<script setup lang=\"ts\">\nimport { PopoverRoot, PopoverTrigger, PopoverPortal, PopoverContent, PopoverArrow } from \"reka-ui\";\nimport { cn } from \"@ecoma-io/loom-core\";\nimport { optional } from \"@ecoma-io/loom-core\";\n\n/**\n * Popover — a floating panel anchored to a trigger, carrying secondary content\n * the user opts into: a filter set, a colour picker, a details card.\n *\n * The escape contract, which is the whole reason to reach for an overlay\n * primitive rather than an absolutely positioned div: opening moves focus into\n * the panel, Esc and an outside click both close it, closing returns focus to\n * the trigger, and the page behind keeps scrolling because a popover is not\n * modal. Focus is *not* trapped — Tab leaves the panel, which is correct for\n * content the user can walk past. `Dialog` is the one that traps.\n *\n * Reach for `DropdownMenu` when the panel is a list of commands, `Tooltip` for\n * a hint that must not take focus at all, and `Dialog` when the task has to\n * block the rest of the UI.\n */\nwithDefaults(\n defineProps<{\n /** Drive the panel from the host with `v-model:open`; omit it and the popover owns its own state. */\n open?: boolean | undefined;\n /** The edge of the trigger to anchor against, before collision flipping. */\n side?: PopoverSide;\n /** Where the panel sits along that edge — `start` keeps its leading edge flush with the trigger's. */\n align?: PopoverAlign;\n /** Gap in pixels between the trigger and the panel. */\n sideOffset?: number;\n /** Draw the pointer notch. Turn it off where the panel reads better flush against its trigger. */\n arrow?: boolean;\n }>(),\n // `open: undefined` is load-bearing, not a redundant default — it is what\n // keeps the uncontrolled third state reachable past Vue's absent-Boolean\n // casting. `optional()` in the template is the other half; its docblock\n // carries the reasoning for both.\n { open: undefined, side: \"bottom\", align: \"center\", sideOffset: 6, arrow: true },\n);\n\ndefineEmits<{ \"update:open\": [value: boolean] }>();\n</script>\n\n<template>\n <PopoverRoot v-bind=\"optional({ open })\" @update:open=\"$emit('update:open', $event)\">\n <!-- @slot The control that opens the panel. Rendered `as-child`, so the\n caller's own element *is* the trigger and no wrapper swallows its\n accessible name. -->\n <PopoverTrigger as-child>\n <slot name=\"trigger\" />\n </PopoverTrigger>\n\n <PopoverPortal>\n <PopoverContent\n :side=\"side\"\n :align=\"align\"\n :side-offset=\"sideOffset\"\n :class=\"\n cn(\n 'z-
|
|
1
|
+
{"version":3,"file":"Popover.js","names":[],"sources":["../../../../../packages/primitives/popover/src/Popover.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Which edge of the trigger the panel prefers. It is a preference and not a\n * guarantee: Reka flips the panel to the opposite edge when it would collide\n * with the viewport, which is why a caller sets the side it *wants* rather\n * than the side it will get.\n *\n * The members mirror Reka's own `Side`. Nothing enforces that in this\n * declaration — the template binding does: give this union a member Reka does\n * not accept and `:side=\"side\"` stops type-checking. Declaring it here rather\n * than aliasing `PopoverContentProps[\"side\"]` is what puts the four values in\n * the generated props table, because the documentation reads syntax and an\n * indexed access type has none to read.\n */\nexport type PopoverSide = \"top\" | \"right\" | \"bottom\" | \"left\";\n\n/** Where the panel sits along that edge. */\nexport type PopoverAlign = \"start\" | \"center\" | \"end\";\n</script>\n\n<script setup lang=\"ts\">\nimport { PopoverRoot, PopoverTrigger, PopoverPortal, PopoverContent, PopoverArrow } from \"reka-ui\";\nimport { cn } from \"@ecoma-io/loom-core\";\nimport { optional } from \"@ecoma-io/loom-core\";\n\n/**\n * Popover — a floating panel anchored to a trigger, carrying secondary content\n * the user opts into: a filter set, a colour picker, a details card.\n *\n * The escape contract, which is the whole reason to reach for an overlay\n * primitive rather than an absolutely positioned div: opening moves focus into\n * the panel, Esc and an outside click both close it, closing returns focus to\n * the trigger, and the page behind keeps scrolling because a popover is not\n * modal. Focus is *not* trapped — Tab leaves the panel, which is correct for\n * content the user can walk past. `Dialog` is the one that traps.\n *\n * Reach for `DropdownMenu` when the panel is a list of commands, `Tooltip` for\n * a hint that must not take focus at all, and `Dialog` when the task has to\n * block the rest of the UI.\n */\nwithDefaults(\n defineProps<{\n /** Drive the panel from the host with `v-model:open`; omit it and the popover owns its own state. */\n open?: boolean | undefined;\n /** The edge of the trigger to anchor against, before collision flipping. */\n side?: PopoverSide;\n /** Where the panel sits along that edge — `start` keeps its leading edge flush with the trigger's. */\n align?: PopoverAlign;\n /** Gap in pixels between the trigger and the panel. */\n sideOffset?: number;\n /** Draw the pointer notch. Turn it off where the panel reads better flush against its trigger. */\n arrow?: boolean;\n }>(),\n // `open: undefined` is load-bearing, not a redundant default — it is what\n // keeps the uncontrolled third state reachable past Vue's absent-Boolean\n // casting. `optional()` in the template is the other half; its docblock\n // carries the reasoning for both.\n { open: undefined, side: \"bottom\", align: \"center\", sideOffset: 6, arrow: true },\n);\n\ndefineEmits<{ \"update:open\": [value: boolean] }>();\n</script>\n\n<template>\n <PopoverRoot v-bind=\"optional({ open })\" @update:open=\"$emit('update:open', $event)\">\n <!-- @slot The control that opens the panel. Rendered `as-child`, so the\n caller's own element *is* the trigger and no wrapper swallows its\n accessible name. -->\n <PopoverTrigger as-child>\n <slot name=\"trigger\" />\n </PopoverTrigger>\n\n <PopoverPortal>\n <PopoverContent\n :side=\"side\"\n :align=\"align\"\n :side-offset=\"sideOffset\"\n :class=\"\n cn(\n 'z-overlay min-w-[12rem] max-w-[min(90vw,22rem)] rounded-md border border-border bg-popover p-3 text-sm text-popover-foreground shadow-md outline-none',\n // Both states scoped, never unconditional. Reka's Presence\n // keeps closed content mounted until an animationend arrives, and a\n // mount-only animation never fires a second one — so an\n // unconditional animation class strands an invisible panel over the\n // page, swallowing clicks. Scoped, the closed element computes\n // `animation-name: none` and Presence takes its immediate-unmount\n // branch instead; the paired exit is precisely what Presence is\n // waiting to hold it for. The origin below is what makes that scale\n // grow out of the trigger rather than out of the panel's own\n // centre — on the way out as well as in.\n 'data-[state=open]:animate-scale-in data-[state=closed]:animate-scale-out',\n )\n \"\n style=\"transform-origin: var(--reka-popper-transform-origin)\"\n >\n <!-- @slot The panel body. -->\n <slot />\n <PopoverArrow v-if=\"arrow\" class=\"fill-popover\" :width=\"12\" :height=\"6\" />\n </PopoverContent>\n </PopoverPortal>\n </PopoverRoot>\n</template>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Popover.vue.d.ts","sourceRoot":"","sources":["../../../../../packages/primitives/popover/src/Popover.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Popover.vue.d.ts","sourceRoot":"","sources":["../../../../../packages/primitives/popover/src/Popover.vue"],"names":[],"mappings":"AA8GA;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE9D,4CAA4C;AAC5C,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;wBACjC,OAAO,YAAY;AAAxC,wBAAyC;AACzC,QAAA,MAAM,YAAY;IAiBd,qGAAqG;WAC9F,OAAO,GAAG,SAAS;IAC1B,4EAA4E;WACrE,WAAW;IAClB,sGAAsG;YAC9F,YAAY;IACpB,uDAAuD;iBAC1C,MAAM;IACnB,kGAAkG;YAC1F,OAAO;;;;IATf,qGAAqG;WAC9F,OAAO,GAAG,SAAS;IAC1B,4EAA4E;WACrE,WAAW;IAClB,sGAAsG;YAC9F,YAAY;IACpB,uDAAuD;iBAC1C,MAAM;IACnB,kGAAkG;YAC1F,OAAO;;;;UANR,WAAW;gBAIL,MAAM;WAFX,YAAY;UAJb,OAAO,GAAG,SAAS;WAQlB,OAAO;;cAyKL,CAAC,KAAK,IAAiB,KAAK,GAAG;;cAC/B,CAAC,KAAK,IAAiB,KAAK,GAAG;EAWzC,CAAC;AAWL,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
|
|
@@ -31,7 +31,7 @@ var Popover_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCo
|
|
|
31
31
|
side: __props.side,
|
|
32
32
|
align: __props.align,
|
|
33
33
|
"side-offset": __props.sideOffset,
|
|
34
|
-
class: normalizeClass(unref(cn)("z-
|
|
34
|
+
class: normalizeClass(unref(cn)("z-overlay min-w-[12rem] max-w-[min(90vw,22rem)] rounded-md border border-border bg-popover p-3 text-sm text-popover-foreground shadow-md outline-none", "data-[state=open]:animate-scale-in data-[state=closed]:animate-scale-out")),
|
|
35
35
|
style: { "transform-origin": "var(--reka-popper-transform-origin)" }
|
|
36
36
|
}, {
|
|
37
37
|
default: withCtx(() => [renderSlot(_ctx.$slots, "default"), __props.arrow ? (openBlock(), createBlock(unref(PopoverArrow), {
|
package/dist/packages/primitives/popover/src/Popover.vue_vue_type_script_setup_true_lang.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Popover.vue_vue_type_script_setup_true_lang.js","names":["$emit"],"sources":["../../../../../packages/primitives/popover/src/Popover.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Which edge of the trigger the panel prefers. It is a preference and not a\n * guarantee: Reka flips the panel to the opposite edge when it would collide\n * with the viewport, which is why a caller sets the side it *wants* rather\n * than the side it will get.\n *\n * The members mirror Reka's own `Side`. Nothing enforces that in this\n * declaration — the template binding does: give this union a member Reka does\n * not accept and `:side=\"side\"` stops type-checking. Declaring it here rather\n * than aliasing `PopoverContentProps[\"side\"]` is what puts the four values in\n * the generated props table, because the documentation reads syntax and an\n * indexed access type has none to read.\n */\nexport type PopoverSide = \"top\" | \"right\" | \"bottom\" | \"left\";\n\n/** Where the panel sits along that edge. */\nexport type PopoverAlign = \"start\" | \"center\" | \"end\";\n</script>\n\n<script setup lang=\"ts\">\nimport { PopoverRoot, PopoverTrigger, PopoverPortal, PopoverContent, PopoverArrow } from \"reka-ui\";\nimport { cn } from \"@ecoma-io/loom-core\";\nimport { optional } from \"@ecoma-io/loom-core\";\n\n/**\n * Popover — a floating panel anchored to a trigger, carrying secondary content\n * the user opts into: a filter set, a colour picker, a details card.\n *\n * The escape contract, which is the whole reason to reach for an overlay\n * primitive rather than an absolutely positioned div: opening moves focus into\n * the panel, Esc and an outside click both close it, closing returns focus to\n * the trigger, and the page behind keeps scrolling because a popover is not\n * modal. Focus is *not* trapped — Tab leaves the panel, which is correct for\n * content the user can walk past. `Dialog` is the one that traps.\n *\n * Reach for `DropdownMenu` when the panel is a list of commands, `Tooltip` for\n * a hint that must not take focus at all, and `Dialog` when the task has to\n * block the rest of the UI.\n */\nwithDefaults(\n defineProps<{\n /** Drive the panel from the host with `v-model:open`; omit it and the popover owns its own state. */\n open?: boolean | undefined;\n /** The edge of the trigger to anchor against, before collision flipping. */\n side?: PopoverSide;\n /** Where the panel sits along that edge — `start` keeps its leading edge flush with the trigger's. */\n align?: PopoverAlign;\n /** Gap in pixels between the trigger and the panel. */\n sideOffset?: number;\n /** Draw the pointer notch. Turn it off where the panel reads better flush against its trigger. */\n arrow?: boolean;\n }>(),\n // `open: undefined` is load-bearing, not a redundant default — it is what\n // keeps the uncontrolled third state reachable past Vue's absent-Boolean\n // casting. `optional()` in the template is the other half; its docblock\n // carries the reasoning for both.\n { open: undefined, side: \"bottom\", align: \"center\", sideOffset: 6, arrow: true },\n);\n\ndefineEmits<{ \"update:open\": [value: boolean] }>();\n</script>\n\n<template>\n <PopoverRoot v-bind=\"optional({ open })\" @update:open=\"$emit('update:open', $event)\">\n <!-- @slot The control that opens the panel. Rendered `as-child`, so the\n caller's own element *is* the trigger and no wrapper swallows its\n accessible name. -->\n <PopoverTrigger as-child>\n <slot name=\"trigger\" />\n </PopoverTrigger>\n\n <PopoverPortal>\n <PopoverContent\n :side=\"side\"\n :align=\"align\"\n :side-offset=\"sideOffset\"\n :class=\"\n cn(\n 'z-
|
|
1
|
+
{"version":3,"file":"Popover.vue_vue_type_script_setup_true_lang.js","names":["$emit"],"sources":["../../../../../packages/primitives/popover/src/Popover.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Which edge of the trigger the panel prefers. It is a preference and not a\n * guarantee: Reka flips the panel to the opposite edge when it would collide\n * with the viewport, which is why a caller sets the side it *wants* rather\n * than the side it will get.\n *\n * The members mirror Reka's own `Side`. Nothing enforces that in this\n * declaration — the template binding does: give this union a member Reka does\n * not accept and `:side=\"side\"` stops type-checking. Declaring it here rather\n * than aliasing `PopoverContentProps[\"side\"]` is what puts the four values in\n * the generated props table, because the documentation reads syntax and an\n * indexed access type has none to read.\n */\nexport type PopoverSide = \"top\" | \"right\" | \"bottom\" | \"left\";\n\n/** Where the panel sits along that edge. */\nexport type PopoverAlign = \"start\" | \"center\" | \"end\";\n</script>\n\n<script setup lang=\"ts\">\nimport { PopoverRoot, PopoverTrigger, PopoverPortal, PopoverContent, PopoverArrow } from \"reka-ui\";\nimport { cn } from \"@ecoma-io/loom-core\";\nimport { optional } from \"@ecoma-io/loom-core\";\n\n/**\n * Popover — a floating panel anchored to a trigger, carrying secondary content\n * the user opts into: a filter set, a colour picker, a details card.\n *\n * The escape contract, which is the whole reason to reach for an overlay\n * primitive rather than an absolutely positioned div: opening moves focus into\n * the panel, Esc and an outside click both close it, closing returns focus to\n * the trigger, and the page behind keeps scrolling because a popover is not\n * modal. Focus is *not* trapped — Tab leaves the panel, which is correct for\n * content the user can walk past. `Dialog` is the one that traps.\n *\n * Reach for `DropdownMenu` when the panel is a list of commands, `Tooltip` for\n * a hint that must not take focus at all, and `Dialog` when the task has to\n * block the rest of the UI.\n */\nwithDefaults(\n defineProps<{\n /** Drive the panel from the host with `v-model:open`; omit it and the popover owns its own state. */\n open?: boolean | undefined;\n /** The edge of the trigger to anchor against, before collision flipping. */\n side?: PopoverSide;\n /** Where the panel sits along that edge — `start` keeps its leading edge flush with the trigger's. */\n align?: PopoverAlign;\n /** Gap in pixels between the trigger and the panel. */\n sideOffset?: number;\n /** Draw the pointer notch. Turn it off where the panel reads better flush against its trigger. */\n arrow?: boolean;\n }>(),\n // `open: undefined` is load-bearing, not a redundant default — it is what\n // keeps the uncontrolled third state reachable past Vue's absent-Boolean\n // casting. `optional()` in the template is the other half; its docblock\n // carries the reasoning for both.\n { open: undefined, side: \"bottom\", align: \"center\", sideOffset: 6, arrow: true },\n);\n\ndefineEmits<{ \"update:open\": [value: boolean] }>();\n</script>\n\n<template>\n <PopoverRoot v-bind=\"optional({ open })\" @update:open=\"$emit('update:open', $event)\">\n <!-- @slot The control that opens the panel. Rendered `as-child`, so the\n caller's own element *is* the trigger and no wrapper swallows its\n accessible name. -->\n <PopoverTrigger as-child>\n <slot name=\"trigger\" />\n </PopoverTrigger>\n\n <PopoverPortal>\n <PopoverContent\n :side=\"side\"\n :align=\"align\"\n :side-offset=\"sideOffset\"\n :class=\"\n cn(\n 'z-overlay min-w-[12rem] max-w-[min(90vw,22rem)] rounded-md border border-border bg-popover p-3 text-sm text-popover-foreground shadow-md outline-none',\n // Both states scoped, never unconditional. Reka's Presence\n // keeps closed content mounted until an animationend arrives, and a\n // mount-only animation never fires a second one — so an\n // unconditional animation class strands an invisible panel over the\n // page, swallowing clicks. Scoped, the closed element computes\n // `animation-name: none` and Presence takes its immediate-unmount\n // branch instead; the paired exit is precisely what Presence is\n // waiting to hold it for. The origin below is what makes that scale\n // grow out of the trigger rather than out of the panel's own\n // centre — on the way out as well as in.\n 'data-[state=open]:animate-scale-in data-[state=closed]:animate-scale-out',\n )\n \"\n style=\"transform-origin: var(--reka-popper-transform-origin)\"\n >\n <!-- @slot The panel body. -->\n <slot />\n <PopoverArrow v-if=\"arrow\" class=\"fill-popover\" :width=\"12\" :height=\"6\" />\n </PopoverContent>\n </PopoverPortal>\n </PopoverRoot>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;GAgEE,OAAA,UAAA,GAAA,YAoCc,MAAA,WAAA,GApCd,WAAqB,MAoCP,QAAA,CApCe,CAAA,EAAA,MAAG,QAAA,KAAI,CAAA,GAAA,EAAM,iBAAW,OAAA,OAAA,OAAA,MAAA,WAAEA,KAAAA,MAAK,eAAgB,MAAM,GAAA,CAAA,GAAA;IAIhF,SAAA,cAEiB,CAFjB,YAEiB,MAAA,cAAA,GAAA,EAFD,YAAA,GAAQ,GAAA;KACtB,SAAA,cAAuB,CAAvB,WAAuB,KAAA,QAAA,SAAA,CAAA,CAAA;;IAGzB,CAAA,GAAA,YA2BgB,MAAA,aAAA,GAAA,MAAA;KA1Bd,SAAA,cAyBiB,CAzBjB,YAyBiB,MAAA,cAAA,GAAA;MAxBd,MAAM,QAAA;MACN,OAAO,QAAA;MACP,eAAa,QAAA;MACb,OAAK,eAAa,MAAA,EAAA,CAAE,CAAA,yJAAA,0EAAA,CAAA;MAgBrB,OAAA,EAAA,oBAAA,sCAAA;;MAGA,SAAA,cAAQ,CAAR,WAAQ,KAAA,QAAA,SAAA,GACY,QAAA,SAApB,UAAA,GAAA,YAA0E,MAAA,YAAA,GAAA;;OAA/C,OAAM;OAAgB,OAAO;OAAK,QAAQ"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type LabelOverrides } from "
|
|
2
|
-
import type { ProgressLabels } from "
|
|
1
|
+
import { type LabelOverrides } from "../../../labels/src/index";
|
|
2
|
+
import type { ProgressLabels } from "../../../labels/src/index";
|
|
3
3
|
/**
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { default, progressVariants, PROGRESS_LABELS } from "./Progress.vue";
|
|
2
2
|
export type { ProgressSize } from "./Progress.vue";
|
|
3
|
-
export type { ProgressLabels } from "
|
|
3
|
+
export type { ProgressLabels } from "../../../labels/src/index";
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type LabelOverrides } from "
|
|
2
|
-
import type { RadialProgressLabels } from "
|
|
1
|
+
import { type LabelOverrides } from "../../../labels/src/index";
|
|
2
|
+
import type { RadialProgressLabels } from "../../../labels/src/index";
|
|
3
3
|
/**
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { default, radialProgressVariants, RADIAL_PROGRESS_LABELS } from "./RadialProgress.vue";
|
|
2
2
|
export type { RadialProgressSize, RadialProgressThickness } from "./RadialProgress.vue";
|
|
3
|
-
export type { RadialProgressLabels } from "
|
|
3
|
+
export type { RadialProgressLabels } from "../../../labels/src/index";
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RadioGroup.js","names":[],"sources":["../../../../../packages/primitives/radio-group/src/RadioGroup.vue"],"sourcesContent":["<script lang=\"ts\">\n/** One selectable row in a {@link RadioGroup}. */\nexport interface RadioOption {\n /** Matched against `modelValue`. */\n value: string;\n /** Visible label, rendered beside the control. */\n label: string;\n /** Secondary text, rendered small under the label. */\n description?: string;\n /** Disables this row alone, leaving its siblings pickable. */\n disabled?: boolean;\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { RadioGroupIndicator, RadioGroupItem, RadioGroupRoot } from \"reka-ui\";\nimport { cn } from \"@ecoma-io/loom-core\";\nimport { optional } from \"@ecoma-io/loom-core\";\nimport { useSplitAttrs } from \"@ecoma-io/loom-core\";\nimport { useFieldControl } from \"@ecoma-io/loom-labels\";\n\n/**\n * RadioGroup — a vertical list of mutually exclusive options, each with a\n * visible (and optionally described) label — for longer or explained\n * choices and settings lists. For a compact horizontal toggle among 2-5\n * short options that are all visible at once, reach for SegmentedControl\n * instead. Built on Reka UI's RadioGroup: roving tabindex (the group is one\n * Tab stop, not N) with arrow-key navigation between items.\n *\n * Inside a [Field](../Field/Field.vue) the row's description, `name`,\n * `required` and `invalid` reach the group through `useFieldControl()`, and\n * `name` below still wins wherever it is set — the row and this prop are one\n * concept, not two that can disagree.\n *\n * **A row's label does not name this group.** `<label for>` names a labelable\n * element and this renders a `div[role=\"radiogroup\"]`, so the row's label\n * resolves to the element and names nobody. Name it with a\n * [Fieldset](../Fieldset/Fieldset.vue)'s real `<legend>`, or with an\n * `aria-label`/`aria-labelledby` of its own.\n *\n * There is no `readonly`, and a row's is ignored rather than approximated: each\n * option is a `<button role=\"radio\">` with no native read-only state to put it\n * in, and a group whose options cannot be picked is a disabled group.\n */\nconst props = withDefaults(\n defineProps<{\n /** The selected option's `value`. */\n modelValue?: string;\n /** The rows to render, in order. */\n options: RadioOption[];\n /** Disables every row at once, distinct from a single option's own `disabled`. Unset defers to a wrapping Field. */\n disabled?: boolean | undefined;\n /** Set when this group posts inside a real `<form>` — becomes the submitted field name. Unset defers to a wrapping Field. */\n name?: string;\n }>(),\n {\n // Not `false`: absent has to stay tellable from `false` for a Field above\n // to disable the group 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: string] }>();\n\ndefineOptions({ inheritAttrs: false });\nconst { attrs, rest: groupAttrs } = 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** `groupAttrs`, and that position is the contract (see TextField.vue).\n// `name` leaves `optional()` below with it: resolved once here, it reaches\n// RadioGroupRoot's own `name` prop, which is what mints the hidden input a\n// `<form>` submits.\n//\n// `required` and `invalid` are omitted because this component has no prop for\n// either — the row's answer stands unopposed. `readonly` is omitted for the\n// reason the docblock gives.\n//\n// The resolved `required` then reaches the group through Reka's own prop rather\n// than the `aria-required` in `field.attrs`: RadioGroupRoot writes that\n// attribute itself, so leaving it to the bag is a race with a `false` — see\n// Checkbox.vue, where the merge order makes the same race a certainty.\nconst field = useFieldControl(() => ({\n id: attrs.id as string | undefined,\n describedBy: attrs[\"aria-describedby\"] as string | undefined,\n name: props.name,\n disabled: props.disabled,\n}));\n</script>\n\n<template>\n <RadioGroupRoot\n v-bind=\"{ ...optional({ modelValue }), ...groupAttrs, ...field.attrs }\"\n :disabled=\"field.disabled\"\n :required=\"field.required\"\n orientation=\"vertical\"\n :class=\"cn('flex flex-col gap-3', attrs.class as string)\"\n @update:model-value=\"$emit('update:modelValue', String($event))\"\n >\n <!-- RadioGroupItem is a labelable <button role=\"radio\">, so wrapping it in\n <label> names it exactly like a native control; the rule's\n nesting/id heuristic just doesn't recognize reka-ui's custom element\n as a \"control\". -->\n <!-- eslint-disable-next-line vuejs-accessibility/label-has-for -->\n <label\n v-for=\"opt in options\"\n :key=\"opt.value\"\n :class=\"\n cn(\n 'flex min-h-6 items-start gap-2 text-sm text-foreground',\n // Disabled text stays readable (AA on the light ground) — only the\n // control glyph dims; quiet, not illegible.\n field.disabled || opt.disabled\n ? 'cursor-not-allowed text-muted-foreground'\n : 'cursor-pointer',\n )\n \"\n >\n <RadioGroupItem\n :value=\"opt.value\"\n :class=\"\n cn(\n 'mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full border border-input bg-background',\n // Springy transform (press squish), steady color — the transform\n // rides --ease-spring while border stays instant --ease-out (style\n // below), same press language as Button/Switch/Checkbox.\n 'active:scale-90',\n // Selected = a decision (Loom law): the ring turns primary.\n 'data-[state=checked]:border-primary',\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 'disabled:cursor-not-allowed disabled:
|
|
1
|
+
{"version":3,"file":"RadioGroup.js","names":[],"sources":["../../../../../packages/primitives/radio-group/src/RadioGroup.vue"],"sourcesContent":["<script lang=\"ts\">\n/** One selectable row in a {@link RadioGroup}. */\nexport interface RadioOption {\n /** Matched against `modelValue`. */\n value: string;\n /** Visible label, rendered beside the control. */\n label: string;\n /** Secondary text, rendered small under the label. */\n description?: string;\n /** Disables this row alone, leaving its siblings pickable. */\n disabled?: boolean;\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { RadioGroupIndicator, RadioGroupItem, RadioGroupRoot } from \"reka-ui\";\nimport { cn } from \"@ecoma-io/loom-core\";\nimport { optional } from \"@ecoma-io/loom-core\";\nimport { useSplitAttrs } from \"@ecoma-io/loom-core\";\nimport { useFieldControl } from \"@ecoma-io/loom-labels\";\n\n/**\n * RadioGroup — a vertical list of mutually exclusive options, each with a\n * visible (and optionally described) label — for longer or explained\n * choices and settings lists. For a compact horizontal toggle among 2-5\n * short options that are all visible at once, reach for SegmentedControl\n * instead. Built on Reka UI's RadioGroup: roving tabindex (the group is one\n * Tab stop, not N) with arrow-key navigation between items.\n *\n * Inside a [Field](../Field/Field.vue) the row's description, `name`,\n * `required` and `invalid` reach the group through `useFieldControl()`, and\n * `name` below still wins wherever it is set — the row and this prop are one\n * concept, not two that can disagree.\n *\n * **A row's label does not name this group.** `<label for>` names a labelable\n * element and this renders a `div[role=\"radiogroup\"]`, so the row's label\n * resolves to the element and names nobody. Name it with a\n * [Fieldset](../Fieldset/Fieldset.vue)'s real `<legend>`, or with an\n * `aria-label`/`aria-labelledby` of its own.\n *\n * There is no `readonly`, and a row's is ignored rather than approximated: each\n * option is a `<button role=\"radio\">` with no native read-only state to put it\n * in, and a group whose options cannot be picked is a disabled group.\n */\nconst props = withDefaults(\n defineProps<{\n /** The selected option's `value`. */\n modelValue?: string;\n /** The rows to render, in order. */\n options: RadioOption[];\n /** Disables every row at once, distinct from a single option's own `disabled`. Unset defers to a wrapping Field. */\n disabled?: boolean | undefined;\n /** Set when this group posts inside a real `<form>` — becomes the submitted field name. Unset defers to a wrapping Field. */\n name?: string;\n }>(),\n {\n // Not `false`: absent has to stay tellable from `false` for a Field above\n // to disable the group 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: string] }>();\n\ndefineOptions({ inheritAttrs: false });\nconst { attrs, rest: groupAttrs } = 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** `groupAttrs`, and that position is the contract (see TextField.vue).\n// `name` leaves `optional()` below with it: resolved once here, it reaches\n// RadioGroupRoot's own `name` prop, which is what mints the hidden input a\n// `<form>` submits.\n//\n// `required` and `invalid` are omitted because this component has no prop for\n// either — the row's answer stands unopposed. `readonly` is omitted for the\n// reason the docblock gives.\n//\n// The resolved `required` then reaches the group through Reka's own prop rather\n// than the `aria-required` in `field.attrs`: RadioGroupRoot writes that\n// attribute itself, so leaving it to the bag is a race with a `false` — see\n// Checkbox.vue, where the merge order makes the same race a certainty.\nconst field = useFieldControl(() => ({\n id: attrs.id as string | undefined,\n describedBy: attrs[\"aria-describedby\"] as string | undefined,\n name: props.name,\n disabled: props.disabled,\n}));\n</script>\n\n<template>\n <RadioGroupRoot\n v-bind=\"{ ...optional({ modelValue }), ...groupAttrs, ...field.attrs }\"\n :disabled=\"field.disabled\"\n :required=\"field.required\"\n orientation=\"vertical\"\n :class=\"cn('flex flex-col gap-3', attrs.class as string)\"\n @update:model-value=\"$emit('update:modelValue', String($event))\"\n >\n <!-- RadioGroupItem is a labelable <button role=\"radio\">, so wrapping it in\n <label> names it exactly like a native control; the rule's\n nesting/id heuristic just doesn't recognize reka-ui's custom element\n as a \"control\". -->\n <!-- eslint-disable-next-line vuejs-accessibility/label-has-for -->\n <label\n v-for=\"opt in options\"\n :key=\"opt.value\"\n :class=\"\n cn(\n 'flex min-h-6 items-start gap-2 text-sm text-foreground',\n // Disabled text stays readable (AA on the light ground) — only the\n // control glyph dims; quiet, not illegible.\n field.disabled || opt.disabled\n ? 'cursor-not-allowed text-muted-foreground'\n : 'cursor-pointer',\n )\n \"\n >\n <RadioGroupItem\n :value=\"opt.value\"\n :class=\"\n cn(\n 'mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full border border-input bg-background',\n // Springy transform (press squish), steady color — the transform\n // rides --ease-spring while border stays instant --ease-out (style\n // below), same press language as Button/Switch/Checkbox.\n 'active:scale-90',\n // Selected = a decision (Loom law): the ring turns primary.\n 'data-[state=checked]:border-primary',\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 — same verdict as Checkbox beside it. The\n // unchecked circle falls to `bg-muted` with the rim every\n // unavailable control slackens to; a checked one keeps its\n // primary ring and dot, because selected is information (the\n // native `disabled` attribute carries unavailability regardless).\n // Compound form deliberate: Tailwind sorts data variants after\n // plain `disabled:`, so a bare `disabled:bg-muted` would lose to\n // `data-[state=*]:*` and never fire.\n 'disabled:cursor-not-allowed disabled:data-[state=unchecked]:bg-muted disabled:data-[state=unchecked]:border-border',\n )\n \"\n :disabled=\"opt.disabled ?? false\"\n style=\"\n transition:\n transform var(--duration-fast) var(--ease-spring),\n border-color var(--duration-instant) var(--ease-out),\n box-shadow var(--duration-fast) var(--ease-out);\n \"\n >\n <!-- The dot pops in with scale-in — a small causal \"it's selected now\". -->\n <RadioGroupIndicator class=\"flex animate-scale-in items-center justify-center\">\n <span class=\"h-2 w-2 rounded-full bg-primary\" />\n </RadioGroupIndicator>\n </RadioGroupItem>\n <span class=\"flex flex-col gap-0.5\">\n <span>{{ opt.label }}</span>\n <span v-if=\"opt.description\" class=\"text-xs text-muted-foreground\">{{\n opt.description\n }}</span>\n </span>\n </label>\n </RadioGroupRoot>\n</template>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RadioGroup.vue.d.ts","sourceRoot":"","sources":["../../../../../packages/primitives/radio-group/src/RadioGroup.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"RadioGroup.vue.d.ts","sourceRoot":"","sources":["../../../../../packages/primitives/radio-group/src/RadioGroup.vue"],"names":[],"mappings":"AAmLA,kDAAkD;AAClD,MAAM,WAAW,WAAW;IAC1B,oCAAoC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;wBACoB,OAAO,YAAY;AAAxC,wBAAyC;AACzC,QAAA,MAAM,YAAY;IAyBd,qCAAqC;iBACxB,MAAM;IACnB,oCAAoC;aAC3B,WAAW,EAAE;IACtB,oHAAoH;eACzG,OAAO,GAAG,SAAS;IAC9B,6HAA6H;WACtH,MAAM;;;;IAPb,qCAAqC;iBACxB,MAAM;IACnB,oCAAoC;aAC3B,WAAW,EAAE;IACtB,oHAAoH;eACzG,OAAO,GAAG,SAAS;IAC9B,6HAA6H;WACtH,MAAM;;;;cAFF,OAAO,GAAG,SAAS;6EAsP9B,CAAC"}
|
package/dist/packages/primitives/radio-group/src/RadioGroup.vue_vue_type_script_setup_true_lang.js
CHANGED
|
@@ -52,7 +52,7 @@ var RadioGroup_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defin
|
|
|
52
52
|
class: normalizeClass(unref(cn)("flex min-h-6 items-start gap-2 text-sm text-foreground", unref(field).disabled || opt.disabled ? "cursor-not-allowed text-muted-foreground" : "cursor-pointer"))
|
|
53
53
|
}, [createVNode(unref(RadioGroupItem), {
|
|
54
54
|
value: opt.value,
|
|
55
|
-
class: normalizeClass(unref(cn)("mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full border border-input bg-background", "active:scale-90", "data-[state=checked]:border-primary", "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo", "disabled:cursor-not-allowed disabled:
|
|
55
|
+
class: normalizeClass(unref(cn)("mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full border border-input bg-background", "active:scale-90", "data-[state=checked]:border-primary", "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")),
|
|
56
56
|
disabled: opt.disabled ?? false,
|
|
57
57
|
style: { "transition": "transform var(--duration-fast) var(--ease-spring),\n border-color var(--duration-instant) var(--ease-out),\n box-shadow var(--duration-fast) var(--ease-out)" }
|
|
58
58
|
}, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RadioGroup.vue_vue_type_script_setup_true_lang.js","names":["$emit"],"sources":["../../../../../packages/primitives/radio-group/src/RadioGroup.vue"],"sourcesContent":["<script lang=\"ts\">\n/** One selectable row in a {@link RadioGroup}. */\nexport interface RadioOption {\n /** Matched against `modelValue`. */\n value: string;\n /** Visible label, rendered beside the control. */\n label: string;\n /** Secondary text, rendered small under the label. */\n description?: string;\n /** Disables this row alone, leaving its siblings pickable. */\n disabled?: boolean;\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { RadioGroupIndicator, RadioGroupItem, RadioGroupRoot } from \"reka-ui\";\nimport { cn } from \"@ecoma-io/loom-core\";\nimport { optional } from \"@ecoma-io/loom-core\";\nimport { useSplitAttrs } from \"@ecoma-io/loom-core\";\nimport { useFieldControl } from \"@ecoma-io/loom-labels\";\n\n/**\n * RadioGroup — a vertical list of mutually exclusive options, each with a\n * visible (and optionally described) label — for longer or explained\n * choices and settings lists. For a compact horizontal toggle among 2-5\n * short options that are all visible at once, reach for SegmentedControl\n * instead. Built on Reka UI's RadioGroup: roving tabindex (the group is one\n * Tab stop, not N) with arrow-key navigation between items.\n *\n * Inside a [Field](../Field/Field.vue) the row's description, `name`,\n * `required` and `invalid` reach the group through `useFieldControl()`, and\n * `name` below still wins wherever it is set — the row and this prop are one\n * concept, not two that can disagree.\n *\n * **A row's label does not name this group.** `<label for>` names a labelable\n * element and this renders a `div[role=\"radiogroup\"]`, so the row's label\n * resolves to the element and names nobody. Name it with a\n * [Fieldset](../Fieldset/Fieldset.vue)'s real `<legend>`, or with an\n * `aria-label`/`aria-labelledby` of its own.\n *\n * There is no `readonly`, and a row's is ignored rather than approximated: each\n * option is a `<button role=\"radio\">` with no native read-only state to put it\n * in, and a group whose options cannot be picked is a disabled group.\n */\nconst props = withDefaults(\n defineProps<{\n /** The selected option's `value`. */\n modelValue?: string;\n /** The rows to render, in order. */\n options: RadioOption[];\n /** Disables every row at once, distinct from a single option's own `disabled`. Unset defers to a wrapping Field. */\n disabled?: boolean | undefined;\n /** Set when this group posts inside a real `<form>` — becomes the submitted field name. Unset defers to a wrapping Field. */\n name?: string;\n }>(),\n {\n // Not `false`: absent has to stay tellable from `false` for a Field above\n // to disable the group 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: string] }>();\n\ndefineOptions({ inheritAttrs: false });\nconst { attrs, rest: groupAttrs } = 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** `groupAttrs`, and that position is the contract (see TextField.vue).\n// `name` leaves `optional()` below with it: resolved once here, it reaches\n// RadioGroupRoot's own `name` prop, which is what mints the hidden input a\n// `<form>` submits.\n//\n// `required` and `invalid` are omitted because this component has no prop for\n// either — the row's answer stands unopposed. `readonly` is omitted for the\n// reason the docblock gives.\n//\n// The resolved `required` then reaches the group through Reka's own prop rather\n// than the `aria-required` in `field.attrs`: RadioGroupRoot writes that\n// attribute itself, so leaving it to the bag is a race with a `false` — see\n// Checkbox.vue, where the merge order makes the same race a certainty.\nconst field = useFieldControl(() => ({\n id: attrs.id as string | undefined,\n describedBy: attrs[\"aria-describedby\"] as string | undefined,\n name: props.name,\n disabled: props.disabled,\n}));\n</script>\n\n<template>\n <RadioGroupRoot\n v-bind=\"{ ...optional({ modelValue }), ...groupAttrs, ...field.attrs }\"\n :disabled=\"field.disabled\"\n :required=\"field.required\"\n orientation=\"vertical\"\n :class=\"cn('flex flex-col gap-3', attrs.class as string)\"\n @update:model-value=\"$emit('update:modelValue', String($event))\"\n >\n <!-- RadioGroupItem is a labelable <button role=\"radio\">, so wrapping it in\n <label> names it exactly like a native control; the rule's\n nesting/id heuristic just doesn't recognize reka-ui's custom element\n as a \"control\". -->\n <!-- eslint-disable-next-line vuejs-accessibility/label-has-for -->\n <label\n v-for=\"opt in options\"\n :key=\"opt.value\"\n :class=\"\n cn(\n 'flex min-h-6 items-start gap-2 text-sm text-foreground',\n // Disabled text stays readable (AA on the light ground) — only the\n // control glyph dims; quiet, not illegible.\n field.disabled || opt.disabled\n ? 'cursor-not-allowed text-muted-foreground'\n : 'cursor-pointer',\n )\n \"\n >\n <RadioGroupItem\n :value=\"opt.value\"\n :class=\"\n cn(\n 'mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full border border-input bg-background',\n // Springy transform (press squish), steady color — the transform\n // rides --ease-spring while border stays instant --ease-out (style\n // below), same press language as Button/Switch/Checkbox.\n 'active:scale-90',\n // Selected = a decision (Loom law): the ring turns primary.\n 'data-[state=checked]:border-primary',\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 'disabled:cursor-not-allowed disabled:
|
|
1
|
+
{"version":3,"file":"RadioGroup.vue_vue_type_script_setup_true_lang.js","names":["$emit"],"sources":["../../../../../packages/primitives/radio-group/src/RadioGroup.vue"],"sourcesContent":["<script lang=\"ts\">\n/** One selectable row in a {@link RadioGroup}. */\nexport interface RadioOption {\n /** Matched against `modelValue`. */\n value: string;\n /** Visible label, rendered beside the control. */\n label: string;\n /** Secondary text, rendered small under the label. */\n description?: string;\n /** Disables this row alone, leaving its siblings pickable. */\n disabled?: boolean;\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { RadioGroupIndicator, RadioGroupItem, RadioGroupRoot } from \"reka-ui\";\nimport { cn } from \"@ecoma-io/loom-core\";\nimport { optional } from \"@ecoma-io/loom-core\";\nimport { useSplitAttrs } from \"@ecoma-io/loom-core\";\nimport { useFieldControl } from \"@ecoma-io/loom-labels\";\n\n/**\n * RadioGroup — a vertical list of mutually exclusive options, each with a\n * visible (and optionally described) label — for longer or explained\n * choices and settings lists. For a compact horizontal toggle among 2-5\n * short options that are all visible at once, reach for SegmentedControl\n * instead. Built on Reka UI's RadioGroup: roving tabindex (the group is one\n * Tab stop, not N) with arrow-key navigation between items.\n *\n * Inside a [Field](../Field/Field.vue) the row's description, `name`,\n * `required` and `invalid` reach the group through `useFieldControl()`, and\n * `name` below still wins wherever it is set — the row and this prop are one\n * concept, not two that can disagree.\n *\n * **A row's label does not name this group.** `<label for>` names a labelable\n * element and this renders a `div[role=\"radiogroup\"]`, so the row's label\n * resolves to the element and names nobody. Name it with a\n * [Fieldset](../Fieldset/Fieldset.vue)'s real `<legend>`, or with an\n * `aria-label`/`aria-labelledby` of its own.\n *\n * There is no `readonly`, and a row's is ignored rather than approximated: each\n * option is a `<button role=\"radio\">` with no native read-only state to put it\n * in, and a group whose options cannot be picked is a disabled group.\n */\nconst props = withDefaults(\n defineProps<{\n /** The selected option's `value`. */\n modelValue?: string;\n /** The rows to render, in order. */\n options: RadioOption[];\n /** Disables every row at once, distinct from a single option's own `disabled`. Unset defers to a wrapping Field. */\n disabled?: boolean | undefined;\n /** Set when this group posts inside a real `<form>` — becomes the submitted field name. Unset defers to a wrapping Field. */\n name?: string;\n }>(),\n {\n // Not `false`: absent has to stay tellable from `false` for a Field above\n // to disable the group 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: string] }>();\n\ndefineOptions({ inheritAttrs: false });\nconst { attrs, rest: groupAttrs } = 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** `groupAttrs`, and that position is the contract (see TextField.vue).\n// `name` leaves `optional()` below with it: resolved once here, it reaches\n// RadioGroupRoot's own `name` prop, which is what mints the hidden input a\n// `<form>` submits.\n//\n// `required` and `invalid` are omitted because this component has no prop for\n// either — the row's answer stands unopposed. `readonly` is omitted for the\n// reason the docblock gives.\n//\n// The resolved `required` then reaches the group through Reka's own prop rather\n// than the `aria-required` in `field.attrs`: RadioGroupRoot writes that\n// attribute itself, so leaving it to the bag is a race with a `false` — see\n// Checkbox.vue, where the merge order makes the same race a certainty.\nconst field = useFieldControl(() => ({\n id: attrs.id as string | undefined,\n describedBy: attrs[\"aria-describedby\"] as string | undefined,\n name: props.name,\n disabled: props.disabled,\n}));\n</script>\n\n<template>\n <RadioGroupRoot\n v-bind=\"{ ...optional({ modelValue }), ...groupAttrs, ...field.attrs }\"\n :disabled=\"field.disabled\"\n :required=\"field.required\"\n orientation=\"vertical\"\n :class=\"cn('flex flex-col gap-3', attrs.class as string)\"\n @update:model-value=\"$emit('update:modelValue', String($event))\"\n >\n <!-- RadioGroupItem is a labelable <button role=\"radio\">, so wrapping it in\n <label> names it exactly like a native control; the rule's\n nesting/id heuristic just doesn't recognize reka-ui's custom element\n as a \"control\". -->\n <!-- eslint-disable-next-line vuejs-accessibility/label-has-for -->\n <label\n v-for=\"opt in options\"\n :key=\"opt.value\"\n :class=\"\n cn(\n 'flex min-h-6 items-start gap-2 text-sm text-foreground',\n // Disabled text stays readable (AA on the light ground) — only the\n // control glyph dims; quiet, not illegible.\n field.disabled || opt.disabled\n ? 'cursor-not-allowed text-muted-foreground'\n : 'cursor-pointer',\n )\n \"\n >\n <RadioGroupItem\n :value=\"opt.value\"\n :class=\"\n cn(\n 'mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full border border-input bg-background',\n // Springy transform (press squish), steady color — the transform\n // rides --ease-spring while border stays instant --ease-out (style\n // below), same press language as Button/Switch/Checkbox.\n 'active:scale-90',\n // Selected = a decision (Loom law): the ring turns primary.\n 'data-[state=checked]:border-primary',\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 — same verdict as Checkbox beside it. The\n // unchecked circle falls to `bg-muted` with the rim every\n // unavailable control slackens to; a checked one keeps its\n // primary ring and dot, because selected is information (the\n // native `disabled` attribute carries unavailability regardless).\n // Compound form deliberate: Tailwind sorts data variants after\n // plain `disabled:`, so a bare `disabled:bg-muted` would lose to\n // `data-[state=*]:*` and never fire.\n 'disabled:cursor-not-allowed disabled:data-[state=unchecked]:bg-muted disabled:data-[state=unchecked]:border-border',\n )\n \"\n :disabled=\"opt.disabled ?? false\"\n style=\"\n transition:\n transform var(--duration-fast) var(--ease-spring),\n border-color var(--duration-instant) var(--ease-out),\n box-shadow var(--duration-fast) var(--ease-out);\n \"\n >\n <!-- The dot pops in with scale-in — a small causal \"it's selected now\". -->\n <RadioGroupIndicator class=\"flex animate-scale-in items-center justify-center\">\n <span class=\"h-2 w-2 rounded-full bg-primary\" />\n </RadioGroupIndicator>\n </RadioGroupItem>\n <span class=\"flex flex-col gap-0.5\">\n <span>{{ opt.label }}</span>\n <span v-if=\"opt.description\" class=\"text-xs text-muted-foreground\">{{\n opt.description\n }}</span>\n </span>\n </label>\n </RadioGroupRoot>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4CA,MAAM,QAAQ;EAuBd,MAAM,EAAE,OAAO,MAAM,eAAe,cAAc;EAoBlD,MAAM,QAAQ,uBAAuB;GACnC,IAAI,MAAM;GACV,aAAa,MAAM;GACnB,MAAM,MAAM;GACZ,UAAU,MAAM;EAClB,EAAE;;GAIA,OAAA,UAAA,GAAA,YAuEiB,MAAA,cAAA,GAvEjB,WAuEiB;IAAA,GAtEF,MAAA,QAAA,CAAQ,CAAA,EAAA,YAAG,QAAA,WAAU,CAAA;IAAA,GAAQ,MAAA,UAAA;IAAU,GAAK,MAAA,KAAA,CAAK,CAAC;GAAK,GAAA;IACnE,UAAU,MAAA,KAAA,CAAK,CAAC;IAChB,UAAU,MAAA,KAAA,CAAK,CAAC;IACjB,aAAY;IACX,OAAO,MAAA,EAAA,CAAE,CAAA,uBAAwB,MAAA,KAAA,CAAK,CAAC,KAAK;IAC5C,uBAAkB,OAAA,OAAA,OAAA,MAAA,WAAEA,KAAAA,MAAK,qBAAsB,OAAO,MAAM,CAAA;;IAQ3D,SAAA,cAAsB,EADxB,UAAA,IAAA,GAAA,mBAyDQ,UAAA,MAAA,WAxDQ,QAAA,UAAP,QAAG;KADZ,OAAA,UAAA,GAAA,mBAyDQ,SAAA;MAvDL,KAAK,IAAI;MACT,OAAK,eAAW,MAAA,EAAA,CAAE,CAAA,0DAAqN,MAAA,KAAA,CAAK,CAAC,YAAY,IAAI,WAAA,6CAAA,gBAAA,CAAA;KAW9P,GAAA,CAAA,YAoCiB,MAAA,cAAA,GAAA;MAnCd,OAAO,IAAI;MACX,OAAK,eAAa,MAAA,EAAA,CAAE,CAAA,2GAAA,mBAAA,uCAAA,+GAAA,oHAAA,CAAA;MAsBpB,UAAU,IAAI,YAAQ;MACvB,OAAA,EAAA,cAAA,qLAAA;;MAQA,SAAA,cAEsB,CAFtB,YAEsB,MAAA,mBAAA,GAAA,EAFD,OAAM,oDAAmD,GAAA;OAC5E,SAAA,cAAgD,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,CAAhD,mBAAgD,QAAA,EAA1C,OAAM,kCAAiC,GAAA,MAAA,EAAA,CAAA,EAAA,CAAA;;;;;;;;KAGjD,CAAA,GAAA,mBAKO,QALP,YAKO,CAJL,mBAA4B,QAAA,MAAA,gBAAnB,IAAI,KAAK,GAAA,CAAA,GACN,IAAI,eAAhB,UAAA,GAAA,mBAES,QAFT,YAES,gBADP,IAAI,WAAW,GAAA,CAAA,KAAA,mBAAA,IAAA,IAAA,CAAA,CAAA,CAAA,GAAA,CAAA"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { default } from "./Rating.vue";
|
|
2
2
|
export type { RatingSize } from "./Rating.vue";
|
|
3
3
|
export { RATING_LABELS } from "./Rating.vue";
|
|
4
|
-
export type { RatingLabels } from "
|
|
4
|
+
export type { RatingLabels } from "../../../labels/src/index";
|
|
5
5
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SegmentedControl.js","names":[],"sources":["../../../../../packages/primitives/segmented-control/src/SegmentedControl.vue"],"sourcesContent":["<script lang=\"ts\">\n/** One segment in a {@link SegmentedControl}. */\nexport interface SegmentedControlOption {\n /** Matched against `modelValue`. */\n value: string;\n /** Visible label, rendered inside the segment. */\n label: string;\n /** Disables this segment alone, leaving its neighbours pickable. */\n disabled?: boolean;\n /** Forwarded to the segment's DOM node — lets hosts keep stable test hooks. */\n testId?: string;\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { nextTick, onMounted, onUnmounted, reactive, ref, useTemplateRef, watch } from \"vue\";\nimport { RadioGroupRoot, RadioGroupItem } from \"reka-ui\";\nimport { cn, optional } from \"@ecoma-io/loom-core\";\nimport { useSplitAttrs } from \"@ecoma-io/loom-core\";\nimport { useAncestorDisabled } from \"@ecoma-io/loom-labels\";\nimport { useFieldControl } from \"@ecoma-io/loom-labels\";\n\n/**\n * SegmentedControl — pick one of 2-5 mutually exclusive options, all visible\n * at once; one is always active. Built on Reka UI's RadioGroup (single\n * choice, roving tabindex — the group is one Tab stop, not N — with\n * arrow-key navigation). Styled with Loom tokens.\n *\n * Inside a [Field](../Field/Field.vue) the row's description, `name`,\n * `required` and `invalid` reach the group through `useFieldControl()`.\n *\n * **A row's label does not name this group.** `<label for>` names a labelable\n * element and this renders a `div[role=\"radiogroup\"]`, so the row's label\n * resolves to the element and names nobody. Name it with a\n * [Fieldset](../Fieldset/Fieldset.vue)'s real `<legend>`, or with an\n * `aria-label`/`aria-labelledby` of its own — which is what every example\n * already does, because the control carries no label text.\n *\n * There is no `readonly`, and a row's is ignored rather than approximated: each\n * segment is a `<button role=\"radio\">` with no native read-only state to put it\n * in, and one segment is always active, so a read-only control here would be a\n * disabled one showing an answer.\n */\nconst props = withDefaults(\n defineProps<{\n /** The selected option's `value`. */\n modelValue?: string;\n /** The segments to render, in order. */\n options: SegmentedControlOption[];\n /** Disables every segment at once, distinct from a single option's own `disabled`. Unset defers to a wrapping Field. */\n disabled?: boolean | undefined;\n /** `\"sm\"` is the compressed form for dense chrome — e.g. a status bar density level. */\n size?: \"default\" | \"sm\";\n }>(),\n {\n // Not `false`: absent has to stay tellable from `false` for a Field above\n // to disable the control 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 size: \"default\",\n },\n);\n\ndefineEmits<{ \"update:modelValue\": [value: string] }>();\n\ndefineOptions({ inheritAttrs: false });\nconst { attrs, rest: groupAttrs } = useSplitAttrs();\n\n/**\n * The segments are real `<button>`s, so a `<fieldset disabled>` above this\n * control already makes each of them inert — but Reka's roving focus is what\n * decides where Tab lands, and it is driven by the group's own `disabled`,\n * which the fieldset never reaches. Measured on this branch: every segment went\n * `:disabled` while the `role=\"radiogroup\"` container kept `tabindex=\"0\"`, so\n * Tab still stopped on an unavailable control and left the reader nowhere. Its\n * own `disabled` prop sets that to `-1`.\n *\n * Reading the group state here rather than painting it with a CSS variant is\n * also what keeps the appearance honest, and this is the control where the\n * distinction bites: one option may carry `disabled` of its own, so \"a\n * `:disabled` button is inside this track\" and \"this track is unavailable\" are\n * different facts. Only the fieldset says the second.\n *\n * Read off the DOM rather than taken from the Field context, which publishes no\n * `disabled` on purpose — see `../../lib/ancestor-disabled.ts`.\n */\nconst root = useTemplateRef<{ $el?: Element }>(\"root\");\nconst groupDisabled = useAncestorDisabled(() => root.value?.$el);\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** `groupAttrs`, and that position is the contract (see TextField.vue).\n//\n// `name`, `required` and `invalid` are omitted because this component has no\n// prop for any of them — the row's answer stands unopposed, and its `name`\n// reaches RadioGroupRoot's own prop, which mints the hidden input a `<form>`\n// submits. `readonly` is omitted for the reason the docblock gives.\n//\n// The resolved `required` then reaches the group through Reka's own prop rather\n// than the `aria-required` in `field.attrs`: RadioGroupRoot writes that\n// attribute itself, so leaving it to the bag is a race with a `false` — see\n// Checkbox.vue, where the merge order makes the same race a certainty.\nconst field = useFieldControl(() => ({\n id: attrs.id as string | undefined,\n describedBy: attrs[\"aria-describedby\"] as string | undefined,\n // The fieldset beats the prop in both directions, exactly as it does for the\n // segments themselves.\n disabled: groupDisabled.value ? true : props.disabled,\n}));\n\n// Shared sliding indicator behind the checked segment. Measured off the live\n// DOM (offsetLeft/offsetWidth of the [data-state=checked] item), not derived\n// from index/width math, so \"sm\"/\"default\" sizing and variable-width labels\n// stay correct without per-size indicator code.\nconst indicatorEl = ref<HTMLElement | null>(null);\nconst indicatorStyle = reactive({ left: \"0px\", width: \"0px\", opacity: \"0\" });\n\nlet resizeObserver: ResizeObserver | undefined;\n\n// Re-targets onto the checked item itself (not the container) so a late\n// width settle on exactly that element — e.g. the `font-medium` weight swap\n// on data-[state=checked] reflowing after this function's own read — is\n// caught by the observer and re-measured, instead of going unnoticed because\n// the container's total box happened not to change.\nfunction updateIndicator() {\n const container = indicatorEl.value?.parentElement;\n const active = container?.querySelector<HTMLElement>('[role=\"radio\"][data-state=\"checked\"]');\n if (!active) {\n indicatorStyle.opacity = \"0\";\n resizeObserver?.disconnect();\n return;\n }\n indicatorStyle.left = `${active.offsetLeft}px`;\n indicatorStyle.width = `${active.offsetWidth}px`;\n indicatorStyle.opacity = \"1\";\n resizeObserver?.disconnect();\n resizeObserver?.observe(active);\n}\n\nonMounted(() => {\n resizeObserver = new ResizeObserver(updateIndicator);\n updateIndicator();\n});\nonUnmounted(() => resizeObserver?.disconnect());\n\nwatch(\n () => props.modelValue,\n () => nextTick(updateIndicator),\n);\nwatch(\n () => props.options,\n () => nextTick(updateIndicator),\n { deep: true },\n);\n</script>\n\n<template>\n <RadioGroupRoot\n ref=\"root\"\n v-bind=\"{ ...optional({ modelValue }), ...groupAttrs, ...field.attrs }\"\n :disabled=\"field.disabled\"\n :required=\"field.required\"\n orientation=\"horizontal\"\n :class=\"\n cn(\n 'relative inline-flex items-center gap-0.5 rounded-md border border-input bg-muted p-0.5',\n // The one thing the *track* has left to say. Its fill is already\n // `bg-muted` — the well every other unavailable control drains to — so\n // the fill channel is spent before the state arrives, and the segments\n // inside carry the rest. The rim slackening from `input` to the lighter\n // `border` is what makes a wholly unavailable control tellable from an\n // available one at the group's own edge rather than only cell by cell.\n field.disabled && 'cursor-not-allowed border-border',\n attrs.class as string,\n )\n \"\n @update:model-value=\"$emit('update:modelValue', String($event))\"\n >\n <span\n ref=\"indicatorEl\"\n aria-hidden=\"true\"\n class=\"pointer-events-none absolute inset-y-0.5 rounded-sm bg-card shadow-sm\"\n style=\"\n transition:\n left var(--duration-fast) var(--ease-spring),\n width var(--duration-fast) var(--ease-spring);\n \"\n :style=\"{\n left: indicatorStyle.left,\n width: indicatorStyle.width,\n opacity: indicatorStyle.opacity,\n }\"\n />\n <RadioGroupItem\n v-for=\"opt in options\"\n :key=\"opt.value\"\n :value=\"opt.value\"\n :disabled=\"opt.disabled ?? false\"\n v-bind=\"optional({ 'data-testid': opt.testId })\"\n style=\"\n transition:\n transform var(--duration-fast) var(--ease-spring),\n color var(--duration-fast) var(--ease-out);\n \"\n :class=\"\n cn(\n // Named, not the bare `group`: a segmented control is dropped into\n // application chrome, and a bare `group-*` would also answer to any\n // ancestor a host happened to mark up as one.\n 'group/segment relative z-10 inline-flex items-center justify-center rounded-sm text-muted-foreground',\n size === 'sm' ? 'px-1.5 py-px text-[11px]' : 'px-3 py-1 text-sm',\n 'data-[state=checked]:font-medium data-[state=checked]:text-foreground',\n 'data-[state=unchecked]:hover:bg-subtle',\n 'active:scale-press',\n 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo',\n // No `opacity` here. A segment *is* its label — there is no glyph and\n // no fill of its own to dim — so `disabled:opacity-50` had nothing to\n // act on but the text, taking an unchecked segment to 1.96:1 and a\n // chosen one to 3.13:1 on its thumb.\n //\n // Unavailability is a fill instead, and it is the one step this\n // system already treats as meaningful: the cell drains up a rung of\n // the elevation rhythm, from the track's `bg-muted` to the page's own\n // `bg-background`, so it reads as a hole in the track rather than as\n // part of it. On a *chosen* segment that same fill covers the raised\n // white thumb, which is the whole signal — the value is still shown\n // and it is visibly no longer settable.\n 'disabled:pointer-events-none data-[disabled]:bg-background',\n )\n \"\n >\n <!-- The mute lives on this span rather than on the segment, and it has\n to. `data-[disabled]:` sorts *before* `data-[state=checked]:` in\n Tailwind's variant order, so a disabled segment that is also the\n chosen one would take `text-foreground` from the button — and a\n colour set on the button is only inherited here. Declared on the span\n it wins whatever the segment resolved to: 5.25:1 over the drained\n fill, against the 1.96:1 the dim used to leave. -->\n <span class=\"group-data-[disabled]/segment:text-muted-foreground\">{{ opt.label }}</span>\n </RadioGroupItem>\n </RadioGroupRoot>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"SegmentedControl.js","names":[],"sources":["../../../../../packages/primitives/segmented-control/src/SegmentedControl.vue"],"sourcesContent":["<script lang=\"ts\">\n/** One segment in a {@link SegmentedControl}. */\nexport interface SegmentedControlOption {\n /** Matched against `modelValue`. */\n value: string;\n /** Visible label, rendered inside the segment. */\n label: string;\n /** Disables this segment alone, leaving its neighbours pickable. */\n disabled?: boolean;\n /** Forwarded to the segment's DOM node — lets hosts keep stable test hooks. */\n testId?: string;\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { nextTick, onMounted, onUnmounted, reactive, ref, useTemplateRef, watch } from \"vue\";\nimport { RadioGroupRoot, RadioGroupItem } from \"reka-ui\";\nimport { cn, optional } from \"@ecoma-io/loom-core\";\nimport { useSplitAttrs } from \"@ecoma-io/loom-core\";\nimport { useAncestorDisabled } from \"@ecoma-io/loom-labels\";\nimport { useFieldControl } from \"@ecoma-io/loom-labels\";\n\n/**\n * SegmentedControl — pick one of 2-5 mutually exclusive options, all visible\n * at once; one is always active. Built on Reka UI's RadioGroup (single\n * choice, roving tabindex — the group is one Tab stop, not N — with\n * arrow-key navigation). Styled with Loom tokens.\n *\n * Inside a [Field](../Field/Field.vue) the row's description, `name`,\n * `required` and `invalid` reach the group through `useFieldControl()`.\n *\n * **A row's label does not name this group.** `<label for>` names a labelable\n * element and this renders a `div[role=\"radiogroup\"]`, so the row's label\n * resolves to the element and names nobody. Name it with a\n * [Fieldset](../Fieldset/Fieldset.vue)'s real `<legend>`, or with an\n * `aria-label`/`aria-labelledby` of its own — which is what every example\n * already does, because the control carries no label text.\n *\n * There is no `readonly`, and a row's is ignored rather than approximated: each\n * segment is a `<button role=\"radio\">` with no native read-only state to put it\n * in, and one segment is always active, so a read-only control here would be a\n * disabled one showing an answer.\n */\nconst props = withDefaults(\n defineProps<{\n /** The selected option's `value`. */\n modelValue?: string;\n /** The segments to render, in order. */\n options: SegmentedControlOption[];\n /** Disables every segment at once, distinct from a single option's own `disabled`. Unset defers to a wrapping Field. */\n disabled?: boolean | undefined;\n /** `\"sm\"` is the compressed form for dense chrome — e.g. a status bar density level. */\n size?: \"default\" | \"sm\";\n }>(),\n {\n // Not `false`: absent has to stay tellable from `false` for a Field above\n // to disable the control 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 size: \"default\",\n },\n);\n\ndefineEmits<{ \"update:modelValue\": [value: string] }>();\n\ndefineOptions({ inheritAttrs: false });\nconst { attrs, rest: groupAttrs } = useSplitAttrs();\n\n/**\n * The segments are real `<button>`s, so a `<fieldset disabled>` above this\n * control already makes each of them inert — but Reka's roving focus is what\n * decides where Tab lands, and it is driven by the group's own `disabled`,\n * which the fieldset never reaches. Measured on this branch: every segment went\n * `:disabled` while the `role=\"radiogroup\"` container kept `tabindex=\"0\"`, so\n * Tab still stopped on an unavailable control and left the reader nowhere. Its\n * own `disabled` prop sets that to `-1`.\n *\n * Reading the group state here rather than painting it with a CSS variant is\n * also what keeps the appearance honest, and this is the control where the\n * distinction bites: one option may carry `disabled` of its own, so \"a\n * `:disabled` button is inside this track\" and \"this track is unavailable\" are\n * different facts. Only the fieldset says the second.\n *\n * Read off the DOM rather than taken from the Field context, which publishes no\n * `disabled` on purpose — see `../../lib/ancestor-disabled.ts`.\n */\nconst root = useTemplateRef<{ $el?: Element }>(\"root\");\nconst groupDisabled = useAncestorDisabled(() => root.value?.$el);\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** `groupAttrs`, and that position is the contract (see TextField.vue).\n//\n// `name`, `required` and `invalid` are omitted because this component has no\n// prop for any of them — the row's answer stands unopposed, and its `name`\n// reaches RadioGroupRoot's own prop, which mints the hidden input a `<form>`\n// submits. `readonly` is omitted for the reason the docblock gives.\n//\n// The resolved `required` then reaches the group through Reka's own prop rather\n// than the `aria-required` in `field.attrs`: RadioGroupRoot writes that\n// attribute itself, so leaving it to the bag is a race with a `false` — see\n// Checkbox.vue, where the merge order makes the same race a certainty.\nconst field = useFieldControl(() => ({\n id: attrs.id as string | undefined,\n describedBy: attrs[\"aria-describedby\"] as string | undefined,\n // The fieldset beats the prop in both directions, exactly as it does for the\n // segments themselves.\n disabled: groupDisabled.value ? true : props.disabled,\n}));\n\n// Shared sliding indicator behind the checked segment. Measured off the live\n// DOM (offsetLeft/offsetWidth of the [data-state=checked] item), not derived\n// from index/width math, so \"sm\"/\"default\" sizing and variable-width labels\n// stay correct without per-size indicator code.\nconst indicatorEl = ref<HTMLElement | null>(null);\nconst indicatorStyle = reactive({ left: \"0px\", width: \"0px\", opacity: \"0\" });\n\nlet resizeObserver: ResizeObserver | undefined;\n\n// Re-targets onto the checked item itself (not the container) so a late\n// width settle on exactly that element — e.g. the `font-medium` weight swap\n// on data-[state=checked] reflowing after this function's own read — is\n// caught by the observer and re-measured, instead of going unnoticed because\n// the container's total box happened not to change.\nfunction updateIndicator() {\n const container = indicatorEl.value?.parentElement;\n const active = container?.querySelector<HTMLElement>('[role=\"radio\"][data-state=\"checked\"]');\n if (!active) {\n indicatorStyle.opacity = \"0\";\n resizeObserver?.disconnect();\n return;\n }\n indicatorStyle.left = `${active.offsetLeft}px`;\n indicatorStyle.width = `${active.offsetWidth}px`;\n indicatorStyle.opacity = \"1\";\n resizeObserver?.disconnect();\n resizeObserver?.observe(active);\n}\n\nonMounted(() => {\n resizeObserver = new ResizeObserver(updateIndicator);\n updateIndicator();\n});\nonUnmounted(() => resizeObserver?.disconnect());\n\n// One watcher for both re-measure triggers, and deliberately **not** deep on\n// `options`. The two separate watches each scheduled the same\n// `nextTick(updateIndicator)`, so one host tick that changed both inputs paid\n// the measurement twice; merging them costs nothing and removes the double.\n// Dropping `deep:` is not a regression: an in-place mutation of an option\n// object only matters to the indicator if it changes a *width* — a label edit,\n// say — and the ResizeObserver above is already watching exactly the checked\n// element for that, so the deep traversal bought nothing the observer does not\n// deliver sooner. A new array identity or a new selection still fires this.\nwatch([() => props.modelValue, () => props.options], () => nextTick(updateIndicator));\n</script>\n\n<template>\n <RadioGroupRoot\n ref=\"root\"\n v-bind=\"{ ...optional({ modelValue }), ...groupAttrs, ...field.attrs }\"\n :disabled=\"field.disabled\"\n :required=\"field.required\"\n orientation=\"horizontal\"\n :class=\"\n cn(\n 'relative inline-flex items-center gap-0.5 rounded-md border border-input bg-muted p-0.5',\n // The one thing the *track* has left to say. Its fill is already\n // `bg-muted` — the well every other unavailable control drains to — so\n // the fill channel is spent before the state arrives, and the segments\n // inside carry the rest. The rim slackening from `input` to the lighter\n // `border` is what makes a wholly unavailable control tellable from an\n // available one at the group's own edge rather than only cell by cell.\n field.disabled && 'cursor-not-allowed border-border',\n attrs.class as string,\n )\n \"\n @update:model-value=\"$emit('update:modelValue', String($event))\"\n >\n <span\n ref=\"indicatorEl\"\n aria-hidden=\"true\"\n class=\"pointer-events-none absolute inset-y-0.5 rounded-sm bg-card shadow-sm\"\n style=\"\n transition:\n left var(--duration-fast) var(--ease-spring),\n width var(--duration-fast) var(--ease-spring);\n \"\n :style=\"{\n left: indicatorStyle.left,\n width: indicatorStyle.width,\n opacity: indicatorStyle.opacity,\n }\"\n />\n <RadioGroupItem\n v-for=\"opt in options\"\n :key=\"opt.value\"\n :value=\"opt.value\"\n :disabled=\"opt.disabled ?? false\"\n v-bind=\"optional({ 'data-testid': opt.testId })\"\n style=\"\n transition:\n transform var(--duration-fast) var(--ease-spring),\n color var(--duration-fast) var(--ease-out);\n \"\n :class=\"\n cn(\n // Named, not the bare `group`: a segmented control is dropped into\n // application chrome, and a bare `group-*` would also answer to any\n // ancestor a host happened to mark up as one.\n // `min-h-6`/`min-w-6` are the WCAG 2.5.8 target floors made\n // explicit: the sm segment's box was previously a product of whatever\n // line-height the surrounding text happened to hand down — swapping\n // to the named `text-micro` (line-height 1.4) dropped it to 23px,\n // and a micro label (a one-character density toggle) collapses the\n // width under 24 too. Floors that hold regardless of type metrics\n // are the honest encoding.\n 'group/segment relative z-10 inline-flex min-h-6 min-w-6 items-center justify-center rounded-sm text-muted-foreground',\n size === 'sm' ? 'px-1.5 py-px text-micro' : 'px-3 py-1 text-sm',\n 'data-[state=checked]:font-medium data-[state=checked]:text-foreground',\n 'data-[state=unchecked]:hover:bg-subtle',\n 'active:scale-press',\n 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo',\n // No `opacity` here. A segment *is* its label — there is no glyph and\n // no fill of its own to dim — so `disabled:opacity-50` had nothing to\n // act on but the text, taking an unchecked segment to 1.96:1 and a\n // chosen one to 3.13:1 on its thumb.\n //\n // Unavailability is a fill instead, and it is the one step this\n // system already treats as meaningful: the cell drains up a rung of\n // the elevation rhythm, from the track's `bg-muted` to the page's own\n // `bg-background`, so it reads as a hole in the track rather than as\n // part of it. On a *chosen* segment that same fill covers the raised\n // white thumb, which is the whole signal — the value is still shown\n // and it is visibly no longer settable.\n 'disabled:pointer-events-none data-[disabled]:bg-background',\n )\n \"\n >\n <!-- The mute lives on this span rather than on the segment, and it has\n to. `data-[disabled]:` sorts *before* `data-[state=checked]:` in\n Tailwind's variant order, so a disabled segment that is also the\n chosen one would take `text-foreground` from the button — and a\n colour set on the button is only inherited here. Declared on the span\n it wins whatever the segment resolved to: 5.25:1 over the drained\n fill, against the 1.96:1 the dim used to leave. -->\n <span class=\"group-data-[disabled]/segment:text-muted-foreground\">{{ opt.label }}</span>\n </RadioGroupItem>\n </RadioGroupRoot>\n</template>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SegmentedControl.vue.d.ts","sourceRoot":"","sources":["../../../../../packages/primitives/segmented-control/src/SegmentedControl.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SegmentedControl.vue.d.ts","sourceRoot":"","sources":["../../../../../packages/primitives/segmented-control/src/SegmentedControl.vue"],"names":[],"mappings":"AAyQA,iDAAiD;AACjD,MAAM,WAAW,sBAAsB;IACrC,oCAAoC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;wBACoB,OAAO,YAAY;AAAxC,wBAAyC;AACzC,QAAA,MAAM,YAAY;IAuBd,qCAAqC;iBACxB,MAAM;IACnB,wCAAwC;aAC/B,sBAAsB,EAAE;IACjC,wHAAwH;eAC7G,OAAO,GAAG,SAAS;IAC9B,wFAAwF;WACjF,SAAS,GAAG,IAAI;;;;IAPvB,qCAAqC;iBACxB,MAAM;IACnB,wCAAwC;aAC/B,sBAAsB,EAAE;IACjC,wHAAwH;eAC7G,OAAO,GAAG,SAAS;IAC9B,wFAAwF;WACjF,SAAS,GAAG,IAAI;;;;UAAhB,SAAS,GAAG,IAAI;cAFZ,OAAO,GAAG,SAAS;6EAgV9B,CAAC"}
|
|
@@ -75,8 +75,7 @@ var SegmentedControl_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
|
|
|
75
75
|
updateIndicator();
|
|
76
76
|
});
|
|
77
77
|
onUnmounted(() => resizeObserver?.disconnect());
|
|
78
|
-
watch(() => props.modelValue, () => nextTick(updateIndicator));
|
|
79
|
-
watch(() => props.options, () => nextTick(updateIndicator), { deep: true });
|
|
78
|
+
watch([() => props.modelValue, () => props.options], () => nextTick(updateIndicator));
|
|
80
79
|
return (_ctx, _cache) => {
|
|
81
80
|
return openBlock(), createBlock(unref(RadioGroupRoot), mergeProps({
|
|
82
81
|
ref_key: "root",
|
|
@@ -109,7 +108,7 @@ var SegmentedControl_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
|
|
|
109
108
|
disabled: opt.disabled ?? false
|
|
110
109
|
}, { ref_for: true }, unref(optional)({ "data-testid": opt.testId }), {
|
|
111
110
|
style: { "transition": "transform var(--duration-fast) var(--ease-spring),\n color var(--duration-fast) var(--ease-out)" },
|
|
112
|
-
class: unref(cn)("group/segment relative z-10 inline-flex items-center justify-center rounded-sm text-muted-foreground", __props.size === "sm" ? "px-1.5 py-px text-
|
|
111
|
+
class: unref(cn)("group/segment relative z-10 inline-flex min-h-6 min-w-6 items-center justify-center rounded-sm text-muted-foreground", __props.size === "sm" ? "px-1.5 py-px text-micro" : "px-3 py-1 text-sm", "data-[state=checked]:font-medium data-[state=checked]:text-foreground", "data-[state=unchecked]:hover:bg-subtle", "active:scale-press", "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo", "disabled:pointer-events-none data-[disabled]:bg-background")
|
|
113
112
|
}), {
|
|
114
113
|
default: withCtx(() => [createElementVNode("span", _hoisted_1, toDisplayString(opt.label), 1)]),
|
|
115
114
|
_: 2
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SegmentedControl.vue_vue_type_script_setup_true_lang.js","names":["$emit"],"sources":["../../../../../packages/primitives/segmented-control/src/SegmentedControl.vue"],"sourcesContent":["<script lang=\"ts\">\n/** One segment in a {@link SegmentedControl}. */\nexport interface SegmentedControlOption {\n /** Matched against `modelValue`. */\n value: string;\n /** Visible label, rendered inside the segment. */\n label: string;\n /** Disables this segment alone, leaving its neighbours pickable. */\n disabled?: boolean;\n /** Forwarded to the segment's DOM node — lets hosts keep stable test hooks. */\n testId?: string;\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { nextTick, onMounted, onUnmounted, reactive, ref, useTemplateRef, watch } from \"vue\";\nimport { RadioGroupRoot, RadioGroupItem } from \"reka-ui\";\nimport { cn, optional } from \"@ecoma-io/loom-core\";\nimport { useSplitAttrs } from \"@ecoma-io/loom-core\";\nimport { useAncestorDisabled } from \"@ecoma-io/loom-labels\";\nimport { useFieldControl } from \"@ecoma-io/loom-labels\";\n\n/**\n * SegmentedControl — pick one of 2-5 mutually exclusive options, all visible\n * at once; one is always active. Built on Reka UI's RadioGroup (single\n * choice, roving tabindex — the group is one Tab stop, not N — with\n * arrow-key navigation). Styled with Loom tokens.\n *\n * Inside a [Field](../Field/Field.vue) the row's description, `name`,\n * `required` and `invalid` reach the group through `useFieldControl()`.\n *\n * **A row's label does not name this group.** `<label for>` names a labelable\n * element and this renders a `div[role=\"radiogroup\"]`, so the row's label\n * resolves to the element and names nobody. Name it with a\n * [Fieldset](../Fieldset/Fieldset.vue)'s real `<legend>`, or with an\n * `aria-label`/`aria-labelledby` of its own — which is what every example\n * already does, because the control carries no label text.\n *\n * There is no `readonly`, and a row's is ignored rather than approximated: each\n * segment is a `<button role=\"radio\">` with no native read-only state to put it\n * in, and one segment is always active, so a read-only control here would be a\n * disabled one showing an answer.\n */\nconst props = withDefaults(\n defineProps<{\n /** The selected option's `value`. */\n modelValue?: string;\n /** The segments to render, in order. */\n options: SegmentedControlOption[];\n /** Disables every segment at once, distinct from a single option's own `disabled`. Unset defers to a wrapping Field. */\n disabled?: boolean | undefined;\n /** `\"sm\"` is the compressed form for dense chrome — e.g. a status bar density level. */\n size?: \"default\" | \"sm\";\n }>(),\n {\n // Not `false`: absent has to stay tellable from `false` for a Field above\n // to disable the control 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 size: \"default\",\n },\n);\n\ndefineEmits<{ \"update:modelValue\": [value: string] }>();\n\ndefineOptions({ inheritAttrs: false });\nconst { attrs, rest: groupAttrs } = useSplitAttrs();\n\n/**\n * The segments are real `<button>`s, so a `<fieldset disabled>` above this\n * control already makes each of them inert — but Reka's roving focus is what\n * decides where Tab lands, and it is driven by the group's own `disabled`,\n * which the fieldset never reaches. Measured on this branch: every segment went\n * `:disabled` while the `role=\"radiogroup\"` container kept `tabindex=\"0\"`, so\n * Tab still stopped on an unavailable control and left the reader nowhere. Its\n * own `disabled` prop sets that to `-1`.\n *\n * Reading the group state here rather than painting it with a CSS variant is\n * also what keeps the appearance honest, and this is the control where the\n * distinction bites: one option may carry `disabled` of its own, so \"a\n * `:disabled` button is inside this track\" and \"this track is unavailable\" are\n * different facts. Only the fieldset says the second.\n *\n * Read off the DOM rather than taken from the Field context, which publishes no\n * `disabled` on purpose — see `../../lib/ancestor-disabled.ts`.\n */\nconst root = useTemplateRef<{ $el?: Element }>(\"root\");\nconst groupDisabled = useAncestorDisabled(() => root.value?.$el);\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** `groupAttrs`, and that position is the contract (see TextField.vue).\n//\n// `name`, `required` and `invalid` are omitted because this component has no\n// prop for any of them — the row's answer stands unopposed, and its `name`\n// reaches RadioGroupRoot's own prop, which mints the hidden input a `<form>`\n// submits. `readonly` is omitted for the reason the docblock gives.\n//\n// The resolved `required` then reaches the group through Reka's own prop rather\n// than the `aria-required` in `field.attrs`: RadioGroupRoot writes that\n// attribute itself, so leaving it to the bag is a race with a `false` — see\n// Checkbox.vue, where the merge order makes the same race a certainty.\nconst field = useFieldControl(() => ({\n id: attrs.id as string | undefined,\n describedBy: attrs[\"aria-describedby\"] as string | undefined,\n // The fieldset beats the prop in both directions, exactly as it does for the\n // segments themselves.\n disabled: groupDisabled.value ? true : props.disabled,\n}));\n\n// Shared sliding indicator behind the checked segment. Measured off the live\n// DOM (offsetLeft/offsetWidth of the [data-state=checked] item), not derived\n// from index/width math, so \"sm\"/\"default\" sizing and variable-width labels\n// stay correct without per-size indicator code.\nconst indicatorEl = ref<HTMLElement | null>(null);\nconst indicatorStyle = reactive({ left: \"0px\", width: \"0px\", opacity: \"0\" });\n\nlet resizeObserver: ResizeObserver | undefined;\n\n// Re-targets onto the checked item itself (not the container) so a late\n// width settle on exactly that element — e.g. the `font-medium` weight swap\n// on data-[state=checked] reflowing after this function's own read — is\n// caught by the observer and re-measured, instead of going unnoticed because\n// the container's total box happened not to change.\nfunction updateIndicator() {\n const container = indicatorEl.value?.parentElement;\n const active = container?.querySelector<HTMLElement>('[role=\"radio\"][data-state=\"checked\"]');\n if (!active) {\n indicatorStyle.opacity = \"0\";\n resizeObserver?.disconnect();\n return;\n }\n indicatorStyle.left = `${active.offsetLeft}px`;\n indicatorStyle.width = `${active.offsetWidth}px`;\n indicatorStyle.opacity = \"1\";\n resizeObserver?.disconnect();\n resizeObserver?.observe(active);\n}\n\nonMounted(() => {\n resizeObserver = new ResizeObserver(updateIndicator);\n updateIndicator();\n});\nonUnmounted(() => resizeObserver?.disconnect());\n\nwatch(\n () => props.modelValue,\n () => nextTick(updateIndicator),\n);\nwatch(\n () => props.options,\n () => nextTick(updateIndicator),\n { deep: true },\n);\n</script>\n\n<template>\n <RadioGroupRoot\n ref=\"root\"\n v-bind=\"{ ...optional({ modelValue }), ...groupAttrs, ...field.attrs }\"\n :disabled=\"field.disabled\"\n :required=\"field.required\"\n orientation=\"horizontal\"\n :class=\"\n cn(\n 'relative inline-flex items-center gap-0.5 rounded-md border border-input bg-muted p-0.5',\n // The one thing the *track* has left to say. Its fill is already\n // `bg-muted` — the well every other unavailable control drains to — so\n // the fill channel is spent before the state arrives, and the segments\n // inside carry the rest. The rim slackening from `input` to the lighter\n // `border` is what makes a wholly unavailable control tellable from an\n // available one at the group's own edge rather than only cell by cell.\n field.disabled && 'cursor-not-allowed border-border',\n attrs.class as string,\n )\n \"\n @update:model-value=\"$emit('update:modelValue', String($event))\"\n >\n <span\n ref=\"indicatorEl\"\n aria-hidden=\"true\"\n class=\"pointer-events-none absolute inset-y-0.5 rounded-sm bg-card shadow-sm\"\n style=\"\n transition:\n left var(--duration-fast) var(--ease-spring),\n width var(--duration-fast) var(--ease-spring);\n \"\n :style=\"{\n left: indicatorStyle.left,\n width: indicatorStyle.width,\n opacity: indicatorStyle.opacity,\n }\"\n />\n <RadioGroupItem\n v-for=\"opt in options\"\n :key=\"opt.value\"\n :value=\"opt.value\"\n :disabled=\"opt.disabled ?? false\"\n v-bind=\"optional({ 'data-testid': opt.testId })\"\n style=\"\n transition:\n transform var(--duration-fast) var(--ease-spring),\n color var(--duration-fast) var(--ease-out);\n \"\n :class=\"\n cn(\n // Named, not the bare `group`: a segmented control is dropped into\n // application chrome, and a bare `group-*` would also answer to any\n // ancestor a host happened to mark up as one.\n 'group/segment relative z-10 inline-flex items-center justify-center rounded-sm text-muted-foreground',\n size === 'sm' ? 'px-1.5 py-px text-[11px]' : 'px-3 py-1 text-sm',\n 'data-[state=checked]:font-medium data-[state=checked]:text-foreground',\n 'data-[state=unchecked]:hover:bg-subtle',\n 'active:scale-press',\n 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo',\n // No `opacity` here. A segment *is* its label — there is no glyph and\n // no fill of its own to dim — so `disabled:opacity-50` had nothing to\n // act on but the text, taking an unchecked segment to 1.96:1 and a\n // chosen one to 3.13:1 on its thumb.\n //\n // Unavailability is a fill instead, and it is the one step this\n // system already treats as meaningful: the cell drains up a rung of\n // the elevation rhythm, from the track's `bg-muted` to the page's own\n // `bg-background`, so it reads as a hole in the track rather than as\n // part of it. On a *chosen* segment that same fill covers the raised\n // white thumb, which is the whole signal — the value is still shown\n // and it is visibly no longer settable.\n 'disabled:pointer-events-none data-[disabled]:bg-background',\n )\n \"\n >\n <!-- The mute lives on this span rather than on the segment, and it has\n to. `data-[disabled]:` sorts *before* `data-[state=checked]:` in\n Tailwind's variant order, so a disabled segment that is also the\n chosen one would take `text-foreground` from the button — and a\n colour set on the button is only inherited here. Declared on the span\n it wins whatever the segment resolved to: 5.25:1 over the drained\n fill, against the 1.96:1 the dim used to leave. -->\n <span class=\"group-data-[disabled]/segment:text-muted-foreground\">{{ opt.label }}</span>\n </RadioGroupItem>\n </RadioGroupRoot>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;EA2CA,MAAM,QAAQ;EAwBd,MAAM,EAAE,OAAO,MAAM,eAAe,cAAc;;;;;;;;;;;;;;;;;;;EAoBlD,MAAM,OAAO,eAAkC,MAAM;EACrD,MAAM,gBAAgB,0BAA0B,KAAK,OAAO,GAAG;EAkB/D,MAAM,QAAQ,uBAAuB;GACnC,IAAI,MAAM;GACV,aAAa,MAAM;GAGnB,UAAU,cAAc,QAAQ,OAAO,MAAM;EAC/C,EAAE;EAMF,MAAM,cAAc,IAAwB,IAAI;EAChD,MAAM,iBAAiB,SAAS;GAAE,MAAM;GAAO,OAAO;GAAO,SAAS;EAAI,CAAC;EAE3E,IAAI;EAOJ,SAAS,kBAAkB;GAEzB,MAAM,UADY,YAAY,OAAO,cAAA,EACX,cAA2B,0CAAsC;GAC3F,IAAI,CAAC,QAAQ;IACX,eAAe,UAAU;IACzB,gBAAgB,WAAW;IAC3B;GACF;GACA,eAAe,OAAO,GAAG,OAAO,WAAW;GAC3C,eAAe,QAAQ,GAAG,OAAO,YAAY;GAC7C,eAAe,UAAU;GACzB,gBAAgB,WAAW;GAC3B,gBAAgB,QAAQ,MAAM;EAChC;EAEA,gBAAgB;GACd,iBAAiB,IAAI,eAAe,eAAe;GACnD,gBAAgB;EAClB,CAAC;EACD,kBAAkB,gBAAgB,WAAW,CAAC;EAE9C,YACQ,MAAM,kBACN,SAAS,eAAe,CAChC;EACA,YACQ,MAAM,eACN,SAAS,eAAe,GAC9B,EAAE,MAAM,KAAK,CACf;;GAIE,OAAA,UAAA,GAAA,YAmFiB,MAAA,cAAA,GAnFjB,WAmFiB;IAlFX,SAAA;IAAJ,KAAI;GACS,GAAA;IAAA,GAAA,MAAA,QAAA,CAAQ,CAAA,EAAA,YAAG,QAAA,WAAU,CAAA;IAAA,GAAQ,MAAA,UAAA;IAAU,GAAK,MAAA,KAAA,CAAK,CAAC;GAAK,GAAA;IACnE,UAAU,MAAA,KAAA,CAAK,CAAC;IAChB,UAAU,MAAA,KAAA,CAAK,CAAC;IACjB,aAAY;IACX,OAAc,MAAA,EAAA,CAAE,CAAA,2FAAwkB,MAAA,KAAA,CAAK,CAAC,YAAQ,oCAAgD,MAAA,KAAA,CAAK,CAAC,KAAA;IAa5pB,uBAAkB,OAAA,OAAA,OAAA,MAAA,WAAEA,KAAAA,MAAK,qBAAsB,OAAO,MAAM,CAAA;;IAE7D,SAAA,cAcE,CAdF,mBAcE,QAAA;KAbI,SAAA;KAAJ,KAAI;KACJ,eAAY;KACZ,OAAM;KACN,OAIC,eAAA,CAJD,EAAA,cAAA,yGAAA,GAIC;MACuB,MAAA,eAAe;MAAqB,OAAA,eAAe;MAAwB,SAAA,eAAe;;IAMpH,GAAA,MAAA,CAAA,IAAA,UAAA,IAAA,GAAA,mBA8CiB,UAAA,MAAA,WA7CD,QAAA,UAAP,QAAG;KADZ,OAAA,UAAA,GAAA,YA8CiB,MAAA,cAAA,GA9CjB,WA8CiB;MA5Cd,KAAK,IAAI;MACT,OAAO,IAAI;MACX,UAAU,IAAI,YAAQ;KACf,GAAA,EAAA,SAAA,KAAA,GAAA,MAAA,QAAA,CAAQ,CAAA,EAAA,eAAkB,IAAI,OAAM,CAAA,GAAA;MAC5C,OAAA,EAAA,cAAA,2GAAA;MAKC,OAAgB,MAAA,EAAA,CAAE,CAAA,wGAAoV,QAAA,SAAI,OAAA,6BAAA,qBAAA,yEAAA,0CAAA,sBAAA,+GAAA,4DAAA;;MAkC3W,SAAA,cAAwF,CAAxF,mBAAwF,QAAxF,YAAwF,gBAAnB,IAAI,KAAK,GAAA,CAAA,CAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"SegmentedControl.vue_vue_type_script_setup_true_lang.js","names":["$emit"],"sources":["../../../../../packages/primitives/segmented-control/src/SegmentedControl.vue"],"sourcesContent":["<script lang=\"ts\">\n/** One segment in a {@link SegmentedControl}. */\nexport interface SegmentedControlOption {\n /** Matched against `modelValue`. */\n value: string;\n /** Visible label, rendered inside the segment. */\n label: string;\n /** Disables this segment alone, leaving its neighbours pickable. */\n disabled?: boolean;\n /** Forwarded to the segment's DOM node — lets hosts keep stable test hooks. */\n testId?: string;\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { nextTick, onMounted, onUnmounted, reactive, ref, useTemplateRef, watch } from \"vue\";\nimport { RadioGroupRoot, RadioGroupItem } from \"reka-ui\";\nimport { cn, optional } from \"@ecoma-io/loom-core\";\nimport { useSplitAttrs } from \"@ecoma-io/loom-core\";\nimport { useAncestorDisabled } from \"@ecoma-io/loom-labels\";\nimport { useFieldControl } from \"@ecoma-io/loom-labels\";\n\n/**\n * SegmentedControl — pick one of 2-5 mutually exclusive options, all visible\n * at once; one is always active. Built on Reka UI's RadioGroup (single\n * choice, roving tabindex — the group is one Tab stop, not N — with\n * arrow-key navigation). Styled with Loom tokens.\n *\n * Inside a [Field](../Field/Field.vue) the row's description, `name`,\n * `required` and `invalid` reach the group through `useFieldControl()`.\n *\n * **A row's label does not name this group.** `<label for>` names a labelable\n * element and this renders a `div[role=\"radiogroup\"]`, so the row's label\n * resolves to the element and names nobody. Name it with a\n * [Fieldset](../Fieldset/Fieldset.vue)'s real `<legend>`, or with an\n * `aria-label`/`aria-labelledby` of its own — which is what every example\n * already does, because the control carries no label text.\n *\n * There is no `readonly`, and a row's is ignored rather than approximated: each\n * segment is a `<button role=\"radio\">` with no native read-only state to put it\n * in, and one segment is always active, so a read-only control here would be a\n * disabled one showing an answer.\n */\nconst props = withDefaults(\n defineProps<{\n /** The selected option's `value`. */\n modelValue?: string;\n /** The segments to render, in order. */\n options: SegmentedControlOption[];\n /** Disables every segment at once, distinct from a single option's own `disabled`. Unset defers to a wrapping Field. */\n disabled?: boolean | undefined;\n /** `\"sm\"` is the compressed form for dense chrome — e.g. a status bar density level. */\n size?: \"default\" | \"sm\";\n }>(),\n {\n // Not `false`: absent has to stay tellable from `false` for a Field above\n // to disable the control 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 size: \"default\",\n },\n);\n\ndefineEmits<{ \"update:modelValue\": [value: string] }>();\n\ndefineOptions({ inheritAttrs: false });\nconst { attrs, rest: groupAttrs } = useSplitAttrs();\n\n/**\n * The segments are real `<button>`s, so a `<fieldset disabled>` above this\n * control already makes each of them inert — but Reka's roving focus is what\n * decides where Tab lands, and it is driven by the group's own `disabled`,\n * which the fieldset never reaches. Measured on this branch: every segment went\n * `:disabled` while the `role=\"radiogroup\"` container kept `tabindex=\"0\"`, so\n * Tab still stopped on an unavailable control and left the reader nowhere. Its\n * own `disabled` prop sets that to `-1`.\n *\n * Reading the group state here rather than painting it with a CSS variant is\n * also what keeps the appearance honest, and this is the control where the\n * distinction bites: one option may carry `disabled` of its own, so \"a\n * `:disabled` button is inside this track\" and \"this track is unavailable\" are\n * different facts. Only the fieldset says the second.\n *\n * Read off the DOM rather than taken from the Field context, which publishes no\n * `disabled` on purpose — see `../../lib/ancestor-disabled.ts`.\n */\nconst root = useTemplateRef<{ $el?: Element }>(\"root\");\nconst groupDisabled = useAncestorDisabled(() => root.value?.$el);\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** `groupAttrs`, and that position is the contract (see TextField.vue).\n//\n// `name`, `required` and `invalid` are omitted because this component has no\n// prop for any of them — the row's answer stands unopposed, and its `name`\n// reaches RadioGroupRoot's own prop, which mints the hidden input a `<form>`\n// submits. `readonly` is omitted for the reason the docblock gives.\n//\n// The resolved `required` then reaches the group through Reka's own prop rather\n// than the `aria-required` in `field.attrs`: RadioGroupRoot writes that\n// attribute itself, so leaving it to the bag is a race with a `false` — see\n// Checkbox.vue, where the merge order makes the same race a certainty.\nconst field = useFieldControl(() => ({\n id: attrs.id as string | undefined,\n describedBy: attrs[\"aria-describedby\"] as string | undefined,\n // The fieldset beats the prop in both directions, exactly as it does for the\n // segments themselves.\n disabled: groupDisabled.value ? true : props.disabled,\n}));\n\n// Shared sliding indicator behind the checked segment. Measured off the live\n// DOM (offsetLeft/offsetWidth of the [data-state=checked] item), not derived\n// from index/width math, so \"sm\"/\"default\" sizing and variable-width labels\n// stay correct without per-size indicator code.\nconst indicatorEl = ref<HTMLElement | null>(null);\nconst indicatorStyle = reactive({ left: \"0px\", width: \"0px\", opacity: \"0\" });\n\nlet resizeObserver: ResizeObserver | undefined;\n\n// Re-targets onto the checked item itself (not the container) so a late\n// width settle on exactly that element — e.g. the `font-medium` weight swap\n// on data-[state=checked] reflowing after this function's own read — is\n// caught by the observer and re-measured, instead of going unnoticed because\n// the container's total box happened not to change.\nfunction updateIndicator() {\n const container = indicatorEl.value?.parentElement;\n const active = container?.querySelector<HTMLElement>('[role=\"radio\"][data-state=\"checked\"]');\n if (!active) {\n indicatorStyle.opacity = \"0\";\n resizeObserver?.disconnect();\n return;\n }\n indicatorStyle.left = `${active.offsetLeft}px`;\n indicatorStyle.width = `${active.offsetWidth}px`;\n indicatorStyle.opacity = \"1\";\n resizeObserver?.disconnect();\n resizeObserver?.observe(active);\n}\n\nonMounted(() => {\n resizeObserver = new ResizeObserver(updateIndicator);\n updateIndicator();\n});\nonUnmounted(() => resizeObserver?.disconnect());\n\n// One watcher for both re-measure triggers, and deliberately **not** deep on\n// `options`. The two separate watches each scheduled the same\n// `nextTick(updateIndicator)`, so one host tick that changed both inputs paid\n// the measurement twice; merging them costs nothing and removes the double.\n// Dropping `deep:` is not a regression: an in-place mutation of an option\n// object only matters to the indicator if it changes a *width* — a label edit,\n// say — and the ResizeObserver above is already watching exactly the checked\n// element for that, so the deep traversal bought nothing the observer does not\n// deliver sooner. A new array identity or a new selection still fires this.\nwatch([() => props.modelValue, () => props.options], () => nextTick(updateIndicator));\n</script>\n\n<template>\n <RadioGroupRoot\n ref=\"root\"\n v-bind=\"{ ...optional({ modelValue }), ...groupAttrs, ...field.attrs }\"\n :disabled=\"field.disabled\"\n :required=\"field.required\"\n orientation=\"horizontal\"\n :class=\"\n cn(\n 'relative inline-flex items-center gap-0.5 rounded-md border border-input bg-muted p-0.5',\n // The one thing the *track* has left to say. Its fill is already\n // `bg-muted` — the well every other unavailable control drains to — so\n // the fill channel is spent before the state arrives, and the segments\n // inside carry the rest. The rim slackening from `input` to the lighter\n // `border` is what makes a wholly unavailable control tellable from an\n // available one at the group's own edge rather than only cell by cell.\n field.disabled && 'cursor-not-allowed border-border',\n attrs.class as string,\n )\n \"\n @update:model-value=\"$emit('update:modelValue', String($event))\"\n >\n <span\n ref=\"indicatorEl\"\n aria-hidden=\"true\"\n class=\"pointer-events-none absolute inset-y-0.5 rounded-sm bg-card shadow-sm\"\n style=\"\n transition:\n left var(--duration-fast) var(--ease-spring),\n width var(--duration-fast) var(--ease-spring);\n \"\n :style=\"{\n left: indicatorStyle.left,\n width: indicatorStyle.width,\n opacity: indicatorStyle.opacity,\n }\"\n />\n <RadioGroupItem\n v-for=\"opt in options\"\n :key=\"opt.value\"\n :value=\"opt.value\"\n :disabled=\"opt.disabled ?? false\"\n v-bind=\"optional({ 'data-testid': opt.testId })\"\n style=\"\n transition:\n transform var(--duration-fast) var(--ease-spring),\n color var(--duration-fast) var(--ease-out);\n \"\n :class=\"\n cn(\n // Named, not the bare `group`: a segmented control is dropped into\n // application chrome, and a bare `group-*` would also answer to any\n // ancestor a host happened to mark up as one.\n // `min-h-6`/`min-w-6` are the WCAG 2.5.8 target floors made\n // explicit: the sm segment's box was previously a product of whatever\n // line-height the surrounding text happened to hand down — swapping\n // to the named `text-micro` (line-height 1.4) dropped it to 23px,\n // and a micro label (a one-character density toggle) collapses the\n // width under 24 too. Floors that hold regardless of type metrics\n // are the honest encoding.\n 'group/segment relative z-10 inline-flex min-h-6 min-w-6 items-center justify-center rounded-sm text-muted-foreground',\n size === 'sm' ? 'px-1.5 py-px text-micro' : 'px-3 py-1 text-sm',\n 'data-[state=checked]:font-medium data-[state=checked]:text-foreground',\n 'data-[state=unchecked]:hover:bg-subtle',\n 'active:scale-press',\n 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo',\n // No `opacity` here. A segment *is* its label — there is no glyph and\n // no fill of its own to dim — so `disabled:opacity-50` had nothing to\n // act on but the text, taking an unchecked segment to 1.96:1 and a\n // chosen one to 3.13:1 on its thumb.\n //\n // Unavailability is a fill instead, and it is the one step this\n // system already treats as meaningful: the cell drains up a rung of\n // the elevation rhythm, from the track's `bg-muted` to the page's own\n // `bg-background`, so it reads as a hole in the track rather than as\n // part of it. On a *chosen* segment that same fill covers the raised\n // white thumb, which is the whole signal — the value is still shown\n // and it is visibly no longer settable.\n 'disabled:pointer-events-none data-[disabled]:bg-background',\n )\n \"\n >\n <!-- The mute lives on this span rather than on the segment, and it has\n to. `data-[disabled]:` sorts *before* `data-[state=checked]:` in\n Tailwind's variant order, so a disabled segment that is also the\n chosen one would take `text-foreground` from the button — and a\n colour set on the button is only inherited here. Declared on the span\n it wins whatever the segment resolved to: 5.25:1 over the drained\n fill, against the 1.96:1 the dim used to leave. -->\n <span class=\"group-data-[disabled]/segment:text-muted-foreground\">{{ opt.label }}</span>\n </RadioGroupItem>\n </RadioGroupRoot>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;EA2CA,MAAM,QAAQ;EAwBd,MAAM,EAAE,OAAO,MAAM,eAAe,cAAc;;;;;;;;;;;;;;;;;;;EAoBlD,MAAM,OAAO,eAAkC,MAAM;EACrD,MAAM,gBAAgB,0BAA0B,KAAK,OAAO,GAAG;EAkB/D,MAAM,QAAQ,uBAAuB;GACnC,IAAI,MAAM;GACV,aAAa,MAAM;GAGnB,UAAU,cAAc,QAAQ,OAAO,MAAM;EAC/C,EAAE;EAMF,MAAM,cAAc,IAAwB,IAAI;EAChD,MAAM,iBAAiB,SAAS;GAAE,MAAM;GAAO,OAAO;GAAO,SAAS;EAAI,CAAC;EAE3E,IAAI;EAOJ,SAAS,kBAAkB;GAEzB,MAAM,UADY,YAAY,OAAO,cAAA,EACX,cAA2B,0CAAsC;GAC3F,IAAI,CAAC,QAAQ;IACX,eAAe,UAAU;IACzB,gBAAgB,WAAW;IAC3B;GACF;GACA,eAAe,OAAO,GAAG,OAAO,WAAW;GAC3C,eAAe,QAAQ,GAAG,OAAO,YAAY;GAC7C,eAAe,UAAU;GACzB,gBAAgB,WAAW;GAC3B,gBAAgB,QAAQ,MAAM;EAChC;EAEA,gBAAgB;GACd,iBAAiB,IAAI,eAAe,eAAe;GACnD,gBAAgB;EAClB,CAAC;EACD,kBAAkB,gBAAgB,WAAW,CAAC;EAW9C,MAAM,OAAO,MAAM,kBAAkB,MAAM,OAAO,SAAS,SAAS,eAAe,CAAC;;GAIlF,OAAA,UAAA,GAAA,YA0FiB,MAAA,cAAA,GA1FjB,WA0FiB;IAzFX,SAAA;IAAJ,KAAI;GACS,GAAA;IAAA,GAAA,MAAA,QAAA,CAAQ,CAAA,EAAA,YAAG,QAAA,WAAU,CAAA;IAAA,GAAQ,MAAA,UAAA;IAAU,GAAK,MAAA,KAAA,CAAK,CAAC;GAAK,GAAA;IACnE,UAAU,MAAA,KAAA,CAAK,CAAC;IAChB,UAAU,MAAA,KAAA,CAAK,CAAC;IACjB,aAAY;IACX,OAAc,MAAA,EAAA,CAAE,CAAA,2FAAwkB,MAAA,KAAA,CAAK,CAAC,YAAQ,oCAAgD,MAAA,KAAA,CAAK,CAAC,KAAA;IAa5pB,uBAAkB,OAAA,OAAA,OAAA,MAAA,WAAEA,KAAAA,MAAK,qBAAsB,OAAO,MAAM,CAAA;;IAE7D,SAAA,cAcE,CAdF,mBAcE,QAAA;KAbI,SAAA;KAAJ,KAAI;KACJ,eAAY;KACZ,OAAM;KACN,OAIC,eAAA,CAJD,EAAA,cAAA,yGAAA,GAIC;MACuB,MAAA,eAAe;MAAqB,OAAA,eAAe;MAAwB,SAAA,eAAe;;IAMpH,GAAA,MAAA,CAAA,IAAA,UAAA,IAAA,GAAA,mBAqDiB,UAAA,MAAA,WApDD,QAAA,UAAP,QAAG;KADZ,OAAA,UAAA,GAAA,YAqDiB,MAAA,cAAA,GArDjB,WAqDiB;MAnDd,KAAK,IAAI;MACT,OAAO,IAAI;MACX,UAAU,IAAI,YAAQ;KACf,GAAA,EAAA,SAAA,KAAA,GAAA,MAAA,QAAA,CAAQ,CAAA,EAAA,eAAkB,IAAI,OAAM,CAAA,GAAA;MAC5C,OAAA,EAAA,cAAA,2GAAA;MAKC,OAAgB,MAAA,EAAA,CAAE,CAAA,wHAAy1B,QAAA,SAAI,OAAA,4BAAA,qBAAA,yEAAA,0CAAA,sBAAA,+GAAA,4DAAA;;MAyCh3B,SAAA,cAAwF,CAAxF,mBAAwF,QAAxF,YAAwF,gBAAnB,IAAI,KAAK,GAAA,CAAA,CAAA,CAAA"}
|