@auto-engineer/generate-react-client 1.12.1
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/CHANGELOG.md +12 -0
- package/LICENSE +10 -0
- package/dist/src/commands/generate-react-client.d.ts +21 -0
- package/dist/src/commands/generate-react-client.d.ts.map +1 -0
- package/dist/src/commands/generate-react-client.js +62 -0
- package/dist/src/commands/generate-react-client.js.map +1 -0
- package/dist/src/copy-starter.d.ts +2 -0
- package/dist/src/copy-starter.d.ts.map +1 -0
- package/dist/src/copy-starter.js +34 -0
- package/dist/src/copy-starter.js.map +1 -0
- package/dist/src/index.d.ts +10 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +4 -0
- package/dist/src/index.js.map +1 -0
- package/dist/starter/.storybook/main.ts +33 -0
- package/dist/starter/.storybook/preview.tsx +35 -0
- package/dist/starter/components.json +29 -0
- package/dist/starter/index.html +12 -0
- package/dist/starter/package.json +60 -0
- package/dist/starter/pnpm-lock.yaml +5236 -0
- package/dist/starter/public/mockServiceWorker.js +336 -0
- package/dist/starter/src/App.tsx +15 -0
- package/dist/starter/src/components/.gitkeep +0 -0
- package/dist/starter/src/components/ui/Accordion.stories.tsx +47 -0
- package/dist/starter/src/components/ui/Accordion.tsx +51 -0
- package/dist/starter/src/components/ui/Alert.stories.tsx +27 -0
- package/dist/starter/src/components/ui/Alert.tsx +49 -0
- package/dist/starter/src/components/ui/AlertDialog.stories.tsx +65 -0
- package/dist/starter/src/components/ui/AlertDialog.tsx +163 -0
- package/dist/starter/src/components/ui/AspectRatio.stories.tsx +33 -0
- package/dist/starter/src/components/ui/AspectRatio.tsx +9 -0
- package/dist/starter/src/components/ui/Avatar.stories.tsx +42 -0
- package/dist/starter/src/components/ui/Avatar.tsx +87 -0
- package/dist/starter/src/components/ui/Badge.stories.tsx +36 -0
- package/dist/starter/src/components/ui/Badge.tsx +40 -0
- package/dist/starter/src/components/ui/Breadcrumb.stories.tsx +52 -0
- package/dist/starter/src/components/ui/Breadcrumb.tsx +92 -0
- package/dist/starter/src/components/ui/Button.stories.tsx +92 -0
- package/dist/starter/src/components/ui/Button.tsx +62 -0
- package/dist/starter/src/components/ui/ButtonGroup.stories.tsx +30 -0
- package/dist/starter/src/components/ui/ButtonGroup.tsx +75 -0
- package/dist/starter/src/components/ui/Calendar.stories.tsx +38 -0
- package/dist/starter/src/components/ui/Calendar.tsx +159 -0
- package/dist/starter/src/components/ui/Card.stories.tsx +42 -0
- package/dist/starter/src/components/ui/Card.tsx +56 -0
- package/dist/starter/src/components/ui/Carousel.stories.tsx +54 -0
- package/dist/starter/src/components/ui/Carousel.tsx +216 -0
- package/dist/starter/src/components/ui/Chart.stories.tsx +38 -0
- package/dist/starter/src/components/ui/Chart.tsx +296 -0
- package/dist/starter/src/components/ui/Checkbox.stories.tsx +31 -0
- package/dist/starter/src/components/ui/Checkbox.tsx +29 -0
- package/dist/starter/src/components/ui/Collapsible.stories.tsx +56 -0
- package/dist/starter/src/components/ui/Collapsible.tsx +15 -0
- package/dist/starter/src/components/ui/Combobox.stories.tsx +73 -0
- package/dist/starter/src/components/ui/Combobox.tsx +267 -0
- package/dist/starter/src/components/ui/Command.stories.tsx +69 -0
- package/dist/starter/src/components/ui/Command.tsx +137 -0
- package/dist/starter/src/components/ui/ContextMenu.stories.tsx +66 -0
- package/dist/starter/src/components/ui/ContextMenu.tsx +211 -0
- package/dist/starter/src/components/ui/DesignSystem-Colors.mdx +68 -0
- package/dist/starter/src/components/ui/DesignSystem-Colors.stories.tsx +116 -0
- package/dist/starter/src/components/ui/DesignSystem-Layout.mdx +64 -0
- package/dist/starter/src/components/ui/DesignSystem-Layout.stories.tsx +166 -0
- package/dist/starter/src/components/ui/DesignSystem-Typography.mdx +31 -0
- package/dist/starter/src/components/ui/DesignSystem-Typography.stories.tsx +79 -0
- package/dist/starter/src/components/ui/Dialog.stories.tsx +72 -0
- package/dist/starter/src/components/ui/Dialog.tsx +136 -0
- package/dist/starter/src/components/ui/Direction.stories.tsx +36 -0
- package/dist/starter/src/components/ui/Direction.tsx +18 -0
- package/dist/starter/src/components/ui/Drawer.stories.tsx +68 -0
- package/dist/starter/src/components/ui/Drawer.tsx +106 -0
- package/dist/starter/src/components/ui/DropdownMenu.stories.tsx +72 -0
- package/dist/starter/src/components/ui/DropdownMenu.tsx +219 -0
- package/dist/starter/src/components/ui/Empty.stories.tsx +35 -0
- package/dist/starter/src/components/ui/Empty.tsx +85 -0
- package/dist/starter/src/components/ui/Field.stories.tsx +47 -0
- package/dist/starter/src/components/ui/Field.tsx +226 -0
- package/dist/starter/src/components/ui/Form.stories.tsx +44 -0
- package/dist/starter/src/components/ui/Form.tsx +136 -0
- package/dist/starter/src/components/ui/HoverCard.stories.tsx +47 -0
- package/dist/starter/src/components/ui/HoverCard.tsx +36 -0
- package/dist/starter/src/components/ui/Input.stories.tsx +38 -0
- package/dist/starter/src/components/ui/Input.tsx +21 -0
- package/dist/starter/src/components/ui/InputGroup.stories.tsx +50 -0
- package/dist/starter/src/components/ui/InputGroup.tsx +147 -0
- package/dist/starter/src/components/ui/InputOTP.stories.tsx +40 -0
- package/dist/starter/src/components/ui/InputOTP.tsx +68 -0
- package/dist/starter/src/components/ui/Item.stories.tsx +61 -0
- package/dist/starter/src/components/ui/Item.tsx +158 -0
- package/dist/starter/src/components/ui/Kbd.stories.tsx +54 -0
- package/dist/starter/src/components/ui/Kbd.tsx +18 -0
- package/dist/starter/src/components/ui/Label.stories.tsx +85 -0
- package/dist/starter/src/components/ui/Label.tsx +40 -0
- package/dist/starter/src/components/ui/Menubar.stories.tsx +76 -0
- package/dist/starter/src/components/ui/Menubar.tsx +236 -0
- package/dist/starter/src/components/ui/NativeSelect.stories.tsx +42 -0
- package/dist/starter/src/components/ui/NativeSelect.tsx +44 -0
- package/dist/starter/src/components/ui/NavigationMenu.stories.tsx +78 -0
- package/dist/starter/src/components/ui/NavigationMenu.tsx +142 -0
- package/dist/starter/src/components/ui/Pagination.stories.tsx +75 -0
- package/dist/starter/src/components/ui/Pagination.tsx +100 -0
- package/dist/starter/src/components/ui/Popover.stories.tsx +51 -0
- package/dist/starter/src/components/ui/Popover.tsx +52 -0
- package/dist/starter/src/components/ui/Progress.stories.tsx +28 -0
- package/dist/starter/src/components/ui/Progress.tsx +24 -0
- package/dist/starter/src/components/ui/RadioGroup.stories.tsx +48 -0
- package/dist/starter/src/components/ui/RadioGroup.tsx +31 -0
- package/dist/starter/src/components/ui/Resizable.stories.tsx +69 -0
- package/dist/starter/src/components/ui/Resizable.tsx +47 -0
- package/dist/starter/src/components/ui/ScrollArea.stories.tsx +43 -0
- package/dist/starter/src/components/ui/ScrollArea.tsx +46 -0
- package/dist/starter/src/components/ui/Select.stories.tsx +57 -0
- package/dist/starter/src/components/ui/Select.tsx +162 -0
- package/dist/starter/src/components/ui/Separator.stories.tsx +40 -0
- package/dist/starter/src/components/ui/Separator.tsx +26 -0
- package/dist/starter/src/components/ui/Sheet.stories.tsx +66 -0
- package/dist/starter/src/components/ui/Sheet.tsx +107 -0
- package/dist/starter/src/components/ui/Sidebar.stories.tsx +94 -0
- package/dist/starter/src/components/ui/Sidebar.tsx +675 -0
- package/dist/starter/src/components/ui/Skeleton.stories.tsx +38 -0
- package/dist/starter/src/components/ui/Skeleton.tsx +7 -0
- package/dist/starter/src/components/ui/Slider.stories.tsx +21 -0
- package/dist/starter/src/components/ui/Slider.tsx +54 -0
- package/dist/starter/src/components/ui/Sonner.stories.tsx +44 -0
- package/dist/starter/src/components/ui/Sonner.tsx +34 -0
- package/dist/starter/src/components/ui/Spinner.stories.tsx +23 -0
- package/dist/starter/src/components/ui/Spinner.tsx +9 -0
- package/dist/starter/src/components/ui/Switch.stories.tsx +35 -0
- package/dist/starter/src/components/ui/Switch.tsx +33 -0
- package/dist/starter/src/components/ui/Table.stories.tsx +65 -0
- package/dist/starter/src/components/ui/Table.tsx +75 -0
- package/dist/starter/src/components/ui/Tabs.stories.tsx +51 -0
- package/dist/starter/src/components/ui/Tabs.tsx +69 -0
- package/dist/starter/src/components/ui/Textarea.stories.tsx +24 -0
- package/dist/starter/src/components/ui/Textarea.tsx +18 -0
- package/dist/starter/src/components/ui/Toast.stories.tsx +112 -0
- package/dist/starter/src/components/ui/Toast.tsx +114 -0
- package/dist/starter/src/components/ui/Toaster.tsx +28 -0
- package/dist/starter/src/components/ui/Toggle.stories.tsx +40 -0
- package/dist/starter/src/components/ui/Toggle.tsx +41 -0
- package/dist/starter/src/components/ui/ToggleGroup.stories.tsx +58 -0
- package/dist/starter/src/components/ui/ToggleGroup.tsx +80 -0
- package/dist/starter/src/components/ui/Tooltip.stories.tsx +40 -0
- package/dist/starter/src/components/ui/Tooltip.tsx +42 -0
- package/dist/starter/src/hooks/use-mobile.ts +19 -0
- package/dist/starter/src/hooks/use-toast.ts +186 -0
- package/dist/starter/src/index.css +123 -0
- package/dist/starter/src/lib/utils.ts +6 -0
- package/dist/starter/src/main.tsx +5 -0
- package/dist/starter/tsconfig.app.json +25 -0
- package/dist/starter/tsconfig.json +4 -0
- package/dist/starter/vite.config.ts +16 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +37 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
3
|
+
import { Slot } from 'radix-ui';
|
|
4
|
+
|
|
5
|
+
import { cn } from '@/lib/utils';
|
|
6
|
+
import { Separator } from '@/components/ui/Separator';
|
|
7
|
+
|
|
8
|
+
function ItemGroup({ className, ...props }: React.ComponentProps<'div'>) {
|
|
9
|
+
return (
|
|
10
|
+
<div role="list" data-slot="item-group" className={cn('group/item-group flex flex-col', className)} {...props} />
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function ItemSeparator({ className, ...props }: React.ComponentProps<typeof Separator>) {
|
|
15
|
+
return <Separator data-slot="item-separator" orientation="horizontal" className={cn('my-0', className)} {...props} />;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const itemVariants = cva(
|
|
19
|
+
'group/item flex items-center border border-transparent text-sm rounded-md transition-colors [a]:hover:bg-accent/50 [a]:transition-colors duration-100 flex-wrap outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',
|
|
20
|
+
{
|
|
21
|
+
variants: {
|
|
22
|
+
variant: {
|
|
23
|
+
default: 'bg-transparent',
|
|
24
|
+
outline: 'border-border',
|
|
25
|
+
muted: 'bg-muted/50',
|
|
26
|
+
},
|
|
27
|
+
size: {
|
|
28
|
+
default: 'p-4 gap-4 ',
|
|
29
|
+
sm: 'py-3 px-4 gap-2.5',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
defaultVariants: {
|
|
33
|
+
variant: 'default',
|
|
34
|
+
size: 'default',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
function Item({
|
|
40
|
+
className,
|
|
41
|
+
variant = 'default',
|
|
42
|
+
size = 'default',
|
|
43
|
+
asChild = false,
|
|
44
|
+
...props
|
|
45
|
+
}: React.ComponentProps<'div'> & VariantProps<typeof itemVariants> & { asChild?: boolean }) {
|
|
46
|
+
const Comp = asChild ? Slot.Root : 'div';
|
|
47
|
+
return (
|
|
48
|
+
<Comp
|
|
49
|
+
data-slot="item"
|
|
50
|
+
data-variant={variant}
|
|
51
|
+
data-size={size}
|
|
52
|
+
className={cn(itemVariants({ variant, size, className }))}
|
|
53
|
+
{...props}
|
|
54
|
+
/>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const itemMediaVariants = cva(
|
|
59
|
+
'flex shrink-0 items-center justify-center gap-2 group-has-[[data-slot=item-description]]/item:self-start [&_svg]:pointer-events-none group-has-[[data-slot=item-description]]/item:translate-y-0.5',
|
|
60
|
+
{
|
|
61
|
+
variants: {
|
|
62
|
+
variant: {
|
|
63
|
+
default: 'bg-transparent',
|
|
64
|
+
icon: "size-8 border rounded-sm bg-muted [&_svg:not([class*='size-'])]:size-4",
|
|
65
|
+
image: 'size-10 rounded-sm overflow-hidden [&_img]:size-full [&_img]:object-cover',
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
defaultVariants: {
|
|
69
|
+
variant: 'default',
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
function ItemMedia({
|
|
75
|
+
className,
|
|
76
|
+
variant = 'default',
|
|
77
|
+
...props
|
|
78
|
+
}: React.ComponentProps<'div'> & VariantProps<typeof itemMediaVariants>) {
|
|
79
|
+
return (
|
|
80
|
+
<div
|
|
81
|
+
data-slot="item-media"
|
|
82
|
+
data-variant={variant}
|
|
83
|
+
className={cn(itemMediaVariants({ variant, className }))}
|
|
84
|
+
{...props}
|
|
85
|
+
/>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function ItemContent({ className, ...props }: React.ComponentProps<'div'>) {
|
|
90
|
+
return (
|
|
91
|
+
<div
|
|
92
|
+
data-slot="item-content"
|
|
93
|
+
className={cn('flex flex-1 flex-col gap-1 [&+[data-slot=item-content]]:flex-none', className)}
|
|
94
|
+
{...props}
|
|
95
|
+
/>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function ItemTitle({ className, ...props }: React.ComponentProps<'div'>) {
|
|
100
|
+
return (
|
|
101
|
+
<div
|
|
102
|
+
data-slot="item-title"
|
|
103
|
+
className={cn('flex w-fit items-center gap-2 text-sm leading-snug font-medium', className)}
|
|
104
|
+
{...props}
|
|
105
|
+
/>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function ItemDescription({ className, ...props }: React.ComponentProps<'p'>) {
|
|
110
|
+
return (
|
|
111
|
+
<p
|
|
112
|
+
data-slot="item-description"
|
|
113
|
+
className={cn(
|
|
114
|
+
'text-muted-foreground line-clamp-2 text-sm leading-normal font-normal text-balance',
|
|
115
|
+
'[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4',
|
|
116
|
+
className,
|
|
117
|
+
)}
|
|
118
|
+
{...props}
|
|
119
|
+
/>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function ItemActions({ className, ...props }: React.ComponentProps<'div'>) {
|
|
124
|
+
return <div data-slot="item-actions" className={cn('flex items-center gap-2', className)} {...props} />;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function ItemHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
|
128
|
+
return (
|
|
129
|
+
<div
|
|
130
|
+
data-slot="item-header"
|
|
131
|
+
className={cn('flex basis-full items-center justify-between gap-2', className)}
|
|
132
|
+
{...props}
|
|
133
|
+
/>
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function ItemFooter({ className, ...props }: React.ComponentProps<'div'>) {
|
|
138
|
+
return (
|
|
139
|
+
<div
|
|
140
|
+
data-slot="item-footer"
|
|
141
|
+
className={cn('flex basis-full items-center justify-between gap-2', className)}
|
|
142
|
+
{...props}
|
|
143
|
+
/>
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export {
|
|
148
|
+
Item,
|
|
149
|
+
ItemMedia,
|
|
150
|
+
ItemContent,
|
|
151
|
+
ItemActions,
|
|
152
|
+
ItemGroup,
|
|
153
|
+
ItemSeparator,
|
|
154
|
+
ItemTitle,
|
|
155
|
+
ItemDescription,
|
|
156
|
+
ItemHeader,
|
|
157
|
+
ItemFooter,
|
|
158
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
import { Kbd } from './Kbd';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof Kbd> = {
|
|
5
|
+
title: 'Kbd',
|
|
6
|
+
component: Kbd,
|
|
7
|
+
parameters: {
|
|
8
|
+
layout: 'centered',
|
|
9
|
+
},
|
|
10
|
+
tags: ['autodocs'],
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default meta;
|
|
14
|
+
type Story = StoryObj<typeof meta>;
|
|
15
|
+
|
|
16
|
+
export const Default: Story = {
|
|
17
|
+
args: {
|
|
18
|
+
children: '⌘K',
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const WithText: Story = {
|
|
23
|
+
args: {
|
|
24
|
+
children: 'Ctrl',
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const ArrowKeys: Story = {
|
|
29
|
+
args: {
|
|
30
|
+
children: '→',
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const Multiple: Story = {
|
|
35
|
+
render: () => (
|
|
36
|
+
<div className="flex gap-2 items-center">
|
|
37
|
+
<Kbd>⌘</Kbd>
|
|
38
|
+
<span>+</span>
|
|
39
|
+
<Kbd>K</Kbd>
|
|
40
|
+
</div>
|
|
41
|
+
),
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const Combination: Story = {
|
|
45
|
+
render: () => (
|
|
46
|
+
<div className="flex gap-2 items-center">
|
|
47
|
+
<Kbd>Ctrl</Kbd>
|
|
48
|
+
<span>+</span>
|
|
49
|
+
<Kbd>Shift</Kbd>
|
|
50
|
+
<span>+</span>
|
|
51
|
+
<Kbd>P</Kbd>
|
|
52
|
+
</div>
|
|
53
|
+
),
|
|
54
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { cn } from '@/lib/utils';
|
|
3
|
+
|
|
4
|
+
interface KbdProps {
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function Kbd({ children, className }: KbdProps) {
|
|
10
|
+
return (
|
|
11
|
+
<kbd
|
|
12
|
+
data-slot="kbd"
|
|
13
|
+
className={cn('border border-border rounded bg-muted px-1.5 py-0.5 text-xs font-medium', className)}
|
|
14
|
+
>
|
|
15
|
+
{children}
|
|
16
|
+
</kbd>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
import { Label } from './Label';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof Label> = {
|
|
5
|
+
title: 'Label',
|
|
6
|
+
component: Label,
|
|
7
|
+
parameters: {
|
|
8
|
+
layout: 'centered',
|
|
9
|
+
},
|
|
10
|
+
tags: ['autodocs'],
|
|
11
|
+
argTypes: {
|
|
12
|
+
variant: {
|
|
13
|
+
control: { type: 'radio' },
|
|
14
|
+
options: ['default', 'required'],
|
|
15
|
+
},
|
|
16
|
+
required: {
|
|
17
|
+
control: { type: 'boolean' },
|
|
18
|
+
},
|
|
19
|
+
htmlFor: {
|
|
20
|
+
control: { type: 'text' },
|
|
21
|
+
},
|
|
22
|
+
children: {
|
|
23
|
+
control: { type: 'text' },
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export default meta;
|
|
29
|
+
type Story = StoryObj<typeof meta>;
|
|
30
|
+
|
|
31
|
+
export const Default: Story = {
|
|
32
|
+
args: {
|
|
33
|
+
children: 'Email address',
|
|
34
|
+
htmlFor: 'email',
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const Required: Story = {
|
|
39
|
+
args: {
|
|
40
|
+
children: 'Email address',
|
|
41
|
+
htmlFor: 'email',
|
|
42
|
+
required: true,
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const RequiredVariant: Story = {
|
|
47
|
+
args: {
|
|
48
|
+
children: 'Email address',
|
|
49
|
+
htmlFor: 'email',
|
|
50
|
+
variant: 'required',
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const WithForm: Story = {
|
|
55
|
+
render: (args) => (
|
|
56
|
+
<div className="space-y-2">
|
|
57
|
+
<Label htmlFor="example-input" required>
|
|
58
|
+
Example Field
|
|
59
|
+
</Label>
|
|
60
|
+
<input
|
|
61
|
+
id="example-input"
|
|
62
|
+
type="text"
|
|
63
|
+
className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
|
64
|
+
placeholder="Enter value..."
|
|
65
|
+
/>
|
|
66
|
+
</div>
|
|
67
|
+
),
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export const DisabledField: Story = {
|
|
71
|
+
render: (args) => (
|
|
72
|
+
<div className="space-y-2">
|
|
73
|
+
<Label htmlFor="disabled-input" required>
|
|
74
|
+
Disabled Field
|
|
75
|
+
</Label>
|
|
76
|
+
<input
|
|
77
|
+
id="disabled-input"
|
|
78
|
+
type="text"
|
|
79
|
+
disabled
|
|
80
|
+
className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
|
81
|
+
placeholder="Disabled input..."
|
|
82
|
+
/>
|
|
83
|
+
</div>
|
|
84
|
+
),
|
|
85
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
3
|
+
import { cn } from '@/lib/utils';
|
|
4
|
+
|
|
5
|
+
const labelVariants = cva(
|
|
6
|
+
'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',
|
|
7
|
+
{
|
|
8
|
+
variants: {
|
|
9
|
+
variant: {
|
|
10
|
+
default: 'text-foreground',
|
|
11
|
+
required: "text-foreground after:content-['*'] after:ml-1 after:text-destructive",
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
defaultVariants: {
|
|
15
|
+
variant: 'default',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
export interface LabelProps extends React.LabelHTMLAttributes<HTMLLabelElement>, VariantProps<typeof labelVariants> {
|
|
21
|
+
htmlFor?: string;
|
|
22
|
+
required?: boolean;
|
|
23
|
+
children?: React.ReactNode;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const Label = React.forwardRef<HTMLLabelElement, LabelProps>(({ className, variant, required, ...props }, ref) => {
|
|
27
|
+
const effectiveVariant = required ? 'required' : variant || 'default';
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<label
|
|
31
|
+
ref={ref}
|
|
32
|
+
data-slot="label"
|
|
33
|
+
className={cn(labelVariants({ variant: effectiveVariant }), className)}
|
|
34
|
+
{...props}
|
|
35
|
+
/>
|
|
36
|
+
);
|
|
37
|
+
});
|
|
38
|
+
Label.displayName = 'Label';
|
|
39
|
+
|
|
40
|
+
export { Label, labelVariants };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
import {
|
|
3
|
+
Menubar,
|
|
4
|
+
MenubarMenu,
|
|
5
|
+
MenubarTrigger,
|
|
6
|
+
MenubarContent,
|
|
7
|
+
MenubarItem,
|
|
8
|
+
MenubarSeparator,
|
|
9
|
+
MenubarLabel,
|
|
10
|
+
MenubarShortcut,
|
|
11
|
+
} from '@/components/ui/Menubar';
|
|
12
|
+
|
|
13
|
+
const meta: Meta<typeof Menubar> = {
|
|
14
|
+
title: 'Menubar',
|
|
15
|
+
component: Menubar,
|
|
16
|
+
};
|
|
17
|
+
export default meta;
|
|
18
|
+
type Story = StoryObj<typeof Menubar>;
|
|
19
|
+
|
|
20
|
+
export const Default: Story = {
|
|
21
|
+
render: () => (
|
|
22
|
+
<Menubar>
|
|
23
|
+
<MenubarMenu>
|
|
24
|
+
<MenubarTrigger>File</MenubarTrigger>
|
|
25
|
+
<MenubarContent>
|
|
26
|
+
<MenubarItem>
|
|
27
|
+
New Tab <MenubarShortcut>Ctrl+T</MenubarShortcut>
|
|
28
|
+
</MenubarItem>
|
|
29
|
+
<MenubarItem>
|
|
30
|
+
New Window <MenubarShortcut>Ctrl+N</MenubarShortcut>
|
|
31
|
+
</MenubarItem>
|
|
32
|
+
<MenubarSeparator />
|
|
33
|
+
<MenubarItem>
|
|
34
|
+
Save <MenubarShortcut>Ctrl+S</MenubarShortcut>
|
|
35
|
+
</MenubarItem>
|
|
36
|
+
<MenubarSeparator />
|
|
37
|
+
<MenubarItem>Exit</MenubarItem>
|
|
38
|
+
</MenubarContent>
|
|
39
|
+
</MenubarMenu>
|
|
40
|
+
<MenubarMenu>
|
|
41
|
+
<MenubarTrigger>Edit</MenubarTrigger>
|
|
42
|
+
<MenubarContent>
|
|
43
|
+
<MenubarItem>
|
|
44
|
+
Undo <MenubarShortcut>Ctrl+Z</MenubarShortcut>
|
|
45
|
+
</MenubarItem>
|
|
46
|
+
<MenubarItem>
|
|
47
|
+
Redo <MenubarShortcut>Ctrl+Y</MenubarShortcut>
|
|
48
|
+
</MenubarItem>
|
|
49
|
+
<MenubarSeparator />
|
|
50
|
+
<MenubarItem>Cut</MenubarItem>
|
|
51
|
+
<MenubarItem>Copy</MenubarItem>
|
|
52
|
+
<MenubarItem>Paste</MenubarItem>
|
|
53
|
+
</MenubarContent>
|
|
54
|
+
</MenubarMenu>
|
|
55
|
+
</Menubar>
|
|
56
|
+
),
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const WithLabels: Story = {
|
|
60
|
+
render: () => (
|
|
61
|
+
<Menubar>
|
|
62
|
+
<MenubarMenu>
|
|
63
|
+
<MenubarTrigger>View</MenubarTrigger>
|
|
64
|
+
<MenubarContent>
|
|
65
|
+
<MenubarLabel>Appearance</MenubarLabel>
|
|
66
|
+
<MenubarItem>Zoom In</MenubarItem>
|
|
67
|
+
<MenubarItem>Zoom Out</MenubarItem>
|
|
68
|
+
<MenubarSeparator />
|
|
69
|
+
<MenubarLabel>Layout</MenubarLabel>
|
|
70
|
+
<MenubarItem>Full Screen</MenubarItem>
|
|
71
|
+
<MenubarItem>Side by Side</MenubarItem>
|
|
72
|
+
</MenubarContent>
|
|
73
|
+
</MenubarMenu>
|
|
74
|
+
</Menubar>
|
|
75
|
+
),
|
|
76
|
+
};
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { CheckIcon, ChevronRightIcon, CircleIcon } from 'lucide-react';
|
|
5
|
+
import { Menubar as MenubarPrimitive } from 'radix-ui';
|
|
6
|
+
|
|
7
|
+
import { cn } from '@/lib/utils';
|
|
8
|
+
|
|
9
|
+
function Menubar({ className, ...props }: React.ComponentProps<typeof MenubarPrimitive.Root>) {
|
|
10
|
+
return (
|
|
11
|
+
<MenubarPrimitive.Root
|
|
12
|
+
data-slot="menubar"
|
|
13
|
+
className={cn('bg-background flex h-9 items-center gap-1 rounded-md border p-1 shadow-xs', className)}
|
|
14
|
+
{...props}
|
|
15
|
+
/>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function MenubarMenu({ ...props }: React.ComponentProps<typeof MenubarPrimitive.Menu>) {
|
|
20
|
+
return <MenubarPrimitive.Menu data-slot="menubar-menu" {...props} />;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function MenubarGroup({ ...props }: React.ComponentProps<typeof MenubarPrimitive.Group>) {
|
|
24
|
+
return <MenubarPrimitive.Group data-slot="menubar-group" {...props} />;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function MenubarPortal({ ...props }: React.ComponentProps<typeof MenubarPrimitive.Portal>) {
|
|
28
|
+
return <MenubarPrimitive.Portal data-slot="menubar-portal" {...props} />;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function MenubarRadioGroup({ ...props }: React.ComponentProps<typeof MenubarPrimitive.RadioGroup>) {
|
|
32
|
+
return <MenubarPrimitive.RadioGroup data-slot="menubar-radio-group" {...props} />;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function MenubarTrigger({ className, ...props }: React.ComponentProps<typeof MenubarPrimitive.Trigger>) {
|
|
36
|
+
return (
|
|
37
|
+
<MenubarPrimitive.Trigger
|
|
38
|
+
data-slot="menubar-trigger"
|
|
39
|
+
className={cn(
|
|
40
|
+
'focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex items-center rounded-sm px-2 py-1 text-sm font-medium outline-hidden select-none',
|
|
41
|
+
className,
|
|
42
|
+
)}
|
|
43
|
+
{...props}
|
|
44
|
+
/>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function MenubarContent({
|
|
49
|
+
className,
|
|
50
|
+
align = 'start',
|
|
51
|
+
alignOffset = -4,
|
|
52
|
+
sideOffset = 8,
|
|
53
|
+
...props
|
|
54
|
+
}: React.ComponentProps<typeof MenubarPrimitive.Content>) {
|
|
55
|
+
return (
|
|
56
|
+
<MenubarPortal>
|
|
57
|
+
<MenubarPrimitive.Content
|
|
58
|
+
data-slot="menubar-content"
|
|
59
|
+
align={align}
|
|
60
|
+
alignOffset={alignOffset}
|
|
61
|
+
sideOffset={sideOffset}
|
|
62
|
+
className={cn(
|
|
63
|
+
'bg-popover text-popover-foreground data-[state=open]:animate-in 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-[12rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-md',
|
|
64
|
+
className,
|
|
65
|
+
)}
|
|
66
|
+
{...props}
|
|
67
|
+
/>
|
|
68
|
+
</MenubarPortal>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function MenubarItem({
|
|
73
|
+
className,
|
|
74
|
+
inset,
|
|
75
|
+
variant = 'default',
|
|
76
|
+
...props
|
|
77
|
+
}: React.ComponentProps<typeof MenubarPrimitive.Item> & {
|
|
78
|
+
inset?: boolean;
|
|
79
|
+
variant?: 'default' | 'destructive';
|
|
80
|
+
}) {
|
|
81
|
+
return (
|
|
82
|
+
<MenubarPrimitive.Item
|
|
83
|
+
data-slot="menubar-item"
|
|
84
|
+
data-inset={inset}
|
|
85
|
+
data-variant={variant}
|
|
86
|
+
className={cn(
|
|
87
|
+
"focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
88
|
+
className,
|
|
89
|
+
)}
|
|
90
|
+
{...props}
|
|
91
|
+
/>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function MenubarCheckboxItem({
|
|
96
|
+
className,
|
|
97
|
+
children,
|
|
98
|
+
checked,
|
|
99
|
+
...props
|
|
100
|
+
}: React.ComponentProps<typeof MenubarPrimitive.CheckboxItem>) {
|
|
101
|
+
return (
|
|
102
|
+
<MenubarPrimitive.CheckboxItem
|
|
103
|
+
data-slot="menubar-checkbox-item"
|
|
104
|
+
className={cn(
|
|
105
|
+
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-xs py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
106
|
+
className,
|
|
107
|
+
)}
|
|
108
|
+
checked={checked}
|
|
109
|
+
{...props}
|
|
110
|
+
>
|
|
111
|
+
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
|
|
112
|
+
<MenubarPrimitive.ItemIndicator>
|
|
113
|
+
<CheckIcon className="size-4" />
|
|
114
|
+
</MenubarPrimitive.ItemIndicator>
|
|
115
|
+
</span>
|
|
116
|
+
{children}
|
|
117
|
+
</MenubarPrimitive.CheckboxItem>
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function MenubarRadioItem({ className, children, ...props }: React.ComponentProps<typeof MenubarPrimitive.RadioItem>) {
|
|
122
|
+
return (
|
|
123
|
+
<MenubarPrimitive.RadioItem
|
|
124
|
+
data-slot="menubar-radio-item"
|
|
125
|
+
className={cn(
|
|
126
|
+
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-xs py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
127
|
+
className,
|
|
128
|
+
)}
|
|
129
|
+
{...props}
|
|
130
|
+
>
|
|
131
|
+
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
|
|
132
|
+
<MenubarPrimitive.ItemIndicator>
|
|
133
|
+
<CircleIcon className="size-2 fill-current" />
|
|
134
|
+
</MenubarPrimitive.ItemIndicator>
|
|
135
|
+
</span>
|
|
136
|
+
{children}
|
|
137
|
+
</MenubarPrimitive.RadioItem>
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function MenubarLabel({
|
|
142
|
+
className,
|
|
143
|
+
inset,
|
|
144
|
+
...props
|
|
145
|
+
}: React.ComponentProps<typeof MenubarPrimitive.Label> & {
|
|
146
|
+
inset?: boolean;
|
|
147
|
+
}) {
|
|
148
|
+
return (
|
|
149
|
+
<MenubarPrimitive.Label
|
|
150
|
+
data-slot="menubar-label"
|
|
151
|
+
data-inset={inset}
|
|
152
|
+
className={cn('px-2 py-1.5 text-sm font-medium data-[inset]:pl-8', className)}
|
|
153
|
+
{...props}
|
|
154
|
+
/>
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function MenubarSeparator({ className, ...props }: React.ComponentProps<typeof MenubarPrimitive.Separator>) {
|
|
159
|
+
return (
|
|
160
|
+
<MenubarPrimitive.Separator
|
|
161
|
+
data-slot="menubar-separator"
|
|
162
|
+
className={cn('bg-border -mx-1 my-1 h-px', className)}
|
|
163
|
+
{...props}
|
|
164
|
+
/>
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function MenubarShortcut({ className, ...props }: React.ComponentProps<'span'>) {
|
|
169
|
+
return (
|
|
170
|
+
<span
|
|
171
|
+
data-slot="menubar-shortcut"
|
|
172
|
+
className={cn('text-muted-foreground ml-auto text-xs tracking-widest', className)}
|
|
173
|
+
{...props}
|
|
174
|
+
/>
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function MenubarSub({ ...props }: React.ComponentProps<typeof MenubarPrimitive.Sub>) {
|
|
179
|
+
return <MenubarPrimitive.Sub data-slot="menubar-sub" {...props} />;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function MenubarSubTrigger({
|
|
183
|
+
className,
|
|
184
|
+
inset,
|
|
185
|
+
children,
|
|
186
|
+
...props
|
|
187
|
+
}: React.ComponentProps<typeof MenubarPrimitive.SubTrigger> & {
|
|
188
|
+
inset?: boolean;
|
|
189
|
+
}) {
|
|
190
|
+
return (
|
|
191
|
+
<MenubarPrimitive.SubTrigger
|
|
192
|
+
data-slot="menubar-sub-trigger"
|
|
193
|
+
data-inset={inset}
|
|
194
|
+
className={cn(
|
|
195
|
+
'focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[inset]:pl-8',
|
|
196
|
+
className,
|
|
197
|
+
)}
|
|
198
|
+
{...props}
|
|
199
|
+
>
|
|
200
|
+
{children}
|
|
201
|
+
<ChevronRightIcon className="ml-auto h-4 w-4" />
|
|
202
|
+
</MenubarPrimitive.SubTrigger>
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function MenubarSubContent({ className, ...props }: React.ComponentProps<typeof MenubarPrimitive.SubContent>) {
|
|
207
|
+
return (
|
|
208
|
+
<MenubarPrimitive.SubContent
|
|
209
|
+
data-slot="menubar-sub-content"
|
|
210
|
+
className={cn(
|
|
211
|
+
'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-(--radix-menubar-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg',
|
|
212
|
+
className,
|
|
213
|
+
)}
|
|
214
|
+
{...props}
|
|
215
|
+
/>
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export {
|
|
220
|
+
Menubar,
|
|
221
|
+
MenubarPortal,
|
|
222
|
+
MenubarMenu,
|
|
223
|
+
MenubarTrigger,
|
|
224
|
+
MenubarContent,
|
|
225
|
+
MenubarGroup,
|
|
226
|
+
MenubarSeparator,
|
|
227
|
+
MenubarLabel,
|
|
228
|
+
MenubarItem,
|
|
229
|
+
MenubarShortcut,
|
|
230
|
+
MenubarCheckboxItem,
|
|
231
|
+
MenubarRadioGroup,
|
|
232
|
+
MenubarRadioItem,
|
|
233
|
+
MenubarSub,
|
|
234
|
+
MenubarSubTrigger,
|
|
235
|
+
MenubarSubContent,
|
|
236
|
+
};
|