@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,51 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Slider as SliderPrimitive } from '@base-ui/react/slider';
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
|
|
6
|
+
function Slider({
|
|
7
|
+
defaultValue,
|
|
8
|
+
value,
|
|
9
|
+
min = 0,
|
|
10
|
+
max = 100,
|
|
11
|
+
...props
|
|
12
|
+
}: Omit<SliderPrimitive.Root.Props, 'className'>) {
|
|
13
|
+
const _values = React.useMemo(
|
|
14
|
+
() => (Array.isArray(value) ? value : Array.isArray(defaultValue) ? defaultValue : [min, max]),
|
|
15
|
+
[value, defaultValue, min, max],
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<SliderPrimitive.Root
|
|
20
|
+
className="data-horizontal:w-full data-vertical:h-full"
|
|
21
|
+
data-slot="slider"
|
|
22
|
+
defaultValue={defaultValue}
|
|
23
|
+
value={value}
|
|
24
|
+
min={min}
|
|
25
|
+
max={max}
|
|
26
|
+
thumbAlignment="edge"
|
|
27
|
+
{...props}
|
|
28
|
+
>
|
|
29
|
+
<SliderPrimitive.Control className="data-vertical:min-h-40 relative flex w-full touch-none items-center select-none data-disabled:opacity-50 data-vertical:h-full data-vertical:w-auto data-vertical:flex-col">
|
|
30
|
+
<SliderPrimitive.Track
|
|
31
|
+
data-slot="slider-track"
|
|
32
|
+
className="bg-muted rounded-full data-horizontal:h-1.5 data-horizontal:w-full data-vertical:h-full data-vertical:w-1.5 relative overflow-hidden select-none"
|
|
33
|
+
>
|
|
34
|
+
<SliderPrimitive.Indicator
|
|
35
|
+
data-slot="slider-range"
|
|
36
|
+
className="bg-primary select-none data-horizontal:h-full data-vertical:w-full"
|
|
37
|
+
/>
|
|
38
|
+
</SliderPrimitive.Track>
|
|
39
|
+
{Array.from({ length: _values.length }, (_, index) => (
|
|
40
|
+
<SliderPrimitive.Thumb
|
|
41
|
+
data-slot="slider-thumb"
|
|
42
|
+
key={index}
|
|
43
|
+
className="border-primary ring-ring/50 size-4 rounded-full border bg-white shadow-sm transition-[color,box-shadow] hover:ring-4 focus-visible:ring-4 focus-visible:outline-hidden block shrink-0 select-none disabled:pointer-events-none disabled:opacity-50"
|
|
44
|
+
/>
|
|
45
|
+
))}
|
|
46
|
+
</SliderPrimitive.Control>
|
|
47
|
+
</SliderPrimitive.Root>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export { Slider };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CircleCheckIcon,
|
|
3
|
+
InfoIcon,
|
|
4
|
+
Loader2Icon,
|
|
5
|
+
OctagonXIcon,
|
|
6
|
+
TriangleAlertIcon,
|
|
7
|
+
} from 'lucide-react';
|
|
8
|
+
import { useTheme } from 'next-themes';
|
|
9
|
+
import { Toaster as Sonner, type ToasterProps } from 'sonner';
|
|
10
|
+
|
|
11
|
+
const Toaster = ({ ...props }: ToasterProps) => {
|
|
12
|
+
const { theme = 'system' } = useTheme();
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<Sonner
|
|
16
|
+
theme={theme as ToasterProps['theme']}
|
|
17
|
+
className="toaster group"
|
|
18
|
+
icons={{
|
|
19
|
+
success: <CircleCheckIcon className="size-4" />,
|
|
20
|
+
info: <InfoIcon className="size-4" />,
|
|
21
|
+
warning: <TriangleAlertIcon className="size-4" />,
|
|
22
|
+
error: <OctagonXIcon className="size-4" />,
|
|
23
|
+
loading: <Loader2Icon className="size-4 animate-spin" />,
|
|
24
|
+
}}
|
|
25
|
+
style={
|
|
26
|
+
{
|
|
27
|
+
'--normal-bg': 'var(--popover)',
|
|
28
|
+
'--normal-text': 'var(--popover-foreground)',
|
|
29
|
+
'--normal-border': 'var(--border)',
|
|
30
|
+
'--border-radius': 'var(--radius)',
|
|
31
|
+
} as React.CSSProperties
|
|
32
|
+
}
|
|
33
|
+
toastOptions={{
|
|
34
|
+
classNames: {
|
|
35
|
+
toast: 'cn-toast',
|
|
36
|
+
},
|
|
37
|
+
}}
|
|
38
|
+
{...props}
|
|
39
|
+
/>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export { Toaster };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Loader2Icon } from 'lucide-react';
|
|
2
|
+
|
|
3
|
+
function Spinner({ ...props }: Omit<React.ComponentProps<'svg'>, 'className'>) {
|
|
4
|
+
return (
|
|
5
|
+
<Loader2Icon
|
|
6
|
+
role="status"
|
|
7
|
+
aria-label="Loading"
|
|
8
|
+
className="size-4 shrink-0 animate-spin"
|
|
9
|
+
{...props}
|
|
10
|
+
/>
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export { Spinner };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
const stackVariants = cva('flex', {
|
|
5
|
+
variants: {
|
|
6
|
+
direction: {
|
|
7
|
+
row: 'flex-row',
|
|
8
|
+
column: 'flex-col',
|
|
9
|
+
'row-reverse': 'flex-row-reverse',
|
|
10
|
+
'column-reverse': 'flex-col-reverse',
|
|
11
|
+
},
|
|
12
|
+
align: {
|
|
13
|
+
start: 'items-start',
|
|
14
|
+
center: 'items-center',
|
|
15
|
+
end: 'items-end',
|
|
16
|
+
stretch: 'items-stretch',
|
|
17
|
+
baseline: 'items-baseline',
|
|
18
|
+
},
|
|
19
|
+
textAlign: {
|
|
20
|
+
left: 'text-left',
|
|
21
|
+
center: 'text-center',
|
|
22
|
+
right: 'text-right',
|
|
23
|
+
},
|
|
24
|
+
justify: {
|
|
25
|
+
start: 'justify-start',
|
|
26
|
+
center: 'justify-center',
|
|
27
|
+
end: 'justify-end',
|
|
28
|
+
between: 'justify-between',
|
|
29
|
+
around: 'justify-around',
|
|
30
|
+
evenly: 'justify-evenly',
|
|
31
|
+
},
|
|
32
|
+
gap: {
|
|
33
|
+
'0': 'gap-0',
|
|
34
|
+
'0.5': 'gap-0.5',
|
|
35
|
+
'1': 'gap-1',
|
|
36
|
+
'1.5': 'gap-1.5',
|
|
37
|
+
'2': 'gap-2',
|
|
38
|
+
'2.5': 'gap-2.5',
|
|
39
|
+
'3': 'gap-3',
|
|
40
|
+
'4': 'gap-4',
|
|
41
|
+
'5': 'gap-5',
|
|
42
|
+
'6': 'gap-6',
|
|
43
|
+
'8': 'gap-8',
|
|
44
|
+
'10': 'gap-10',
|
|
45
|
+
'12': 'gap-12',
|
|
46
|
+
},
|
|
47
|
+
wrap: {
|
|
48
|
+
true: 'flex-wrap',
|
|
49
|
+
false: 'flex-nowrap',
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
defaultVariants: {
|
|
53
|
+
direction: 'column',
|
|
54
|
+
gap: '0',
|
|
55
|
+
wrap: false,
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
interface StackProps
|
|
60
|
+
extends Omit<React.ComponentProps<'div'>, 'className'>, VariantProps<typeof stackVariants> {}
|
|
61
|
+
|
|
62
|
+
function Stack({ direction, align, justify, gap, wrap, textAlign, ...props }: StackProps) {
|
|
63
|
+
return (
|
|
64
|
+
<div
|
|
65
|
+
data-slot="stack"
|
|
66
|
+
className={stackVariants({ direction, align, justify, gap, wrap, textAlign })}
|
|
67
|
+
{...props}
|
|
68
|
+
/>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export { Stack, stackVariants };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Switch as SwitchPrimitive } from '@base-ui/react/switch';
|
|
4
|
+
|
|
5
|
+
function Switch({
|
|
6
|
+
size = 'default',
|
|
7
|
+
...props
|
|
8
|
+
}: Omit<SwitchPrimitive.Root.Props, 'className'> & {
|
|
9
|
+
size?: 'sm' | 'default';
|
|
10
|
+
}) {
|
|
11
|
+
return (
|
|
12
|
+
<SwitchPrimitive.Root
|
|
13
|
+
data-slot="switch"
|
|
14
|
+
data-size={size}
|
|
15
|
+
className="data-checked:bg-primary data-unchecked:bg-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 dark:data-unchecked:bg-input/80 shrink-0 rounded-full border border-transparent shadow-xs focus-visible:ring-[3px] aria-invalid:ring-[3px] data-[size=default]:h-[18.4px] data-[size=default]:w-[32px] data-[size=sm]:h-[14px] data-[size=sm]:w-[24px] peer group/switch relative inline-flex items-center transition-all outline-none after:absolute after:-inset-x-3 after:-inset-y-2 data-disabled:cursor-not-allowed data-disabled:opacity-50"
|
|
16
|
+
{...props}
|
|
17
|
+
>
|
|
18
|
+
<SwitchPrimitive.Thumb
|
|
19
|
+
data-slot="switch-thumb"
|
|
20
|
+
className="bg-background dark:data-unchecked:bg-foreground dark:data-checked:bg-primary-foreground rounded-full group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 group-data-[size=default]/switch:data-checked:translate-x-[calc(100%-2px)] group-data-[size=sm]/switch:data-checked:translate-x-[calc(100%-2px)] group-data-[size=default]/switch:data-unchecked:translate-x-0 group-data-[size=sm]/switch:data-unchecked:translate-x-0 pointer-events-none block ring-0 transition-transform"
|
|
21
|
+
/>
|
|
22
|
+
</SwitchPrimitive.Root>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export { Switch };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
function Table({ ...props }: Omit<React.ComponentProps<'table'>, 'className'>) {
|
|
4
|
+
return (
|
|
5
|
+
<div data-slot="table-container" className="relative w-full overflow-x-auto">
|
|
6
|
+
<table data-slot="table" className="w-full caption-bottom text-sm" {...props} />
|
|
7
|
+
</div>
|
|
8
|
+
);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function TableHeader({ ...props }: Omit<React.ComponentProps<'thead'>, 'className'>) {
|
|
12
|
+
return <thead data-slot="table-header" className="[&_tr]:border-b" {...props} />;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function TableBody({ ...props }: Omit<React.ComponentProps<'tbody'>, 'className'>) {
|
|
16
|
+
return <tbody data-slot="table-body" className="[&_tr:last-child]:border-0" {...props} />;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function TableFooter({ ...props }: Omit<React.ComponentProps<'tfoot'>, 'className'>) {
|
|
20
|
+
return (
|
|
21
|
+
<tfoot
|
|
22
|
+
data-slot="table-footer"
|
|
23
|
+
className="bg-muted/50 border-t font-medium [&>tr]:last:border-b-0"
|
|
24
|
+
{...props}
|
|
25
|
+
/>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function TableRow({ ...props }: Omit<React.ComponentProps<'tr'>, 'className'>) {
|
|
30
|
+
return (
|
|
31
|
+
<tr
|
|
32
|
+
data-slot="table-row"
|
|
33
|
+
className="hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors"
|
|
34
|
+
{...props}
|
|
35
|
+
/>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function TableHead({ ...props }: Omit<React.ComponentProps<'th'>, 'className'>) {
|
|
40
|
+
return (
|
|
41
|
+
<th
|
|
42
|
+
data-slot="table-head"
|
|
43
|
+
className="text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0"
|
|
44
|
+
{...props}
|
|
45
|
+
/>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function TableCell({ ...props }: Omit<React.ComponentProps<'td'>, 'className'>) {
|
|
50
|
+
return (
|
|
51
|
+
<td
|
|
52
|
+
data-slot="table-cell"
|
|
53
|
+
className="p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0"
|
|
54
|
+
{...props}
|
|
55
|
+
/>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function TableCaption({ ...props }: Omit<React.ComponentProps<'caption'>, 'className'>) {
|
|
60
|
+
return (
|
|
61
|
+
<caption data-slot="table-caption" className="text-muted-foreground mt-4 text-sm" {...props} />
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export { Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Tabs as TabsPrimitive } from '@base-ui/react/tabs';
|
|
4
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
5
|
+
|
|
6
|
+
function Tabs({
|
|
7
|
+
orientation = 'horizontal',
|
|
8
|
+
...props
|
|
9
|
+
}: Omit<TabsPrimitive.Root.Props, 'className'>) {
|
|
10
|
+
return (
|
|
11
|
+
<TabsPrimitive.Root
|
|
12
|
+
data-slot="tabs"
|
|
13
|
+
data-orientation={orientation}
|
|
14
|
+
className="gap-2 group/tabs flex data-[orientation=horizontal]:flex-col"
|
|
15
|
+
{...props}
|
|
16
|
+
/>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const tabsListVariants = cva(
|
|
21
|
+
'rounded-lg p-[3px] group-data-horizontal/tabs:h-8 data-[variant=line]:rounded-none group/tabs-list text-muted-foreground inline-flex w-fit items-center justify-center group-data-[orientation=vertical]/tabs:h-fit group-data-[orientation=vertical]/tabs:flex-col',
|
|
22
|
+
{
|
|
23
|
+
variants: {
|
|
24
|
+
variant: {
|
|
25
|
+
default: 'bg-muted',
|
|
26
|
+
line: 'gap-1 bg-transparent',
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
defaultVariants: {
|
|
30
|
+
variant: 'default',
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
function TabsList({
|
|
36
|
+
variant = 'default',
|
|
37
|
+
...props
|
|
38
|
+
}: Omit<TabsPrimitive.List.Props, 'className'> & VariantProps<typeof tabsListVariants>) {
|
|
39
|
+
return (
|
|
40
|
+
<TabsPrimitive.List
|
|
41
|
+
data-slot="tabs-list"
|
|
42
|
+
data-variant={variant}
|
|
43
|
+
className={tabsListVariants({ variant })}
|
|
44
|
+
{...props}
|
|
45
|
+
/>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function TabsTrigger({ ...props }: Omit<TabsPrimitive.Tab.Props, 'className'>) {
|
|
50
|
+
return (
|
|
51
|
+
<TabsPrimitive.Tab
|
|
52
|
+
data-slot="tabs-trigger"
|
|
53
|
+
className="gap-1.5 rounded-md border border-transparent px-1.5 py-0.5 text-sm font-medium group-data-[variant=default]/tabs-list:data-active:shadow-sm group-data-[variant=line]/tabs-list:data-active:shadow-none [&_svg:not([class*='size-'])]:size-4 focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring text-foreground/60 hover:text-foreground dark:text-muted-foreground dark:hover:text-foreground relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center whitespace-nowrap transition-all group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent data-active:bg-background dark:data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 data-active:text-foreground after:bg-foreground after:absolute after:opacity-0 after:transition-opacity group-data-[orientation=horizontal]/tabs:after:inset-x-0 group-data-[orientation=horizontal]/tabs:after:bottom-[-5px] group-data-[orientation=horizontal]/tabs:after:h-0.5 group-data-[orientation=vertical]/tabs:after:inset-y-0 group-data-[orientation=vertical]/tabs:after:-right-1 group-data-[orientation=vertical]/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100"
|
|
54
|
+
{...props}
|
|
55
|
+
/>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function TabsContent({ ...props }: Omit<TabsPrimitive.Panel.Props, 'className'>) {
|
|
60
|
+
return (
|
|
61
|
+
<TabsPrimitive.Panel
|
|
62
|
+
data-slot="tabs-content"
|
|
63
|
+
className="text-sm flex-1 outline-none"
|
|
64
|
+
{...props}
|
|
65
|
+
/>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export { Tabs, TabsContent, TabsList, tabsListVariants, TabsTrigger };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
const textVariants = cva('', {
|
|
5
|
+
variants: {
|
|
6
|
+
size: {
|
|
7
|
+
xs: 'text-xs',
|
|
8
|
+
sm: 'text-sm',
|
|
9
|
+
base: 'text-base',
|
|
10
|
+
lg: 'text-lg',
|
|
11
|
+
},
|
|
12
|
+
variant: {
|
|
13
|
+
default: 'text-foreground',
|
|
14
|
+
muted: 'text-muted-foreground',
|
|
15
|
+
primary: 'text-primary',
|
|
16
|
+
destructive: 'text-destructive',
|
|
17
|
+
success: 'text-green-600 dark:text-green-400',
|
|
18
|
+
},
|
|
19
|
+
weight: {
|
|
20
|
+
normal: 'font-normal',
|
|
21
|
+
medium: 'font-medium',
|
|
22
|
+
semibold: 'font-semibold',
|
|
23
|
+
},
|
|
24
|
+
leading: {
|
|
25
|
+
tight: 'leading-tight',
|
|
26
|
+
snug: 'leading-snug',
|
|
27
|
+
normal: 'leading-normal',
|
|
28
|
+
relaxed: 'leading-relaxed',
|
|
29
|
+
},
|
|
30
|
+
font: {
|
|
31
|
+
sans: 'font-sans',
|
|
32
|
+
mono: 'font-mono tabular-nums',
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
defaultVariants: {
|
|
36
|
+
size: 'base',
|
|
37
|
+
variant: 'default',
|
|
38
|
+
weight: 'normal',
|
|
39
|
+
leading: 'normal',
|
|
40
|
+
font: 'sans',
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
interface TextProps
|
|
45
|
+
extends Omit<React.HTMLAttributes<HTMLElement>, 'className'>, VariantProps<typeof textVariants> {
|
|
46
|
+
as?: 'p' | 'span' | 'div';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function Text({ as: Component = 'p', size, variant, weight, leading, font, ...props }: TextProps) {
|
|
50
|
+
return (
|
|
51
|
+
<Component
|
|
52
|
+
data-slot="text"
|
|
53
|
+
className={textVariants({ size, variant, weight, leading, font })}
|
|
54
|
+
{...props}
|
|
55
|
+
/>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export { Text, textVariants };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
function Textarea({ ...props }: Omit<React.ComponentProps<'textarea'>, 'className'>) {
|
|
4
|
+
return (
|
|
5
|
+
<textarea
|
|
6
|
+
data-slot="textarea"
|
|
7
|
+
className="border-input dark:bg-input/30 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 rounded-lg border bg-transparent px-2.5 py-2 text-base transition-colors focus-visible:ring-[3px] aria-invalid:ring-[3px] 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"
|
|
8
|
+
{...props}
|
|
9
|
+
/>
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export { Textarea };
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Toggle as TogglePrimitive } from '@base-ui/react/toggle';
|
|
4
|
+
import { ToggleGroup as ToggleGroupPrimitive } from '@base-ui/react/toggle-group';
|
|
5
|
+
import { type VariantProps } from 'class-variance-authority';
|
|
6
|
+
import * as React from 'react';
|
|
7
|
+
|
|
8
|
+
import { cn } from '../../../lib/utils';
|
|
9
|
+
import { toggleVariants } from './toggle';
|
|
10
|
+
|
|
11
|
+
const ToggleGroupContext = React.createContext<
|
|
12
|
+
VariantProps<typeof toggleVariants> & {
|
|
13
|
+
spacing?: number;
|
|
14
|
+
orientation?: 'horizontal' | 'vertical';
|
|
15
|
+
}
|
|
16
|
+
>({
|
|
17
|
+
size: 'default',
|
|
18
|
+
variant: 'default',
|
|
19
|
+
spacing: 0,
|
|
20
|
+
orientation: 'horizontal',
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
type ToggleGroupProps = Omit<ToggleGroupPrimitive.Props, 'className'> &
|
|
24
|
+
VariantProps<typeof toggleVariants> & {
|
|
25
|
+
spacing?: number;
|
|
26
|
+
orientation?: 'horizontal' | 'vertical';
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
function ToggleGroup({
|
|
30
|
+
variant,
|
|
31
|
+
size,
|
|
32
|
+
spacing = 0,
|
|
33
|
+
orientation = 'horizontal',
|
|
34
|
+
children,
|
|
35
|
+
...props
|
|
36
|
+
}: ToggleGroupProps) {
|
|
37
|
+
return (
|
|
38
|
+
<ToggleGroupPrimitive
|
|
39
|
+
data-slot="toggle-group"
|
|
40
|
+
data-variant={variant}
|
|
41
|
+
data-size={size}
|
|
42
|
+
data-spacing={spacing}
|
|
43
|
+
data-orientation={orientation}
|
|
44
|
+
style={{ '--gap': spacing } as React.CSSProperties}
|
|
45
|
+
className="rounded-md data-[spacing=0]:data-[variant=outline]:shadow-xs group/toggle-group flex w-fit flex-row items-center gap-[--spacing(var(--gap))] data-[orientation=vertical]:flex-col data-[orientation=vertical]:items-stretch"
|
|
46
|
+
{...props}
|
|
47
|
+
>
|
|
48
|
+
<ToggleGroupContext.Provider value={{ variant, size, spacing, orientation }}>
|
|
49
|
+
{children}
|
|
50
|
+
</ToggleGroupContext.Provider>
|
|
51
|
+
</ToggleGroupPrimitive>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
type ToggleGroupItemProps = Omit<TogglePrimitive.Props, 'className'> &
|
|
56
|
+
VariantProps<typeof toggleVariants>;
|
|
57
|
+
|
|
58
|
+
function ToggleGroupItem({
|
|
59
|
+
children,
|
|
60
|
+
variant = 'default',
|
|
61
|
+
size = 'default',
|
|
62
|
+
...props
|
|
63
|
+
}: ToggleGroupItemProps) {
|
|
64
|
+
const context = React.useContext(ToggleGroupContext);
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<TogglePrimitive
|
|
68
|
+
data-slot="toggle-group-item"
|
|
69
|
+
data-variant={context.variant || variant}
|
|
70
|
+
data-size={context.size || size}
|
|
71
|
+
data-spacing={context.spacing}
|
|
72
|
+
className={cn(
|
|
73
|
+
'data-[state=on]:bg-muted group-data-[spacing=0]/toggle-group:rounded-none group-data-[spacing=0]/toggle-group:px-2 group-data-[spacing=0]/toggle-group:shadow-none group-data-horizontal/toggle-group:data-[spacing=0]:first:rounded-l-md group-data-vertical/toggle-group:data-[spacing=0]:first:rounded-t-md group-data-horizontal/toggle-group:data-[spacing=0]:last:rounded-r-md group-data-vertical/toggle-group:data-[spacing=0]:last:rounded-b-md shrink-0 focus:z-10 focus-visible:z-10 group-data-horizontal/toggle-group:data-[spacing=0]:data-[variant=outline]:border-l-0 group-data-vertical/toggle-group:data-[spacing=0]:data-[variant=outline]:border-t-0 group-data-horizontal/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-l group-data-vertical/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-t',
|
|
74
|
+
toggleVariants({
|
|
75
|
+
variant: context.variant || variant,
|
|
76
|
+
size: context.size || size,
|
|
77
|
+
}),
|
|
78
|
+
)}
|
|
79
|
+
{...props}
|
|
80
|
+
>
|
|
81
|
+
{children}
|
|
82
|
+
</TogglePrimitive>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export { ToggleGroup, ToggleGroupItem };
|
|
87
|
+
export type { ToggleGroupItemProps, ToggleGroupProps };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Toggle as TogglePrimitive } from '@base-ui/react/toggle';
|
|
2
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
3
|
+
|
|
4
|
+
import { cn } from '../../../lib/utils';
|
|
5
|
+
|
|
6
|
+
const toggleVariants = cva(
|
|
7
|
+
"hover:text-foreground aria-pressed:bg-muted focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive gap-1 rounded-md text-sm font-medium transition-[color,box-shadow] [&_svg:not([class*='size-'])]:size-4 group/toggle hover:bg-muted inline-flex items-center justify-center whitespace-nowrap outline-none focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
8
|
+
{
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
default: 'bg-transparent',
|
|
12
|
+
outline: 'border-input hover:bg-muted border bg-transparent shadow-xs',
|
|
13
|
+
},
|
|
14
|
+
size: {
|
|
15
|
+
default: 'h-9 min-w-9 px-2',
|
|
16
|
+
sm: 'h-8 min-w-8 px-1.5',
|
|
17
|
+
lg: 'h-10 min-w-10 px-2.5',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
defaultVariants: {
|
|
21
|
+
variant: 'default',
|
|
22
|
+
size: 'default',
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
function Toggle({
|
|
28
|
+
className,
|
|
29
|
+
variant = 'default',
|
|
30
|
+
size = 'default',
|
|
31
|
+
...props
|
|
32
|
+
}: TogglePrimitive.Props & VariantProps<typeof toggleVariants>) {
|
|
33
|
+
return (
|
|
34
|
+
<TogglePrimitive
|
|
35
|
+
data-slot="toggle"
|
|
36
|
+
className={cn(toggleVariants({ variant, size, className }))}
|
|
37
|
+
{...props}
|
|
38
|
+
/>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export { Toggle, toggleVariants };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Tooltip as TooltipPrimitive } from '@base-ui/react/tooltip';
|
|
4
|
+
|
|
5
|
+
function TooltipProvider({ delay = 0, ...props }: TooltipPrimitive.Provider.Props) {
|
|
6
|
+
return <TooltipPrimitive.Provider data-slot="tooltip-provider" delay={delay} {...props} />;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function Tooltip({ ...props }: TooltipPrimitive.Root.Props) {
|
|
10
|
+
return (
|
|
11
|
+
<TooltipProvider>
|
|
12
|
+
<TooltipPrimitive.Root data-slot="tooltip" {...props} />
|
|
13
|
+
</TooltipProvider>
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function TooltipTrigger({ ...props }: Omit<TooltipPrimitive.Trigger.Props, 'className'>) {
|
|
18
|
+
return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function TooltipContent({
|
|
22
|
+
side = 'top',
|
|
23
|
+
sideOffset = 4,
|
|
24
|
+
align = 'center',
|
|
25
|
+
alignOffset = 0,
|
|
26
|
+
children,
|
|
27
|
+
...props
|
|
28
|
+
}: Omit<TooltipPrimitive.Popup.Props, 'className'> &
|
|
29
|
+
Pick<TooltipPrimitive.Positioner.Props, 'align' | 'alignOffset' | 'side' | 'sideOffset'>) {
|
|
30
|
+
return (
|
|
31
|
+
<TooltipPrimitive.Portal>
|
|
32
|
+
<TooltipPrimitive.Positioner
|
|
33
|
+
align={align}
|
|
34
|
+
alignOffset={alignOffset}
|
|
35
|
+
side={side}
|
|
36
|
+
sideOffset={sideOffset}
|
|
37
|
+
className="isolate z-50"
|
|
38
|
+
>
|
|
39
|
+
<TooltipPrimitive.Popup
|
|
40
|
+
data-slot="tooltip-content"
|
|
41
|
+
className="data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-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 rounded-md px-3 py-1.5 text-xs bg-foreground text-background z-50 w-fit max-w-xs origin-(--transform-origin)"
|
|
42
|
+
{...props}
|
|
43
|
+
>
|
|
44
|
+
{children}
|
|
45
|
+
<TooltipPrimitive.Arrow className="size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground z-50 data-[side=bottom]:top-1 data-[side=left]:top-1/2! data-[side=left]:-right-1 data-[side=left]:-translate-y-1/2 data-[side=right]:top-1/2! data-[side=right]:-left-1 data-[side=right]:-translate-y-1/2 data-[side=top]:-bottom-2.5" />
|
|
46
|
+
</TooltipPrimitive.Popup>
|
|
47
|
+
</TooltipPrimitive.Positioner>
|
|
48
|
+
</TooltipPrimitive.Portal>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };
|
package/src/index.ts
ADDED