@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.
- package/README.md +1 -1
- package/config.js +34 -1
- package/dist/system/index.d.ts +1728 -234
- package/dist/system/lib.js +19804 -16600
- package/package.json +1 -1
- package/src/components/UiKbd/UiKbd.stories.ts +1 -1
- package/src/components/UiNavigationMenu/UiNavigationMenu.stories.ts +1196 -0
- package/src/components/UiNavigationMenu/UiNavigationMenu.vue +39 -0
- package/src/components/UiNavigationMenu/UiNavigationMenuContent.vue +25 -0
- package/src/components/UiNavigationMenu/UiNavigationMenuIndicator.vue +14 -0
- package/src/components/UiNavigationMenu/UiNavigationMenuItem.vue +16 -0
- package/src/components/UiNavigationMenu/UiNavigationMenuLink.vue +27 -0
- package/src/components/UiNavigationMenu/UiNavigationMenuList.vue +16 -0
- package/src/components/UiNavigationMenu/UiNavigationMenuTrigger.vue +16 -0
- package/src/components/UiNavigationMenu/__tests__/UiNavigationMenu.test.ts +428 -0
- package/src/components/UiNavigationMenu/index.ts +11 -0
- package/src/components/UiNavigationMenu/types.ts +185 -0
- package/src/components/UiSheet/UiSheet.stories.ts +715 -0
- package/src/components/UiSheet/__tests__/UiSheet.test.ts +229 -0
- package/src/components/UiSheet/index.ts +12 -0
- package/src/components/UiSheet/types.ts +83 -0
- package/src/components/UiSidebar/UiSidebar.stories.ts +1010 -0
- package/src/components/UiSidebar/UiSidebar.vue +20 -0
- package/src/components/UiSidebar/UiSidebarGroupAction.vue +18 -0
- package/src/components/UiSidebar/UiSidebarGroupLabel.vue +18 -0
- package/src/components/UiSidebar/UiSidebarHeaderTrigger.vue +53 -0
- package/src/components/UiSidebar/UiSidebarInput.vue +14 -0
- package/src/components/UiSidebar/UiSidebarMenuAction.vue +19 -0
- package/src/components/UiSidebar/UiSidebarMenuButton.vue +27 -0
- package/src/components/UiSidebar/UiSidebarMenuSkeleton.vue +16 -0
- package/src/components/UiSidebar/UiSidebarMenuSubButton.vue +24 -0
- package/src/components/UiSidebar/UiSidebarProvider.vue +18 -0
- package/src/components/UiSidebar/UiSidebarSeparator.vue +13 -0
- package/src/components/UiSidebar/__tests__/UiSidebar.test.ts +221 -0
- package/src/components/UiSidebar/index.ts +34 -0
- package/src/components/UiSidebar/types.ts +168 -0
- package/src/components/UiStepper/UiStepper.stories.ts +425 -0
- package/src/components/UiStepper/UiStepper.vue +27 -0
- package/src/components/UiStepper/UiStepperDescription.vue +20 -0
- package/src/components/UiStepper/UiStepperIndicator.vue +13 -0
- package/src/components/UiStepper/UiStepperItem.vue +25 -0
- package/src/components/UiStepper/UiStepperSeparator.vue +17 -0
- package/src/components/UiStepper/UiStepperTitle.vue +19 -0
- package/src/components/UiStepper/UiStepperTrigger.vue +18 -0
- package/src/components/UiStepper/__tests__/UiStepper.test.ts +167 -0
- package/src/components/UiStepper/index.ts +9 -0
- package/src/components/UiStepper/types.ts +65 -0
- package/src/components/core/alert/index.ts +2 -2
- package/src/components/core/alert-dialog/AlertDialogContent.vue +1 -1
- package/src/components/core/card/Card.vue +1 -1
- package/src/components/core/drawer/DrawerContent.vue +1 -1
- package/src/components/core/dropdown-menu/DropdownMenuContent.vue +1 -1
- package/src/components/core/dropdown-menu/DropdownMenuSubContent.vue +1 -1
- package/src/components/core/input/Input.vue +1 -1
- package/src/components/core/native-select/NativeSelect.vue +1 -1
- package/src/components/core/native-select/NativeSelectOptGroup.vue +1 -1
- package/src/components/core/native-select/NativeSelectOption.vue +1 -1
- package/src/components/core/navigation-menu/NavigationMenu.vue +40 -0
- package/src/components/core/navigation-menu/NavigationMenuContent.vue +28 -0
- package/src/components/core/navigation-menu/NavigationMenuIndicator.vue +26 -0
- package/src/components/core/navigation-menu/NavigationMenuItem.vue +19 -0
- package/src/components/core/navigation-menu/NavigationMenuLink.vue +27 -0
- package/src/components/core/navigation-menu/NavigationMenuList.vue +21 -0
- package/src/components/core/navigation-menu/NavigationMenuTrigger.vue +27 -0
- package/src/components/core/navigation-menu/NavigationMenuViewport.vue +26 -0
- package/src/components/core/navigation-menu/index.ts +14 -0
- package/src/components/core/popover/PopoverContent.vue +1 -1
- package/src/components/core/select/SelectContent.vue +1 -1
- package/src/components/core/select/SelectTrigger.vue +1 -1
- package/src/components/core/sheet/Sheet.vue +15 -0
- package/src/components/core/sheet/SheetClose.vue +12 -0
- package/src/components/core/sheet/SheetContent.vue +56 -0
- package/src/components/core/sheet/SheetDescription.vue +19 -0
- package/src/components/core/sheet/SheetFooter.vue +9 -0
- package/src/components/core/sheet/SheetHeader.vue +9 -0
- package/src/components/core/sheet/SheetOverlay.vue +24 -0
- package/src/components/core/sheet/SheetTitle.vue +19 -0
- package/src/components/core/sheet/SheetTrigger.vue +12 -0
- package/src/components/core/sheet/index.ts +8 -0
- package/src/components/core/sidebar/Sidebar.vue +105 -0
- package/src/components/core/sidebar/SidebarContent.vue +21 -0
- package/src/components/core/sidebar/SidebarFooter.vue +16 -0
- package/src/components/core/sidebar/SidebarGroup.vue +16 -0
- package/src/components/core/sidebar/SidebarGroupAction.vue +25 -0
- package/src/components/core/sidebar/SidebarGroupContent.vue +16 -0
- package/src/components/core/sidebar/SidebarGroupLabel.vue +23 -0
- package/src/components/core/sidebar/SidebarHeader.vue +16 -0
- package/src/components/core/sidebar/SidebarInput.vue +17 -0
- package/src/components/core/sidebar/SidebarInset.vue +21 -0
- package/src/components/core/sidebar/SidebarMenu.vue +16 -0
- package/src/components/core/sidebar/SidebarMenuAction.vue +33 -0
- package/src/components/core/sidebar/SidebarMenuBadge.vue +26 -0
- package/src/components/core/sidebar/SidebarMenuButton.vue +49 -0
- package/src/components/core/sidebar/SidebarMenuButtonChild.vue +36 -0
- package/src/components/core/sidebar/SidebarMenuItem.vue +16 -0
- package/src/components/core/sidebar/SidebarMenuSkeleton.vue +32 -0
- package/src/components/core/sidebar/SidebarMenuSub.vue +22 -0
- package/src/components/core/sidebar/SidebarMenuSubButton.vue +38 -0
- package/src/components/core/sidebar/SidebarMenuSubItem.vue +16 -0
- package/src/components/core/sidebar/SidebarProvider.vue +102 -0
- package/src/components/core/sidebar/SidebarRail.vue +33 -0
- package/src/components/core/sidebar/SidebarSeparator.vue +17 -0
- package/src/components/core/sidebar/SidebarTrigger.vue +25 -0
- package/src/components/core/sidebar/index.ts +58 -0
- package/src/components/core/sidebar/utils.ts +19 -0
- package/src/components/core/stepper/Stepper.vue +20 -0
- package/src/components/core/stepper/StepperDescription.vue +23 -0
- package/src/components/core/stepper/StepperIndicator.vue +34 -0
- package/src/components/core/stepper/StepperItem.vue +23 -0
- package/src/components/core/stepper/StepperSeparator.vue +29 -0
- package/src/components/core/stepper/StepperTitle.vue +24 -0
- package/src/components/core/stepper/StepperTrigger.vue +22 -0
- package/src/components/core/stepper/index.ts +7 -0
- package/src/components/core/tabs/TabsTrigger.vue +1 -1
- package/src/components/core/tags-input/TagsInput.vue +1 -1
- package/src/components/core/textarea/Textarea.vue +1 -1
- package/src/components/index.ts +4 -0
- package/src/theme/Background.stories.ts +84 -35
- package/src/theme/Extended.stories.ts +4 -4
- 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-
|
|
13
|
+
default: 'bg-background-surface-muted text-content-on-surface-primary',
|
|
14
14
|
destructive:
|
|
15
|
-
'text-destructive bg-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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,
|
|
@@ -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-
|
|
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-
|
|
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-
|
|
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>
|