@aleph-alpha/ui-library 1.13.0 → 1.14.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.
Files changed (120) hide show
  1. package/README.md +1 -1
  2. package/config.js +34 -1
  3. package/dist/system/index.d.ts +1728 -234
  4. package/dist/system/lib.js +19804 -16600
  5. package/package.json +1 -1
  6. package/src/components/UiKbd/UiKbd.stories.ts +1 -1
  7. package/src/components/UiNavigationMenu/UiNavigationMenu.stories.ts +1196 -0
  8. package/src/components/UiNavigationMenu/UiNavigationMenu.vue +39 -0
  9. package/src/components/UiNavigationMenu/UiNavigationMenuContent.vue +25 -0
  10. package/src/components/UiNavigationMenu/UiNavigationMenuIndicator.vue +14 -0
  11. package/src/components/UiNavigationMenu/UiNavigationMenuItem.vue +16 -0
  12. package/src/components/UiNavigationMenu/UiNavigationMenuLink.vue +27 -0
  13. package/src/components/UiNavigationMenu/UiNavigationMenuList.vue +16 -0
  14. package/src/components/UiNavigationMenu/UiNavigationMenuTrigger.vue +16 -0
  15. package/src/components/UiNavigationMenu/__tests__/UiNavigationMenu.test.ts +428 -0
  16. package/src/components/UiNavigationMenu/index.ts +11 -0
  17. package/src/components/UiNavigationMenu/types.ts +185 -0
  18. package/src/components/UiSheet/UiSheet.stories.ts +715 -0
  19. package/src/components/UiSheet/__tests__/UiSheet.test.ts +229 -0
  20. package/src/components/UiSheet/index.ts +12 -0
  21. package/src/components/UiSheet/types.ts +83 -0
  22. package/src/components/UiSidebar/UiSidebar.stories.ts +1010 -0
  23. package/src/components/UiSidebar/UiSidebar.vue +20 -0
  24. package/src/components/UiSidebar/UiSidebarGroupAction.vue +18 -0
  25. package/src/components/UiSidebar/UiSidebarGroupLabel.vue +18 -0
  26. package/src/components/UiSidebar/UiSidebarHeaderTrigger.vue +53 -0
  27. package/src/components/UiSidebar/UiSidebarInput.vue +14 -0
  28. package/src/components/UiSidebar/UiSidebarMenuAction.vue +19 -0
  29. package/src/components/UiSidebar/UiSidebarMenuButton.vue +27 -0
  30. package/src/components/UiSidebar/UiSidebarMenuSkeleton.vue +16 -0
  31. package/src/components/UiSidebar/UiSidebarMenuSubButton.vue +24 -0
  32. package/src/components/UiSidebar/UiSidebarProvider.vue +18 -0
  33. package/src/components/UiSidebar/UiSidebarSeparator.vue +13 -0
  34. package/src/components/UiSidebar/__tests__/UiSidebar.test.ts +221 -0
  35. package/src/components/UiSidebar/index.ts +34 -0
  36. package/src/components/UiSidebar/types.ts +168 -0
  37. package/src/components/UiStepper/UiStepper.stories.ts +425 -0
  38. package/src/components/UiStepper/UiStepper.vue +27 -0
  39. package/src/components/UiStepper/UiStepperDescription.vue +20 -0
  40. package/src/components/UiStepper/UiStepperIndicator.vue +13 -0
  41. package/src/components/UiStepper/UiStepperItem.vue +25 -0
  42. package/src/components/UiStepper/UiStepperSeparator.vue +17 -0
  43. package/src/components/UiStepper/UiStepperTitle.vue +19 -0
  44. package/src/components/UiStepper/UiStepperTrigger.vue +18 -0
  45. package/src/components/UiStepper/__tests__/UiStepper.test.ts +167 -0
  46. package/src/components/UiStepper/index.ts +9 -0
  47. package/src/components/UiStepper/types.ts +65 -0
  48. package/src/components/core/alert/index.ts +2 -2
  49. package/src/components/core/alert-dialog/AlertDialogContent.vue +1 -1
  50. package/src/components/core/card/Card.vue +1 -1
  51. package/src/components/core/drawer/DrawerContent.vue +1 -1
  52. package/src/components/core/dropdown-menu/DropdownMenuContent.vue +1 -1
  53. package/src/components/core/dropdown-menu/DropdownMenuSubContent.vue +1 -1
  54. package/src/components/core/input/Input.vue +1 -1
  55. package/src/components/core/native-select/NativeSelect.vue +1 -1
  56. package/src/components/core/native-select/NativeSelectOptGroup.vue +1 -1
  57. package/src/components/core/native-select/NativeSelectOption.vue +1 -1
  58. package/src/components/core/navigation-menu/NavigationMenu.vue +40 -0
  59. package/src/components/core/navigation-menu/NavigationMenuContent.vue +28 -0
  60. package/src/components/core/navigation-menu/NavigationMenuIndicator.vue +26 -0
  61. package/src/components/core/navigation-menu/NavigationMenuItem.vue +19 -0
  62. package/src/components/core/navigation-menu/NavigationMenuLink.vue +27 -0
  63. package/src/components/core/navigation-menu/NavigationMenuList.vue +21 -0
  64. package/src/components/core/navigation-menu/NavigationMenuTrigger.vue +27 -0
  65. package/src/components/core/navigation-menu/NavigationMenuViewport.vue +26 -0
  66. package/src/components/core/navigation-menu/index.ts +14 -0
  67. package/src/components/core/popover/PopoverContent.vue +1 -1
  68. package/src/components/core/select/SelectContent.vue +1 -1
  69. package/src/components/core/select/SelectTrigger.vue +1 -1
  70. package/src/components/core/sheet/Sheet.vue +15 -0
  71. package/src/components/core/sheet/SheetClose.vue +12 -0
  72. package/src/components/core/sheet/SheetContent.vue +56 -0
  73. package/src/components/core/sheet/SheetDescription.vue +19 -0
  74. package/src/components/core/sheet/SheetFooter.vue +9 -0
  75. package/src/components/core/sheet/SheetHeader.vue +9 -0
  76. package/src/components/core/sheet/SheetOverlay.vue +24 -0
  77. package/src/components/core/sheet/SheetTitle.vue +19 -0
  78. package/src/components/core/sheet/SheetTrigger.vue +12 -0
  79. package/src/components/core/sheet/index.ts +8 -0
  80. package/src/components/core/sidebar/Sidebar.vue +105 -0
  81. package/src/components/core/sidebar/SidebarContent.vue +21 -0
  82. package/src/components/core/sidebar/SidebarFooter.vue +16 -0
  83. package/src/components/core/sidebar/SidebarGroup.vue +16 -0
  84. package/src/components/core/sidebar/SidebarGroupAction.vue +25 -0
  85. package/src/components/core/sidebar/SidebarGroupContent.vue +16 -0
  86. package/src/components/core/sidebar/SidebarGroupLabel.vue +23 -0
  87. package/src/components/core/sidebar/SidebarHeader.vue +16 -0
  88. package/src/components/core/sidebar/SidebarInput.vue +17 -0
  89. package/src/components/core/sidebar/SidebarInset.vue +21 -0
  90. package/src/components/core/sidebar/SidebarMenu.vue +16 -0
  91. package/src/components/core/sidebar/SidebarMenuAction.vue +33 -0
  92. package/src/components/core/sidebar/SidebarMenuBadge.vue +26 -0
  93. package/src/components/core/sidebar/SidebarMenuButton.vue +49 -0
  94. package/src/components/core/sidebar/SidebarMenuButtonChild.vue +36 -0
  95. package/src/components/core/sidebar/SidebarMenuItem.vue +16 -0
  96. package/src/components/core/sidebar/SidebarMenuSkeleton.vue +32 -0
  97. package/src/components/core/sidebar/SidebarMenuSub.vue +22 -0
  98. package/src/components/core/sidebar/SidebarMenuSubButton.vue +38 -0
  99. package/src/components/core/sidebar/SidebarMenuSubItem.vue +16 -0
  100. package/src/components/core/sidebar/SidebarProvider.vue +102 -0
  101. package/src/components/core/sidebar/SidebarRail.vue +33 -0
  102. package/src/components/core/sidebar/SidebarSeparator.vue +17 -0
  103. package/src/components/core/sidebar/SidebarTrigger.vue +25 -0
  104. package/src/components/core/sidebar/index.ts +58 -0
  105. package/src/components/core/sidebar/utils.ts +19 -0
  106. package/src/components/core/stepper/Stepper.vue +20 -0
  107. package/src/components/core/stepper/StepperDescription.vue +23 -0
  108. package/src/components/core/stepper/StepperIndicator.vue +34 -0
  109. package/src/components/core/stepper/StepperItem.vue +23 -0
  110. package/src/components/core/stepper/StepperSeparator.vue +29 -0
  111. package/src/components/core/stepper/StepperTitle.vue +24 -0
  112. package/src/components/core/stepper/StepperTrigger.vue +22 -0
  113. package/src/components/core/stepper/index.ts +7 -0
  114. package/src/components/core/tabs/TabsTrigger.vue +1 -1
  115. package/src/components/core/tags-input/TagsInput.vue +1 -1
  116. package/src/components/core/textarea/Textarea.vue +1 -1
  117. package/src/components/index.ts +4 -0
  118. package/src/theme/Background.stories.ts +84 -35
  119. package/src/theme/Extended.stories.ts +4 -4
  120. package/tokens.json +145 -8
@@ -0,0 +1,167 @@
1
+ import '@testing-library/jest-dom/vitest';
2
+ import { render, waitFor } from '@testing-library/vue';
3
+ import userEvent from '@testing-library/user-event';
4
+ import { describe, expect, test, vi } from 'vitest';
5
+ import { ref } from 'vue';
6
+ import {
7
+ UiStepper,
8
+ UiStepperItem,
9
+ UiStepperTrigger,
10
+ UiStepperIndicator,
11
+ UiStepperTitle,
12
+ UiStepperDescription,
13
+ UiStepperSeparator,
14
+ } from '../index';
15
+
16
+ const components = {
17
+ UiStepper,
18
+ UiStepperItem,
19
+ UiStepperTrigger,
20
+ UiStepperIndicator,
21
+ UiStepperTitle,
22
+ UiStepperDescription,
23
+ UiStepperSeparator,
24
+ };
25
+
26
+ const stepperTemplate = `
27
+ <UiStepper v-bind="stepperProps" v-on="stepperEvents">
28
+ <UiStepperItem :step="1">
29
+ <UiStepperTrigger>
30
+ <UiStepperIndicator>1</UiStepperIndicator>
31
+ <UiStepperTitle>Step 1</UiStepperTitle>
32
+ </UiStepperTrigger>
33
+ <UiStepperSeparator />
34
+ </UiStepperItem>
35
+ <UiStepperItem :step="2">
36
+ <UiStepperTrigger>
37
+ <UiStepperIndicator>2</UiStepperIndicator>
38
+ <UiStepperTitle>Step 2</UiStepperTitle>
39
+ </UiStepperTrigger>
40
+ <UiStepperSeparator />
41
+ </UiStepperItem>
42
+ <UiStepperItem :step="3">
43
+ <UiStepperTrigger>
44
+ <UiStepperIndicator>3</UiStepperIndicator>
45
+ <UiStepperTitle>Step 3</UiStepperTitle>
46
+ </UiStepperTrigger>
47
+ </UiStepperItem>
48
+ </UiStepper>
49
+ `;
50
+
51
+ describe('UiStepper', () => {
52
+ test('activates step specified by defaultValue prop', () => {
53
+ const { getAllByRole } = render({
54
+ components,
55
+ template: stepperTemplate,
56
+ setup() {
57
+ return { stepperProps: { defaultValue: 2, linear: false }, stepperEvents: {} };
58
+ },
59
+ });
60
+
61
+ const triggers = getAllByRole('button');
62
+ expect(triggers[0]).toHaveAttribute('data-state', 'completed');
63
+ expect(triggers[1]).toHaveAttribute('data-state', 'active');
64
+ expect(triggers[2]).toHaveAttribute('data-state', 'inactive');
65
+ });
66
+
67
+ test('emits update:modelValue when a step trigger is clicked', async () => {
68
+ const user = userEvent.setup();
69
+ const onUpdateModelValue = vi.fn();
70
+
71
+ const { getAllByRole } = render({
72
+ components,
73
+ template: stepperTemplate,
74
+ setup() {
75
+ return {
76
+ stepperProps: { defaultValue: 1, linear: false },
77
+ stepperEvents: { 'update:modelValue': onUpdateModelValue },
78
+ };
79
+ },
80
+ });
81
+
82
+ const triggers = getAllByRole('button');
83
+ expect(triggers.length).toBe(3);
84
+
85
+ await user.click(triggers[1]);
86
+
87
+ expect(onUpdateModelValue).toHaveBeenCalledWith(2);
88
+ });
89
+
90
+ test('reflects controlled modelValue and updates when it changes', async () => {
91
+ const modelValue = ref(1);
92
+
93
+ const { getAllByRole } = render({
94
+ components,
95
+ template: `
96
+ <UiStepper v-model="modelValue" :linear="false">
97
+ <UiStepperItem :step="1">
98
+ <UiStepperTrigger>
99
+ <UiStepperIndicator>1</UiStepperIndicator>
100
+ <UiStepperTitle>Step 1</UiStepperTitle>
101
+ </UiStepperTrigger>
102
+ <UiStepperSeparator />
103
+ </UiStepperItem>
104
+ <UiStepperItem :step="2">
105
+ <UiStepperTrigger>
106
+ <UiStepperIndicator>2</UiStepperIndicator>
107
+ <UiStepperTitle>Step 2</UiStepperTitle>
108
+ </UiStepperTrigger>
109
+ </UiStepperItem>
110
+ </UiStepper>
111
+ `,
112
+ setup() {
113
+ return { modelValue };
114
+ },
115
+ });
116
+
117
+ const triggers = getAllByRole('button');
118
+ expect(triggers[0]).toHaveAttribute('data-state', 'active');
119
+ expect(triggers[1]).toHaveAttribute('data-state', 'inactive');
120
+
121
+ modelValue.value = 2;
122
+
123
+ await waitFor(() => {
124
+ expect(triggers[0]).toHaveAttribute('data-state', 'completed');
125
+ expect(triggers[1]).toHaveAttribute('data-state', 'active');
126
+ });
127
+ });
128
+
129
+ test('does not activate a disabled step when clicked', async () => {
130
+ const user = userEvent.setup();
131
+ const onUpdateModelValue = vi.fn();
132
+
133
+ const { getAllByRole } = render({
134
+ components,
135
+ template: `
136
+ <UiStepper :default-value="1" :linear="false" @update:modelValue="onUpdateModelValue">
137
+ <UiStepperItem :step="1">
138
+ <UiStepperTrigger>
139
+ <UiStepperIndicator>1</UiStepperIndicator>
140
+ <UiStepperTitle>Step 1</UiStepperTitle>
141
+ </UiStepperTrigger>
142
+ <UiStepperSeparator />
143
+ </UiStepperItem>
144
+ <UiStepperItem :step="2" :disabled="true">
145
+ <UiStepperTrigger>
146
+ <UiStepperIndicator>2</UiStepperIndicator>
147
+ <UiStepperTitle>Step 2</UiStepperTitle>
148
+ </UiStepperTrigger>
149
+ </UiStepperItem>
150
+ </UiStepper>
151
+ `,
152
+ setup() {
153
+ return { onUpdateModelValue };
154
+ },
155
+ });
156
+
157
+ const triggers = getAllByRole('button', { hidden: true });
158
+ const step2Trigger = triggers[1];
159
+ expect(step2Trigger).toBeDisabled();
160
+
161
+ await user.click(step2Trigger);
162
+
163
+ expect(triggers[0]).toHaveAttribute('data-state', 'active');
164
+ expect(step2Trigger).toHaveAttribute('data-state', 'inactive');
165
+ expect(onUpdateModelValue).not.toHaveBeenCalledWith(2);
166
+ });
167
+ });
@@ -0,0 +1,9 @@
1
+ export { default as UiStepper } from './UiStepper.vue';
2
+ export { default as UiStepperItem } from './UiStepperItem.vue';
3
+ export { default as UiStepperTrigger } from './UiStepperTrigger.vue';
4
+ export { default as UiStepperIndicator } from './UiStepperIndicator.vue';
5
+ export { default as UiStepperTitle } from './UiStepperTitle.vue';
6
+ export { default as UiStepperDescription } from './UiStepperDescription.vue';
7
+ export { default as UiStepperSeparator } from './UiStepperSeparator.vue';
8
+
9
+ export * from './types';
@@ -0,0 +1,65 @@
1
+ /** Orientation of the stepper layout. */
2
+ export type UiStepperOrientation = 'horizontal' | 'vertical';
3
+
4
+ /**
5
+ * A step-by-step navigation component for multi-step workflows. Use for
6
+ * wizards, checkout flows, onboarding sequences, or any process with
7
+ * sequential steps.
8
+ *
9
+ * @category Navigation
10
+ * @useCases wizard, checkout flow, onboarding, multi-step form, progress tracker
11
+ * @keywords stepper, steps, wizard, progress, sequential, workflow, multi-step
12
+ * @related UiProgress, UiTabs
13
+ */
14
+ export type UiStepperProps = {
15
+ /**
16
+ * The controlled value of the active step.
17
+ * - Omit for uncontrolled mode (uses defaultValue)
18
+ * - Use `v-model` for controlled mode
19
+ * @example
20
+ * ```vue
21
+ * <!-- Uncontrolled -->
22
+ * <UiStepper :default-value="1">...</UiStepper>
23
+ *
24
+ * <!-- Controlled -->
25
+ * <UiStepper v-model="currentStep">...</UiStepper>
26
+ * ```
27
+ */
28
+ modelValue?: number;
29
+ /**
30
+ * The step that should be active when initially rendered (uncontrolled mode).
31
+ * @default 1
32
+ */
33
+ defaultValue?: number;
34
+ /** The orientation of the stepper layout. */
35
+ orientation?: UiStepperOrientation;
36
+ /**
37
+ * Whether navigation must be sequential (user cannot skip ahead to incomplete steps).
38
+ * @default true
39
+ */
40
+ linear?: boolean;
41
+ };
42
+
43
+ /**
44
+ * Props for the UiStepperTrigger component.
45
+ */
46
+ export type UiStepperTriggerProps = {
47
+ /**
48
+ * Renders as the child element instead of the default trigger button.
49
+ * Use with UiIconButton or UiButton to customize the trigger appearance.
50
+ * @default false
51
+ */
52
+ asChild?: boolean;
53
+ };
54
+
55
+ /**
56
+ * Props for the UiStepperItem component.
57
+ */
58
+ export type UiStepperItemProps = {
59
+ /** The step number this item represents (required). */
60
+ step: number;
61
+ /** Whether this step is disabled and cannot be navigated to. */
62
+ disabled?: boolean;
63
+ /** Whether this step is marked as completed. */
64
+ completed?: boolean;
65
+ };
@@ -10,9 +10,9 @@ export const alertVariants = cva(
10
10
  {
11
11
  variants: {
12
12
  variant: {
13
- default: 'bg-popover text-popover-foreground',
13
+ default: 'bg-background-surface-muted text-content-on-surface-primary',
14
14
  destructive:
15
- 'text-destructive bg-popover [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90',
15
+ 'text-destructive bg-background-surface-muted [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90',
16
16
  },
17
17
  },
18
18
  defaultVariants: {
@@ -33,7 +33,7 @@
33
33
  v-bind="{ ...$attrs, ...forwarded }"
34
34
  :class="
35
35
  cn(
36
- 'bg-popover data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg',
36
+ 'bg-background-surface-modal data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border border-border-surface-default p-6 shadow-lg duration-200 sm:max-w-lg',
37
37
  props.class,
38
38
  )
39
39
  "
@@ -12,7 +12,7 @@
12
12
  data-slot="card"
13
13
  :class="
14
14
  cn(
15
- 'bg-popover text-popover-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm',
15
+ 'bg-background-surface-muted text-content-on-surface-primary flex flex-col gap-6 rounded-xl border py-6 shadow-sm',
16
16
  props.class,
17
17
  )
18
18
  "
@@ -36,7 +36,7 @@
36
36
  v-bind="{ ...$attrs, ...forwarded }"
37
37
  :class="
38
38
  cn(
39
- 'bg-popover data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=open]:slide-in-from-bottom-2 data-[state=closed]:slide-out-to-bottom-2 fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-lg border shadow-lg duration-200',
39
+ 'bg-background-surface-modal data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=open]:slide-in-from-bottom-2 data-[state=closed]:slide-out-to-bottom-2 fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-lg border border-border-surface-default shadow-lg duration-200',
40
40
  props.class,
41
41
  )
42
42
  "
@@ -29,7 +29,7 @@
29
29
  v-bind="{ ...$attrs, ...forwarded }"
30
30
  :class="
31
31
  cn(
32
- 'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--reka-dropdown-menu-content-available-height) min-w-[8rem] origin-(--reka-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md',
32
+ 'bg-background-surface-floating text-content-on-surface-primary data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--reka-dropdown-menu-content-available-height) min-w-[8rem] origin-(--reka-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border border-border-surface-default p-1 shadow-xs',
33
33
  props.class,
34
34
  )
35
35
  "
@@ -19,7 +19,7 @@
19
19
  v-bind="forwarded"
20
20
  :class="
21
21
  cn(
22
- 'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--reka-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg',
22
+ 'bg-background-surface-floating text-content-on-surface-primary data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--reka-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border border-border-surface-default p-1 shadow-xs',
23
23
  props.class,
24
24
  )
25
25
  "
@@ -25,7 +25,7 @@
25
25
  data-slot="input"
26
26
  :class="
27
27
  cn(
28
- 'file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground border-input h-9 w-full min-w-0 rounded-md border bg-input-background px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
28
+ 'file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground border-input h-9 w-full min-w-0 rounded-md border bg-background-input-default px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
29
29
  'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',
30
30
  'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',
31
31
  props.class,
@@ -37,7 +37,7 @@
37
37
  data-slot="native-select"
38
38
  :class="
39
39
  cn(
40
- 'border-input placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground h-9 w-full min-w-0 appearance-none rounded-md border bg-input-background px-3 py-2 pr-9 text-sm shadow-xs transition-[color,box-shadow] outline-none disabled:pointer-events-none disabled:cursor-not-allowed',
40
+ 'border-input placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground h-9 w-full min-w-0 appearance-none rounded-md border bg-background-input-default px-3 py-2 pr-9 text-sm shadow-xs transition-[color,box-shadow] outline-none disabled:pointer-events-none disabled:cursor-not-allowed',
41
41
  'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',
42
42
  'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',
43
43
  props.class,
@@ -11,7 +11,7 @@
11
11
  <template>
12
12
  <optgroup
13
13
  data-slot="native-select-optgroup"
14
- :class="cn('bg-popover text-popover-foreground', props.class)"
14
+ :class="cn('bg-background-surface-floating text-content-on-surface-primary', props.class)"
15
15
  >
16
16
  <slot />
17
17
  </optgroup>
@@ -11,7 +11,7 @@
11
11
  <template>
12
12
  <option
13
13
  data-slot="native-select-option"
14
- :class="cn('bg-popover text-popover-foreground', props.class)"
14
+ :class="cn('bg-background-surface-floating text-content-on-surface-primary', props.class)"
15
15
  >
16
16
  <slot />
17
17
  </option>
@@ -0,0 +1,40 @@
1
+ <script setup lang="ts">
2
+ import type { NavigationMenuRootEmits, NavigationMenuRootProps } from 'reka-ui';
3
+ import { NavigationMenuRoot, useForwardPropsEmits } from 'reka-ui';
4
+ import { cn } from '@/lib/utils';
5
+ import NavigationMenuViewport from './NavigationMenuViewport.vue';
6
+
7
+ defineOptions({ inheritAttrs: false });
8
+
9
+ const props = withDefaults(
10
+ defineProps<
11
+ NavigationMenuRootProps & {
12
+ viewport?: boolean;
13
+ }
14
+ >(),
15
+ {
16
+ viewport: true,
17
+ },
18
+ );
19
+ const emits = defineEmits<NavigationMenuRootEmits>();
20
+
21
+ const forwarded = useForwardPropsEmits(props, emits);
22
+ </script>
23
+
24
+ <template>
25
+ <NavigationMenuRoot
26
+ v-slot="slotProps"
27
+ data-slot="navigation-menu"
28
+ :data-viewport="viewport"
29
+ v-bind="{ ...forwarded, ...$attrs }"
30
+ :class="
31
+ cn(
32
+ 'group/navigation-menu relative flex max-w-max flex-1 items-center justify-center',
33
+ $attrs.class ?? '',
34
+ )
35
+ "
36
+ >
37
+ <slot v-bind="slotProps" />
38
+ <NavigationMenuViewport v-if="viewport" />
39
+ </NavigationMenuRoot>
40
+ </template>
@@ -0,0 +1,28 @@
1
+ <script setup lang="ts">
2
+ import type { NavigationMenuContentEmits, NavigationMenuContentProps } from 'reka-ui';
3
+ import { NavigationMenuContent, useForwardPropsEmits } from 'reka-ui';
4
+ import { cn } from '@/lib/utils';
5
+
6
+ defineOptions({ inheritAttrs: false });
7
+
8
+ const props = defineProps<NavigationMenuContentProps>();
9
+ const emits = defineEmits<NavigationMenuContentEmits>();
10
+
11
+ const forwarded = useForwardPropsEmits(props, emits);
12
+ </script>
13
+
14
+ <template>
15
+ <NavigationMenuContent
16
+ data-slot="navigation-menu-content"
17
+ v-bind="{ ...forwarded, ...$attrs }"
18
+ :class="
19
+ cn(
20
+ 'data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 top-0 left-0 w-full p-2 pr-2.5 md:absolute md:w-auto',
21
+ 'group-data-[viewport=false]/navigation-menu:bg-popover group-data-[viewport=false]/navigation-menu:text-popover-foreground group-data-[viewport=false]/navigation-menu:data-[state=open]:animate-in group-data-[viewport=false]/navigation-menu:data-[state=closed]:animate-out group-data-[viewport=false]/navigation-menu:data-[state=closed]:zoom-out-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:zoom-in-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:fade-in-0 group-data-[viewport=false]/navigation-menu:data-[state=closed]:fade-out-0 group-data-[viewport=false]/navigation-menu:top-full group-data-[viewport=false]/navigation-menu:mt-1.5 group-data-[viewport=false]/navigation-menu:overflow-hidden group-data-[viewport=false]/navigation-menu:rounded-md group-data-[viewport=false]/navigation-menu:border group-data-[viewport=false]/navigation-menu:shadow group-data-[viewport=false]/navigation-menu:duration-200 **:data-[slot=navigation-menu-link]:focus:ring-0 **:data-[slot=navigation-menu-link]:focus:outline-none',
22
+ $attrs.class ?? '',
23
+ )
24
+ "
25
+ >
26
+ <slot />
27
+ </NavigationMenuContent>
28
+ </template>
@@ -0,0 +1,26 @@
1
+ <script setup lang="ts">
2
+ import type { NavigationMenuIndicatorProps } from 'reka-ui';
3
+ import { NavigationMenuIndicator, useForwardProps } from 'reka-ui';
4
+ import { cn } from '@/lib/utils';
5
+
6
+ defineOptions({ inheritAttrs: false });
7
+
8
+ const props = defineProps<NavigationMenuIndicatorProps>();
9
+
10
+ const forwardedProps = useForwardProps(props);
11
+ </script>
12
+
13
+ <template>
14
+ <NavigationMenuIndicator
15
+ data-slot="navigation-menu-indicator"
16
+ v-bind="{ ...forwardedProps, ...$attrs }"
17
+ :class="
18
+ cn(
19
+ 'data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden',
20
+ $attrs.class ?? '',
21
+ )
22
+ "
23
+ >
24
+ <div class="bg-border relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm shadow-md" />
25
+ </NavigationMenuIndicator>
26
+ </template>
@@ -0,0 +1,19 @@
1
+ <script setup lang="ts">
2
+ import type { NavigationMenuItemProps } from 'reka-ui';
3
+ import { NavigationMenuItem } from 'reka-ui';
4
+ import { cn } from '@/lib/utils';
5
+
6
+ defineOptions({ inheritAttrs: false });
7
+
8
+ const props = defineProps<NavigationMenuItemProps>();
9
+ </script>
10
+
11
+ <template>
12
+ <NavigationMenuItem
13
+ data-slot="navigation-menu-item"
14
+ v-bind="{ ...props, ...$attrs }"
15
+ :class="cn('relative', $attrs.class ?? '')"
16
+ >
17
+ <slot />
18
+ </NavigationMenuItem>
19
+ </template>
@@ -0,0 +1,27 @@
1
+ <script setup lang="ts">
2
+ import type { NavigationMenuLinkEmits, NavigationMenuLinkProps } from 'reka-ui';
3
+ import { NavigationMenuLink, useForwardPropsEmits } from 'reka-ui';
4
+ import { cn } from '@/lib/utils';
5
+
6
+ defineOptions({ inheritAttrs: false });
7
+
8
+ const props = defineProps<NavigationMenuLinkProps>();
9
+ const emits = defineEmits<NavigationMenuLinkEmits>();
10
+
11
+ const forwarded = useForwardPropsEmits(props, emits);
12
+ </script>
13
+
14
+ <template>
15
+ <NavigationMenuLink
16
+ data-slot="navigation-menu-link"
17
+ v-bind="{ ...forwarded, ...$attrs }"
18
+ :class="
19
+ cn(
20
+ 'data-[active]:focus:bg-accent data-[active]:hover:bg-accent data-[active]:bg-accent/50 data-[active]:text-accent-foreground hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground ring-ring/10 dark:ring-ring/20 dark:outline-ring/40 outline-ring/50 [&_svg:not([class*=\'text-\'])]:text-muted-foreground flex flex-col gap-1 rounded-sm p-2 text-sm transition-[color,box-shadow] focus-visible:ring-4 focus-visible:outline-1 [&_svg:not([class*=\'size-\'])]:size-4',
21
+ $attrs.class ?? '',
22
+ )
23
+ "
24
+ >
25
+ <slot />
26
+ </NavigationMenuLink>
27
+ </template>
@@ -0,0 +1,21 @@
1
+ <script setup lang="ts">
2
+ import type { NavigationMenuListProps } from 'reka-ui';
3
+ import { NavigationMenuList, useForwardProps } from 'reka-ui';
4
+ import { cn } from '@/lib/utils';
5
+
6
+ defineOptions({ inheritAttrs: false });
7
+
8
+ const props = defineProps<NavigationMenuListProps>();
9
+
10
+ const forwardedProps = useForwardProps(props);
11
+ </script>
12
+
13
+ <template>
14
+ <NavigationMenuList
15
+ data-slot="navigation-menu-list"
16
+ v-bind="{ ...forwardedProps, ...$attrs }"
17
+ :class="cn('group flex flex-1 list-none items-center justify-center gap-1', $attrs.class ?? '')"
18
+ >
19
+ <slot />
20
+ </NavigationMenuList>
21
+ </template>
@@ -0,0 +1,27 @@
1
+ <script setup lang="ts">
2
+ import type { NavigationMenuTriggerProps } from 'reka-ui';
3
+ import { ChevronDown } from 'lucide-vue-next';
4
+ import { NavigationMenuTrigger, useForwardProps } from 'reka-ui';
5
+ import { cn } from '@/lib/utils';
6
+ import { navigationMenuTriggerStyle } from '.';
7
+
8
+ defineOptions({ inheritAttrs: false });
9
+
10
+ const props = defineProps<NavigationMenuTriggerProps>();
11
+
12
+ const forwardedProps = useForwardProps(props);
13
+ </script>
14
+
15
+ <template>
16
+ <NavigationMenuTrigger
17
+ data-slot="navigation-menu-trigger"
18
+ v-bind="{ ...forwardedProps, ...$attrs }"
19
+ :class="cn(navigationMenuTriggerStyle(), 'group', $attrs.class ?? '')"
20
+ >
21
+ <slot />
22
+ <ChevronDown
23
+ class="relative top-[1px] ml-1 size-3 transition duration-300 group-data-[state=open]:rotate-180"
24
+ aria-hidden="true"
25
+ />
26
+ </NavigationMenuTrigger>
27
+ </template>
@@ -0,0 +1,26 @@
1
+ <script setup lang="ts">
2
+ import type { NavigationMenuViewportProps } from 'reka-ui';
3
+ import { NavigationMenuViewport, useForwardProps } from 'reka-ui';
4
+ import { cn } from '@/lib/utils';
5
+
6
+ defineOptions({ inheritAttrs: false });
7
+
8
+ const props = defineProps<NavigationMenuViewportProps>();
9
+
10
+ const forwardedProps = useForwardProps(props);
11
+ </script>
12
+
13
+ <template>
14
+ <div class="absolute top-full left-0 isolate z-50 flex justify-center">
15
+ <NavigationMenuViewport
16
+ data-slot="navigation-menu-viewport"
17
+ v-bind="{ ...forwardedProps, ...$attrs }"
18
+ :class="
19
+ cn(
20
+ 'origin-top-center bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 relative mt-1.5 h-[var(--reka-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border shadow md:w-[var(--reka-navigation-menu-viewport-width)] left-[var(--reka-navigation-menu-viewport-left)]',
21
+ $attrs.class ?? '',
22
+ )
23
+ "
24
+ />
25
+ </div>
26
+ </template>
@@ -0,0 +1,14 @@
1
+ import { cva } from 'class-variance-authority';
2
+
3
+ export { default as NavigationMenu } from './NavigationMenu.vue';
4
+ export { default as NavigationMenuContent } from './NavigationMenuContent.vue';
5
+ export { default as NavigationMenuIndicator } from './NavigationMenuIndicator.vue';
6
+ export { default as NavigationMenuItem } from './NavigationMenuItem.vue';
7
+ export { default as NavigationMenuLink } from './NavigationMenuLink.vue';
8
+ export { default as NavigationMenuList } from './NavigationMenuList.vue';
9
+ export { default as NavigationMenuTrigger } from './NavigationMenuTrigger.vue';
10
+ export { default as NavigationMenuViewport } from './NavigationMenuViewport.vue';
11
+
12
+ export const navigationMenuTriggerStyle = cva(
13
+ 'group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=open]:hover:bg-accent data-[state=open]:text-accent-foreground data-[state=open]:focus:bg-accent data-[state=open]:bg-accent/50 data-[active]:bg-accent/50 data-[active]:text-accent-foreground data-[active]:hover:bg-accent data-[active]:focus:bg-accent focus-visible:ring-ring/50 outline-none transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1',
14
+ );
@@ -30,7 +30,7 @@
30
30
  v-bind="{ ...$attrs, ...forwarded }"
31
31
  :class="
32
32
  cn(
33
- 'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--reka-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-none',
33
+ 'bg-background-surface-floating text-content-on-surface-primary data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--reka-popover-content-transform-origin) rounded-md border border-border-surface-default p-4 shadow-xs outline-none',
34
34
  props.class,
35
35
  )
36
36
  "
@@ -30,7 +30,7 @@
30
30
  v-bind="{ ...$attrs, ...forwarded }"
31
31
  :class="
32
32
  cn(
33
- 'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--reka-select-content-available-height) min-w-[8rem] overflow-x-hidden overflow-y-auto rounded-md border shadow-md',
33
+ 'bg-background-surface-floating text-content-on-surface-primary data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--reka-select-content-available-height) min-w-[8rem] overflow-x-hidden overflow-y-auto rounded-md border border-border-surface-default shadow-xs',
34
34
  position === 'popper' &&
35
35
  'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
36
36
  props.class,
@@ -24,7 +24,7 @@
24
24
  v-bind="forwardedProps"
25
25
  :class="
26
26
  cn(
27
- 'border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*=\'text-\'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive flex w-fit items-center justify-between gap-2 rounded-md border bg-input-background px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4',
27
+ 'border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*=\'text-\'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive flex w-fit items-center justify-between gap-2 rounded-md border bg-background-input-default px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4',
28
28
  props.class,
29
29
  )
30
30
  "
@@ -0,0 +1,15 @@
1
+ <script setup lang="ts">
2
+ import type { DialogRootEmits, DialogRootProps } from 'reka-ui';
3
+ import { DialogRoot, useForwardPropsEmits } from 'reka-ui';
4
+
5
+ const props = defineProps<DialogRootProps>();
6
+ const emits = defineEmits<DialogRootEmits>();
7
+
8
+ const forwarded = useForwardPropsEmits(props, emits);
9
+ </script>
10
+
11
+ <template>
12
+ <DialogRoot v-slot="slotProps" data-slot="sheet" v-bind="forwarded">
13
+ <slot v-bind="slotProps" />
14
+ </DialogRoot>
15
+ </template>