@trycompai/design-system 1.0.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 +110 -0
- package/components.json +21 -0
- package/hooks/use-mobile.tsx +19 -0
- package/lib/utils.ts +6 -0
- package/package.json +103 -0
- package/postcss.config.mjs +8 -0
- package/src/components/ui/accordion.tsx +60 -0
- package/src/components/ui/alert-dialog.tsx +161 -0
- package/src/components/ui/alert.tsx +109 -0
- package/src/components/ui/aspect-ratio.tsx +21 -0
- package/src/components/ui/avatar.tsx +74 -0
- package/src/components/ui/badge.tsx +48 -0
- package/src/components/ui/breadcrumb.tsx +254 -0
- package/src/components/ui/button-group.tsx +89 -0
- package/src/components/ui/button.tsx +122 -0
- package/src/components/ui/calendar.tsx +190 -0
- package/src/components/ui/card.tsx +155 -0
- package/src/components/ui/carousel.tsx +216 -0
- package/src/components/ui/chart.tsx +325 -0
- package/src/components/ui/checkbox.tsx +22 -0
- package/src/components/ui/collapsible.tsx +17 -0
- package/src/components/ui/combobox.tsx +248 -0
- package/src/components/ui/command.tsx +189 -0
- package/src/components/ui/container.tsx +34 -0
- package/src/components/ui/context-menu.tsx +235 -0
- package/src/components/ui/dialog.tsx +122 -0
- package/src/components/ui/drawer.tsx +102 -0
- package/src/components/ui/dropdown-menu.tsx +242 -0
- package/src/components/ui/empty.tsx +94 -0
- package/src/components/ui/field.tsx +215 -0
- package/src/components/ui/grid.tsx +135 -0
- package/src/components/ui/heading.tsx +56 -0
- package/src/components/ui/hover-card.tsx +46 -0
- package/src/components/ui/index.ts +61 -0
- package/src/components/ui/input-group.tsx +128 -0
- package/src/components/ui/input-otp.tsx +84 -0
- package/src/components/ui/input.tsx +15 -0
- package/src/components/ui/item.tsx +188 -0
- package/src/components/ui/kbd.tsx +26 -0
- package/src/components/ui/label.tsx +15 -0
- package/src/components/ui/menubar.tsx +163 -0
- package/src/components/ui/navigation-menu.tsx +147 -0
- package/src/components/ui/page-header.tsx +51 -0
- package/src/components/ui/page-layout.tsx +65 -0
- package/src/components/ui/pagination.tsx +104 -0
- package/src/components/ui/popover.tsx +57 -0
- package/src/components/ui/progress.tsx +61 -0
- package/src/components/ui/radio-group.tsx +37 -0
- package/src/components/ui/resizable.tsx +41 -0
- package/src/components/ui/scroll-area.tsx +48 -0
- package/src/components/ui/section.tsx +64 -0
- package/src/components/ui/select.tsx +166 -0
- package/src/components/ui/separator.tsx +17 -0
- package/src/components/ui/sheet.tsx +104 -0
- package/src/components/ui/sidebar.tsx +707 -0
- package/src/components/ui/skeleton.tsx +5 -0
- package/src/components/ui/slider.tsx +51 -0
- package/src/components/ui/sonner.tsx +43 -0
- package/src/components/ui/spinner.tsx +14 -0
- package/src/components/ui/stack.tsx +72 -0
- package/src/components/ui/switch.tsx +26 -0
- package/src/components/ui/table.tsx +65 -0
- package/src/components/ui/tabs.tsx +69 -0
- package/src/components/ui/text.tsx +59 -0
- package/src/components/ui/textarea.tsx +13 -0
- package/src/components/ui/toggle-group.tsx +87 -0
- package/src/components/ui/toggle.tsx +42 -0
- package/src/components/ui/tooltip.tsx +52 -0
- package/src/index.ts +3 -0
- package/src/styles/globals.css +122 -0
- package/tailwind.config.ts +59 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
const headingVariants = cva('font-semibold', {
|
|
5
|
+
variants: {
|
|
6
|
+
level: {
|
|
7
|
+
'1': 'text-2xl tracking-tight',
|
|
8
|
+
'2': 'text-xl',
|
|
9
|
+
'3': 'text-lg font-medium',
|
|
10
|
+
'4': 'text-base font-medium',
|
|
11
|
+
'5': 'text-sm font-medium',
|
|
12
|
+
'6': 'text-sm font-medium',
|
|
13
|
+
},
|
|
14
|
+
variant: {
|
|
15
|
+
default: 'text-foreground',
|
|
16
|
+
muted: 'text-muted-foreground',
|
|
17
|
+
},
|
|
18
|
+
tracking: {
|
|
19
|
+
default: '',
|
|
20
|
+
tight: 'tracking-tight',
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
defaultVariants: {
|
|
24
|
+
level: '1',
|
|
25
|
+
variant: 'default',
|
|
26
|
+
tracking: 'default',
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
type HeadingLevel = '1' | '2' | '3' | '4' | '5' | '6';
|
|
31
|
+
|
|
32
|
+
type HeadingProps<T extends HeadingLevel = '1'> = {
|
|
33
|
+
level?: T;
|
|
34
|
+
as?: `h${HeadingLevel}`;
|
|
35
|
+
} & Omit<VariantProps<typeof headingVariants>, 'level'> &
|
|
36
|
+
Omit<React.ComponentProps<`h${T}`>, 'className'>;
|
|
37
|
+
|
|
38
|
+
function Heading<T extends HeadingLevel = '1'>({
|
|
39
|
+
level = '1' as T,
|
|
40
|
+
as,
|
|
41
|
+
variant,
|
|
42
|
+
tracking,
|
|
43
|
+
...props
|
|
44
|
+
}: HeadingProps<T>) {
|
|
45
|
+
const Component = as ?? (`h${level}` as `h${T}`);
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<Component
|
|
49
|
+
data-slot="heading"
|
|
50
|
+
className={headingVariants({ level, variant, tracking })}
|
|
51
|
+
{...props}
|
|
52
|
+
/>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export { Heading, headingVariants };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { PreviewCard as PreviewCardPrimitive } from '@base-ui/react/preview-card';
|
|
4
|
+
|
|
5
|
+
import { cn } from '../../../lib/utils';
|
|
6
|
+
|
|
7
|
+
function HoverCard({ ...props }: PreviewCardPrimitive.Root.Props) {
|
|
8
|
+
return <PreviewCardPrimitive.Root data-slot="hover-card" {...props} />;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function HoverCardTrigger({ ...props }: PreviewCardPrimitive.Trigger.Props) {
|
|
12
|
+
return <PreviewCardPrimitive.Trigger data-slot="hover-card-trigger" {...props} />;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function HoverCardContent({
|
|
16
|
+
className,
|
|
17
|
+
side = 'bottom',
|
|
18
|
+
sideOffset = 4,
|
|
19
|
+
align = 'center',
|
|
20
|
+
alignOffset = 4,
|
|
21
|
+
...props
|
|
22
|
+
}: PreviewCardPrimitive.Popup.Props &
|
|
23
|
+
Pick<PreviewCardPrimitive.Positioner.Props, 'align' | 'alignOffset' | 'side' | 'sideOffset'>) {
|
|
24
|
+
return (
|
|
25
|
+
<PreviewCardPrimitive.Portal data-slot="hover-card-portal">
|
|
26
|
+
<PreviewCardPrimitive.Positioner
|
|
27
|
+
align={align}
|
|
28
|
+
alignOffset={alignOffset}
|
|
29
|
+
side={side}
|
|
30
|
+
sideOffset={sideOffset}
|
|
31
|
+
className="isolate z-50"
|
|
32
|
+
>
|
|
33
|
+
<PreviewCardPrimitive.Popup
|
|
34
|
+
data-slot="hover-card-content"
|
|
35
|
+
className={cn(
|
|
36
|
+
'data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-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 ring-foreground/10 bg-popover text-popover-foreground w-64 rounded-lg p-4 text-sm shadow-md ring-1 duration-100 z-50 origin-(--transform-origin) outline-hidden',
|
|
37
|
+
className,
|
|
38
|
+
)}
|
|
39
|
+
{...props}
|
|
40
|
+
/>
|
|
41
|
+
</PreviewCardPrimitive.Positioner>
|
|
42
|
+
</PreviewCardPrimitive.Portal>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export { HoverCard, HoverCardContent, HoverCardTrigger };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export * from './accordion';
|
|
2
|
+
export * from './alert';
|
|
3
|
+
export * from './alert-dialog';
|
|
4
|
+
export * from './aspect-ratio';
|
|
5
|
+
export * from './avatar';
|
|
6
|
+
export * from './badge';
|
|
7
|
+
export * from './breadcrumb';
|
|
8
|
+
export * from './button';
|
|
9
|
+
export * from './button-group';
|
|
10
|
+
export * from './calendar';
|
|
11
|
+
export * from './card';
|
|
12
|
+
export * from './carousel';
|
|
13
|
+
export * from './chart';
|
|
14
|
+
export * from './checkbox';
|
|
15
|
+
export * from './collapsible';
|
|
16
|
+
export * from './combobox';
|
|
17
|
+
export * from './command';
|
|
18
|
+
export * from './container';
|
|
19
|
+
export * from './context-menu';
|
|
20
|
+
export * from './dialog';
|
|
21
|
+
export * from './drawer';
|
|
22
|
+
export * from './dropdown-menu';
|
|
23
|
+
export * from './empty';
|
|
24
|
+
export * from './field';
|
|
25
|
+
export * from './grid';
|
|
26
|
+
export * from './heading';
|
|
27
|
+
export * from './hover-card';
|
|
28
|
+
export * from './input';
|
|
29
|
+
export * from './input-group';
|
|
30
|
+
export * from './input-otp';
|
|
31
|
+
export * from './item';
|
|
32
|
+
export * from './kbd';
|
|
33
|
+
export * from './label';
|
|
34
|
+
export * from './menubar';
|
|
35
|
+
export * from './navigation-menu';
|
|
36
|
+
export * from './page-header';
|
|
37
|
+
export * from './page-layout';
|
|
38
|
+
export * from './pagination';
|
|
39
|
+
export * from './popover';
|
|
40
|
+
export * from './progress';
|
|
41
|
+
export * from './radio-group';
|
|
42
|
+
export * from './resizable';
|
|
43
|
+
export * from './scroll-area';
|
|
44
|
+
export * from './section';
|
|
45
|
+
export * from './select';
|
|
46
|
+
export * from './separator';
|
|
47
|
+
export * from './sheet';
|
|
48
|
+
export * from './sidebar';
|
|
49
|
+
export * from './skeleton';
|
|
50
|
+
export * from './slider';
|
|
51
|
+
export * from './sonner';
|
|
52
|
+
export * from './spinner';
|
|
53
|
+
export * from './stack';
|
|
54
|
+
export * from './switch';
|
|
55
|
+
export * from './table';
|
|
56
|
+
export * from './tabs';
|
|
57
|
+
export * from './text';
|
|
58
|
+
export * from './textarea';
|
|
59
|
+
export * from './toggle';
|
|
60
|
+
export * from './toggle-group';
|
|
61
|
+
export * from './tooltip';
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { Button as ButtonPrimitive } from '@base-ui/react/button';
|
|
2
|
+
import { Input as InputPrimitive } from '@base-ui/react/input';
|
|
3
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
|
|
6
|
+
import { cn } from '../../../lib/utils';
|
|
7
|
+
import { buttonVariants } from './button';
|
|
8
|
+
|
|
9
|
+
function InputGroup({ ...props }: Omit<React.ComponentProps<'div'>, 'className'>) {
|
|
10
|
+
return (
|
|
11
|
+
<div
|
|
12
|
+
data-slot="input-group"
|
|
13
|
+
role="group"
|
|
14
|
+
className="border-input dark:bg-input/30 has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[[data-slot][aria-invalid=true]]:border-destructive dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40 has-disabled:bg-input/50 dark:has-disabled:bg-input/80 h-8 rounded-lg border transition-colors has-disabled:opacity-50 has-[[data-slot=input-group-control]:focus-visible]:ring-[3px] has-[[data-slot][aria-invalid=true]]:ring-[3px] has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3 has-[>[data-align=block-start]]:[&>input]:pb-3 has-[>[data-align=inline-end]]:[&>input]:pr-1.5 has-[>[data-align=inline-start]]:[&>input]:pl-1.5 [[data-slot=combobox-content]_&]:focus-within:border-inherit [[data-slot=combobox-content]_&]:focus-within:ring-0 group/input-group relative flex w-full min-w-0 items-center outline-none has-[>textarea]:h-auto"
|
|
15
|
+
{...props}
|
|
16
|
+
/>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const inputGroupAddonVariants = cva(
|
|
21
|
+
"text-muted-foreground h-auto gap-2 py-1.5 text-sm font-medium group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4 flex cursor-text items-center justify-center select-none",
|
|
22
|
+
{
|
|
23
|
+
variants: {
|
|
24
|
+
align: {
|
|
25
|
+
'inline-start': 'pl-2 has-[>button]:ml-[-0.25rem] has-[>kbd]:ml-[-0.15rem] order-first',
|
|
26
|
+
'inline-end': 'pr-2 has-[>button]:mr-[-0.25rem] has-[>kbd]:mr-[-0.15rem] order-last',
|
|
27
|
+
'block-start':
|
|
28
|
+
'px-2.5 pt-2 group-has-[>input]/input-group:pt-2 [.border-b]:pb-2 order-first w-full justify-start',
|
|
29
|
+
'block-end':
|
|
30
|
+
'px-2.5 pb-2 group-has-[>input]/input-group:pb-2 [.border-t]:pt-2 order-last w-full justify-start',
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
defaultVariants: {
|
|
34
|
+
align: 'inline-start',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
function InputGroupAddon({
|
|
40
|
+
align = 'inline-start',
|
|
41
|
+
...props
|
|
42
|
+
}: Omit<React.ComponentProps<'div'>, 'className'> & VariantProps<typeof inputGroupAddonVariants>) {
|
|
43
|
+
return (
|
|
44
|
+
<div
|
|
45
|
+
role="group"
|
|
46
|
+
data-slot="input-group-addon"
|
|
47
|
+
data-align={align}
|
|
48
|
+
className={inputGroupAddonVariants({ align })}
|
|
49
|
+
onClick={(e) => {
|
|
50
|
+
if ((e.target as HTMLElement).closest('button')) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
e.currentTarget.parentElement?.querySelector('input')?.focus();
|
|
54
|
+
}}
|
|
55
|
+
{...props}
|
|
56
|
+
/>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const inputGroupButtonVariants = cva('gap-2 text-sm shadow-none flex items-center', {
|
|
61
|
+
variants: {
|
|
62
|
+
size: {
|
|
63
|
+
xs: "h-6 gap-1 rounded-[calc(var(--radius)-5px)] px-1.5 [&>svg:not([class*='size-'])]:size-3.5",
|
|
64
|
+
sm: '',
|
|
65
|
+
'icon-xs': 'size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0',
|
|
66
|
+
'icon-sm': 'size-8 p-0 has-[>svg]:p-0',
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
defaultVariants: {
|
|
70
|
+
size: 'xs',
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
function InputGroupButton({
|
|
75
|
+
type = 'button',
|
|
76
|
+
variant = 'ghost',
|
|
77
|
+
size = 'xs',
|
|
78
|
+
...props
|
|
79
|
+
}: Omit<ButtonPrimitive.Props, 'className' | 'type'> &
|
|
80
|
+
VariantProps<typeof inputGroupButtonVariants> & {
|
|
81
|
+
variant?: 'default' | 'outline' | 'secondary' | 'ghost' | 'destructive' | 'link';
|
|
82
|
+
type?: 'button' | 'submit' | 'reset';
|
|
83
|
+
}) {
|
|
84
|
+
return (
|
|
85
|
+
<ButtonPrimitive
|
|
86
|
+
type={type}
|
|
87
|
+
data-size={size}
|
|
88
|
+
className={cn(buttonVariants({ variant }), inputGroupButtonVariants({ size }))}
|
|
89
|
+
{...props}
|
|
90
|
+
/>
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function InputGroupText({
|
|
95
|
+
align = 'inline-start',
|
|
96
|
+
...props
|
|
97
|
+
}: Omit<React.ComponentProps<'div'>, 'className'> & VariantProps<typeof inputGroupAddonVariants>) {
|
|
98
|
+
return <InputGroupAddon align={align} {...props} />;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function InputGroupInput({ ...props }: Omit<React.ComponentProps<'input'>, 'className'>) {
|
|
102
|
+
return (
|
|
103
|
+
<InputPrimitive
|
|
104
|
+
data-slot="input-group-control"
|
|
105
|
+
className="h-8 rounded-none border-0 bg-transparent px-2.5 py-1 text-base shadow-none ring-0 transition-colors focus-visible:ring-0 aria-invalid:ring-0 md:text-sm placeholder:text-muted-foreground w-full min-w-0 outline-none disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 dark:bg-transparent flex-1"
|
|
106
|
+
{...props}
|
|
107
|
+
/>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function InputGroupTextarea({ ...props }: Omit<React.ComponentProps<'textarea'>, 'className'>) {
|
|
112
|
+
return (
|
|
113
|
+
<textarea
|
|
114
|
+
data-slot="input-group-control"
|
|
115
|
+
className="rounded-none border-0 bg-transparent px-2.5 py-2 text-base shadow-none ring-0 transition-colors focus-visible:ring-0 aria-invalid:ring-0 md:text-sm placeholder:text-muted-foreground flex field-sizing-content min-h-16 w-full outline-none disabled:cursor-not-allowed disabled:opacity-50 dark:bg-transparent flex-1 resize-none"
|
|
116
|
+
{...props}
|
|
117
|
+
/>
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export {
|
|
122
|
+
InputGroup,
|
|
123
|
+
InputGroupAddon,
|
|
124
|
+
InputGroupButton,
|
|
125
|
+
InputGroupInput,
|
|
126
|
+
InputGroupText,
|
|
127
|
+
InputGroupTextarea,
|
|
128
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { OTPInput, OTPInputContext } from 'input-otp';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
import { MinusIcon } from 'lucide-react';
|
|
5
|
+
import { cn } from '../../../lib/utils';
|
|
6
|
+
|
|
7
|
+
function InputOTP({
|
|
8
|
+
className,
|
|
9
|
+
containerClassName,
|
|
10
|
+
...props
|
|
11
|
+
}: React.ComponentProps<typeof OTPInput> & {
|
|
12
|
+
containerClassName?: string;
|
|
13
|
+
}) {
|
|
14
|
+
return (
|
|
15
|
+
<OTPInput
|
|
16
|
+
data-slot="input-otp"
|
|
17
|
+
containerClassName={cn(
|
|
18
|
+
'cn-input-otp flex items-center has-disabled:opacity-50',
|
|
19
|
+
containerClassName,
|
|
20
|
+
)}
|
|
21
|
+
spellCheck={false}
|
|
22
|
+
className={cn('disabled:cursor-not-allowed', className)}
|
|
23
|
+
{...props}
|
|
24
|
+
/>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function InputOTPGroup({ className, ...props }: React.ComponentProps<'div'>) {
|
|
29
|
+
return (
|
|
30
|
+
<div
|
|
31
|
+
data-slot="input-otp-group"
|
|
32
|
+
className={cn(
|
|
33
|
+
'has-aria-invalid:ring-destructive/20 dark:has-aria-invalid:ring-destructive/40 has-aria-invalid:border-destructive rounded-md has-aria-invalid:ring-[3px] flex items-center',
|
|
34
|
+
className,
|
|
35
|
+
)}
|
|
36
|
+
{...props}
|
|
37
|
+
/>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function InputOTPSlot({
|
|
42
|
+
index,
|
|
43
|
+
className,
|
|
44
|
+
...props
|
|
45
|
+
}: React.ComponentProps<'div'> & {
|
|
46
|
+
index: number;
|
|
47
|
+
}) {
|
|
48
|
+
const inputOTPContext = React.useContext(OTPInputContext);
|
|
49
|
+
const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {};
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<div
|
|
53
|
+
data-slot="input-otp-slot"
|
|
54
|
+
data-active={isActive}
|
|
55
|
+
className={cn(
|
|
56
|
+
'dark:bg-input/30 border-input data-[active=true]:border-ring data-[active=true]:ring-ring/50 data-[active=true]:aria-invalid:ring-destructive/20 dark:data-[active=true]:aria-invalid:ring-destructive/40 aria-invalid:border-destructive data-[active=true]:aria-invalid:border-destructive size-9 border-y border-r text-sm shadow-xs transition-all outline-none first:rounded-l-md first:border-l last:rounded-r-md data-[active=true]:ring-[3px] relative flex items-center justify-center data-[active=true]:z-10',
|
|
57
|
+
className,
|
|
58
|
+
)}
|
|
59
|
+
{...props}
|
|
60
|
+
>
|
|
61
|
+
{char}
|
|
62
|
+
{hasFakeCaret && (
|
|
63
|
+
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
|
|
64
|
+
<div className="animate-caret-blink bg-foreground h-4 w-px duration-1000 bg-foreground h-4 w-px" />
|
|
65
|
+
</div>
|
|
66
|
+
)}
|
|
67
|
+
</div>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function InputOTPSeparator({ ...props }: React.ComponentProps<'div'>) {
|
|
72
|
+
return (
|
|
73
|
+
<div
|
|
74
|
+
data-slot="input-otp-separator"
|
|
75
|
+
className="[&_svg:not([class*='size-'])]:size-4 flex items-center"
|
|
76
|
+
role="separator"
|
|
77
|
+
{...props}
|
|
78
|
+
>
|
|
79
|
+
<MinusIcon />
|
|
80
|
+
</div>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Input as InputPrimitive } from '@base-ui/react/input';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
function Input({ type, ...props }: Omit<React.ComponentProps<'input'>, 'className'>) {
|
|
5
|
+
return (
|
|
6
|
+
<InputPrimitive
|
|
7
|
+
type={type}
|
|
8
|
+
data-slot="input"
|
|
9
|
+
className="dark:bg-input/30 border-input focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 disabled:bg-input/50 dark:disabled:bg-input/80 h-8 rounded-lg border bg-transparent px-2.5 py-1 text-base transition-colors file:h-6 file:text-sm file:font-medium focus-visible:ring-[3px] aria-invalid:ring-[3px] md:text-sm file:text-foreground placeholder:text-muted-foreground w-full min-w-0 outline-none file:inline-flex file:border-0 file:bg-transparent disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50"
|
|
10
|
+
{...props}
|
|
11
|
+
/>
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export { Input };
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { mergeProps } from '@base-ui/react/merge-props';
|
|
2
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
3
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
|
|
6
|
+
import { Separator as SeparatorPrimitive } from '@base-ui/react/separator';
|
|
7
|
+
import { cn } from '../../../lib/utils';
|
|
8
|
+
|
|
9
|
+
function ItemGroup({ className, ...props }: React.ComponentProps<'div'>) {
|
|
10
|
+
return (
|
|
11
|
+
<div
|
|
12
|
+
role="list"
|
|
13
|
+
data-slot="item-group"
|
|
14
|
+
className={cn(
|
|
15
|
+
'gap-4 has-[[data-size=sm]]:gap-2.5 has-[[data-size=xs]]:gap-2 group/item-group flex w-full flex-col',
|
|
16
|
+
className,
|
|
17
|
+
)}
|
|
18
|
+
{...props}
|
|
19
|
+
/>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function ItemSeparator({ ...props }: Omit<SeparatorPrimitive.Props, 'className'>) {
|
|
24
|
+
return (
|
|
25
|
+
<SeparatorPrimitive
|
|
26
|
+
data-slot="item-separator"
|
|
27
|
+
orientation="horizontal"
|
|
28
|
+
className="bg-border shrink-0 h-px w-full my-2"
|
|
29
|
+
{...props}
|
|
30
|
+
/>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const itemVariants = cva(
|
|
35
|
+
'[a]:hover:bg-muted rounded-md border text-sm w-full group/item focus-visible:border-ring focus-visible:ring-ring/50 flex items-center flex-wrap outline-none transition-colors duration-100 focus-visible:ring-[3px] [a]:transition-colors',
|
|
36
|
+
{
|
|
37
|
+
variants: {
|
|
38
|
+
variant: {
|
|
39
|
+
default: 'border-transparent',
|
|
40
|
+
outline: 'border-border',
|
|
41
|
+
muted: 'bg-muted/50 border-transparent',
|
|
42
|
+
},
|
|
43
|
+
size: {
|
|
44
|
+
default: 'gap-3.5 px-4 py-3.5',
|
|
45
|
+
sm: 'gap-2.5 px-3 py-2.5',
|
|
46
|
+
xs: 'gap-2 px-2.5 py-2 [[data-slot=dropdown-menu-content]_&]:p-0',
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
defaultVariants: {
|
|
50
|
+
variant: 'default',
|
|
51
|
+
size: 'default',
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
function Item({
|
|
57
|
+
className,
|
|
58
|
+
variant = 'default',
|
|
59
|
+
size = 'default',
|
|
60
|
+
render,
|
|
61
|
+
...props
|
|
62
|
+
}: useRender.ComponentProps<'div'> & VariantProps<typeof itemVariants>) {
|
|
63
|
+
return useRender({
|
|
64
|
+
defaultTagName: 'div',
|
|
65
|
+
props: mergeProps<'div'>(
|
|
66
|
+
{
|
|
67
|
+
className: cn(itemVariants({ variant, size, className })),
|
|
68
|
+
},
|
|
69
|
+
props,
|
|
70
|
+
),
|
|
71
|
+
render,
|
|
72
|
+
state: {
|
|
73
|
+
slot: 'item',
|
|
74
|
+
variant,
|
|
75
|
+
size,
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const itemMediaVariants = cva(
|
|
81
|
+
'gap-2 group-has-[[data-slot=item-description]]/item:translate-y-0.5 group-has-[[data-slot=item-description]]/item:self-start flex shrink-0 items-center justify-center [&_svg]:pointer-events-none',
|
|
82
|
+
{
|
|
83
|
+
variants: {
|
|
84
|
+
variant: {
|
|
85
|
+
default: 'bg-transparent',
|
|
86
|
+
icon: "[&_svg:not([class*='size-'])]:size-4",
|
|
87
|
+
image:
|
|
88
|
+
'size-10 overflow-hidden rounded-sm group-data-[size=sm]/item:size-8 group-data-[size=xs]/item:size-6 [&_img]:size-full [&_img]:object-cover',
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
defaultVariants: {
|
|
92
|
+
variant: 'default',
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
function ItemMedia({
|
|
98
|
+
className,
|
|
99
|
+
variant = 'default',
|
|
100
|
+
...props
|
|
101
|
+
}: React.ComponentProps<'div'> & VariantProps<typeof itemMediaVariants>) {
|
|
102
|
+
return (
|
|
103
|
+
<div
|
|
104
|
+
data-slot="item-media"
|
|
105
|
+
data-variant={variant}
|
|
106
|
+
className={cn(itemMediaVariants({ variant, className }))}
|
|
107
|
+
{...props}
|
|
108
|
+
/>
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function ItemContent({ className, ...props }: React.ComponentProps<'div'>) {
|
|
113
|
+
return (
|
|
114
|
+
<div
|
|
115
|
+
data-slot="item-content"
|
|
116
|
+
className={cn(
|
|
117
|
+
'gap-1 group-data-[size=xs]/item:gap-0 flex flex-1 flex-col [&+[data-slot=item-content]]:flex-none',
|
|
118
|
+
className,
|
|
119
|
+
)}
|
|
120
|
+
{...props}
|
|
121
|
+
/>
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function ItemTitle({ className, ...props }: React.ComponentProps<'div'>) {
|
|
126
|
+
return (
|
|
127
|
+
<div
|
|
128
|
+
data-slot="item-title"
|
|
129
|
+
className={cn(
|
|
130
|
+
'gap-2 text-sm leading-snug font-medium underline-offset-4 line-clamp-1 flex w-fit items-center',
|
|
131
|
+
className,
|
|
132
|
+
)}
|
|
133
|
+
{...props}
|
|
134
|
+
/>
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function ItemDescription({ className, ...props }: React.ComponentProps<'p'>) {
|
|
139
|
+
return (
|
|
140
|
+
<p
|
|
141
|
+
data-slot="item-description"
|
|
142
|
+
className={cn(
|
|
143
|
+
'text-muted-foreground text-left text-sm leading-normal group-data-[size=xs]/item:text-xs [&>a:hover]:text-primary line-clamp-2 font-normal [&>a]:underline [&>a]:underline-offset-4',
|
|
144
|
+
className,
|
|
145
|
+
)}
|
|
146
|
+
{...props}
|
|
147
|
+
/>
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function ItemActions({ className, ...props }: React.ComponentProps<'div'>) {
|
|
152
|
+
return (
|
|
153
|
+
<div data-slot="item-actions" className={cn('gap-2 flex items-center', className)} {...props} />
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function ItemHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
|
158
|
+
return (
|
|
159
|
+
<div
|
|
160
|
+
data-slot="item-header"
|
|
161
|
+
className={cn('gap-2 flex basis-full items-center justify-between', className)}
|
|
162
|
+
{...props}
|
|
163
|
+
/>
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function ItemFooter({ className, ...props }: React.ComponentProps<'div'>) {
|
|
168
|
+
return (
|
|
169
|
+
<div
|
|
170
|
+
data-slot="item-footer"
|
|
171
|
+
className={cn('gap-2 flex basis-full items-center justify-between', className)}
|
|
172
|
+
{...props}
|
|
173
|
+
/>
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export {
|
|
178
|
+
Item,
|
|
179
|
+
ItemActions,
|
|
180
|
+
ItemContent,
|
|
181
|
+
ItemDescription,
|
|
182
|
+
ItemFooter,
|
|
183
|
+
ItemGroup,
|
|
184
|
+
ItemHeader,
|
|
185
|
+
ItemMedia,
|
|
186
|
+
ItemSeparator,
|
|
187
|
+
ItemTitle,
|
|
188
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { cn } from '../../../lib/utils';
|
|
2
|
+
|
|
3
|
+
function Kbd({ className, ...props }: React.ComponentProps<'kbd'>) {
|
|
4
|
+
return (
|
|
5
|
+
<kbd
|
|
6
|
+
data-slot="kbd"
|
|
7
|
+
className={cn(
|
|
8
|
+
"bg-muted text-muted-foreground [[data-slot=tooltip-content]_&]:bg-background/20 [[data-slot=tooltip-content]_&]:text-background dark:[[data-slot=tooltip-content]_&]:bg-background/10 h-5 w-fit min-w-5 gap-1 rounded-sm px-1 font-sans text-xs font-medium [&_svg:not([class*='size-'])]:size-3 pointer-events-none inline-flex items-center justify-center select-none",
|
|
9
|
+
className,
|
|
10
|
+
)}
|
|
11
|
+
{...props}
|
|
12
|
+
/>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function KbdGroup({ className, ...props }: React.ComponentProps<'div'>) {
|
|
17
|
+
return (
|
|
18
|
+
<kbd
|
|
19
|
+
data-slot="kbd-group"
|
|
20
|
+
className={cn('gap-1 inline-flex items-center', className)}
|
|
21
|
+
{...props}
|
|
22
|
+
/>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export { Kbd, KbdGroup };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
|
|
5
|
+
function Label({ ...props }: Omit<React.ComponentProps<'label'>, 'className'>) {
|
|
6
|
+
return (
|
|
7
|
+
<label
|
|
8
|
+
data-slot="label"
|
|
9
|
+
className="gap-2 text-sm leading-none font-medium group-data-[disabled=true]:opacity-50 peer-disabled:opacity-50 flex items-center select-none group-data-[disabled=true]:pointer-events-none peer-disabled:cursor-not-allowed"
|
|
10
|
+
{...props}
|
|
11
|
+
/>
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export { Label };
|