@ptengine/design-components 0.3.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 +309 -0
- package/components.json +21 -0
- package/dist/components/ui/accordion.d.ts +8 -0
- package/dist/components/ui/accordion.d.ts.map +1 -0
- package/dist/components/ui/alert-dialog.d.ts +21 -0
- package/dist/components/ui/alert-dialog.d.ts.map +1 -0
- package/dist/components/ui/alert.d.ts +9 -0
- package/dist/components/ui/alert.d.ts.map +1 -0
- package/dist/components/ui/aspect-ratio.d.ts +4 -0
- package/dist/components/ui/aspect-ratio.d.ts.map +1 -0
- package/dist/components/ui/attachment.d.ts +26 -0
- package/dist/components/ui/attachment.d.ts.map +1 -0
- package/dist/components/ui/avatar.d.ts +10 -0
- package/dist/components/ui/avatar.d.ts.map +1 -0
- package/dist/components/ui/badge.d.ts +10 -0
- package/dist/components/ui/badge.d.ts.map +1 -0
- package/dist/components/ui/breadcrumb.d.ts +22 -0
- package/dist/components/ui/breadcrumb.d.ts.map +1 -0
- package/dist/components/ui/bubble.d.ts +19 -0
- package/dist/components/ui/bubble.d.ts.map +1 -0
- package/dist/components/ui/button-group.d.ts +13 -0
- package/dist/components/ui/button-group.d.ts.map +1 -0
- package/dist/components/ui/button.d.ts +13 -0
- package/dist/components/ui/button.d.ts.map +1 -0
- package/dist/components/ui/calendar.d.ts +9 -0
- package/dist/components/ui/calendar.d.ts.map +1 -0
- package/dist/components/ui/card.d.ts +9 -0
- package/dist/components/ui/card.d.ts.map +1 -0
- package/dist/components/ui/carousel.d.ts +23 -0
- package/dist/components/ui/carousel.d.ts.map +1 -0
- package/dist/components/ui/chart.d.ts +63 -0
- package/dist/components/ui/chart.d.ts.map +1 -0
- package/dist/components/ui/checkbox.d.ts +5 -0
- package/dist/components/ui/checkbox.d.ts.map +1 -0
- package/dist/components/ui/collapsible.d.ts +6 -0
- package/dist/components/ui/collapsible.d.ts.map +1 -0
- package/dist/components/ui/command.d.ts +81 -0
- package/dist/components/ui/command.d.ts.map +1 -0
- package/dist/components/ui/context-menu.d.ts +28 -0
- package/dist/components/ui/context-menu.d.ts.map +1 -0
- package/dist/components/ui/dialog.d.ts +22 -0
- package/dist/components/ui/dialog.d.ts.map +1 -0
- package/dist/components/ui/direction.d.ts +8 -0
- package/dist/components/ui/direction.d.ts.map +1 -0
- package/dist/components/ui/drawer.d.ts +23 -0
- package/dist/components/ui/drawer.d.ts.map +1 -0
- package/dist/components/ui/dropdown-menu.d.ts +28 -0
- package/dist/components/ui/dropdown-menu.d.ts.map +1 -0
- package/dist/components/ui/empty.d.ts +13 -0
- package/dist/components/ui/empty.d.ts.map +1 -0
- package/dist/components/ui/field.d.ts +25 -0
- package/dist/components/ui/field.d.ts.map +1 -0
- package/dist/components/ui/hover-card.d.ts +7 -0
- package/dist/components/ui/hover-card.d.ts.map +1 -0
- package/dist/components/ui/input-group.d.ts +13 -0
- package/dist/components/ui/input-group.d.ts.map +1 -0
- package/dist/components/ui/input-otp.d.ts +35 -0
- package/dist/components/ui/input-otp.d.ts.map +1 -0
- package/dist/components/ui/input.d.ts +5 -0
- package/dist/components/ui/input.d.ts.map +1 -0
- package/dist/components/ui/item.d.ts +24 -0
- package/dist/components/ui/item.d.ts.map +1 -0
- package/dist/components/ui/kbd.d.ts +5 -0
- package/dist/components/ui/kbd.d.ts.map +1 -0
- package/dist/components/ui/label.d.ts +6 -0
- package/dist/components/ui/label.d.ts.map +1 -0
- package/dist/components/ui/marker.d.ts +13 -0
- package/dist/components/ui/marker.d.ts.map +1 -0
- package/dist/components/ui/menubar.d.ts +29 -0
- package/dist/components/ui/menubar.d.ts.map +1 -0
- package/dist/components/ui/message-scroller.d.ts +26 -0
- package/dist/components/ui/message-scroller.d.ts.map +1 -0
- package/dist/components/ui/message.d.ts +11 -0
- package/dist/components/ui/message.d.ts.map +1 -0
- package/dist/components/ui/native-select.d.ts +4 -0
- package/dist/components/ui/native-select.d.ts.map +1 -0
- package/dist/components/ui/navigation-menu.d.ts +13 -0
- package/dist/components/ui/navigation-menu.d.ts.map +1 -0
- package/dist/components/ui/pagination.d.ts +35 -0
- package/dist/components/ui/pagination.d.ts.map +1 -0
- package/dist/components/ui/popover.d.ts +8 -0
- package/dist/components/ui/popover.d.ts.map +1 -0
- package/dist/components/ui/progress.d.ts +5 -0
- package/dist/components/ui/progress.d.ts.map +1 -0
- package/dist/components/ui/radio-group.d.ts +6 -0
- package/dist/components/ui/radio-group.d.ts.map +1 -0
- package/dist/components/ui/resizable.d.ts +24 -0
- package/dist/components/ui/resizable.d.ts.map +1 -0
- package/dist/components/ui/scroll-area.d.ts +6 -0
- package/dist/components/ui/scroll-area.d.ts.map +1 -0
- package/dist/components/ui/search-input.d.ts +23 -0
- package/dist/components/ui/search-input.d.ts.map +1 -0
- package/dist/components/ui/select.d.ts +14 -0
- package/dist/components/ui/select.d.ts.map +1 -0
- package/dist/components/ui/separator.d.ts +5 -0
- package/dist/components/ui/separator.d.ts.map +1 -0
- package/dist/components/ui/sheet.d.ts +28 -0
- package/dist/components/ui/sheet.d.ts.map +1 -0
- package/dist/components/ui/sidebar.d.ts +70 -0
- package/dist/components/ui/sidebar.d.ts.map +1 -0
- package/dist/components/ui/skeleton.d.ts +4 -0
- package/dist/components/ui/skeleton.d.ts.map +1 -0
- package/dist/components/ui/slider.d.ts +5 -0
- package/dist/components/ui/slider.d.ts.map +1 -0
- package/dist/components/ui/sonner.d.ts +6 -0
- package/dist/components/ui/sonner.d.ts.map +1 -0
- package/dist/components/ui/spinner.d.ts +7 -0
- package/dist/components/ui/spinner.d.ts.map +1 -0
- package/dist/components/ui/switch.d.ts +5 -0
- package/dist/components/ui/switch.d.ts.map +1 -0
- package/dist/components/ui/table.d.ts +11 -0
- package/dist/components/ui/table.d.ts.map +1 -0
- package/dist/components/ui/tabs.d.ts +13 -0
- package/dist/components/ui/tabs.d.ts.map +1 -0
- package/dist/components/ui/textarea.d.ts +5 -0
- package/dist/components/ui/textarea.d.ts.map +1 -0
- package/dist/components/ui/toggle-group.d.ts +13 -0
- package/dist/components/ui/toggle-group.d.ts.map +1 -0
- package/dist/components/ui/toggle.d.ts +13 -0
- package/dist/components/ui/toggle.d.ts.map +1 -0
- package/dist/components/ui/tooltip.d.ts +8 -0
- package/dist/components/ui/tooltip.d.ts.map +1 -0
- package/dist/hooks/use-mobile.d.ts +2 -0
- package/dist/hooks/use-mobile.d.ts.map +1 -0
- package/dist/index.cjs +82 -0
- package/dist/index.d.ts +71 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20969 -0
- package/dist/lib/utils.d.ts +4 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/llms.txt +173 -0
- package/package.json +125 -0
- package/src/components/ui/accordion.tsx +51 -0
- package/src/components/ui/alert-dialog.tsx +115 -0
- package/src/components/ui/alert.tsx +48 -0
- package/src/components/ui/aspect-ratio.tsx +5 -0
- package/src/components/ui/attachment.tsx +186 -0
- package/src/components/ui/avatar.tsx +57 -0
- package/src/components/ui/badge.tsx +40 -0
- package/src/components/ui/breadcrumb.tsx +101 -0
- package/src/components/ui/bubble.tsx +123 -0
- package/src/components/ui/button-group.tsx +74 -0
- package/src/components/ui/button.tsx +64 -0
- package/src/components/ui/calendar.tsx +63 -0
- package/src/components/ui/card.tsx +55 -0
- package/src/components/ui/carousel.tsx +252 -0
- package/src/components/ui/chart.tsx +323 -0
- package/src/components/ui/checkbox.tsx +26 -0
- package/src/components/ui/collapsible.tsx +9 -0
- package/src/components/ui/command.tsx +136 -0
- package/src/components/ui/context-menu.tsx +187 -0
- package/src/components/ui/dialog.tsx +103 -0
- package/src/components/ui/direction.tsx +15 -0
- package/src/components/ui/drawer.tsx +98 -0
- package/src/components/ui/dropdown-menu.tsx +186 -0
- package/src/components/ui/empty.tsx +75 -0
- package/src/components/ui/field.tsx +175 -0
- package/src/components/ui/hover-card.tsx +27 -0
- package/src/components/ui/input-group.tsx +80 -0
- package/src/components/ui/input-otp.tsx +67 -0
- package/src/components/ui/input.tsx +24 -0
- package/src/components/ui/item.tsx +118 -0
- package/src/components/ui/kbd.tsx +21 -0
- package/src/components/ui/label.tsx +19 -0
- package/src/components/ui/marker.tsx +67 -0
- package/src/components/ui/menubar.tsx +218 -0
- package/src/components/ui/message-scroller.tsx +206 -0
- package/src/components/ui/message.tsx +85 -0
- package/src/components/ui/native-select.tsx +29 -0
- package/src/components/ui/navigation-menu.tsx +120 -0
- package/src/components/ui/pagination.tsx +108 -0
- package/src/components/ui/popover.tsx +31 -0
- package/src/components/ui/progress.tsx +23 -0
- package/src/components/ui/radio-group.tsx +36 -0
- package/src/components/ui/resizable.tsx +40 -0
- package/src/components/ui/scroll-area.tsx +44 -0
- package/src/components/ui/search-input.tsx +97 -0
- package/src/components/ui/select.tsx +151 -0
- package/src/components/ui/separator.tsx +24 -0
- package/src/components/ui/sheet.tsx +124 -0
- package/src/components/ui/sidebar.tsx +704 -0
- package/src/components/ui/skeleton.tsx +9 -0
- package/src/components/ui/slider.tsx +41 -0
- package/src/components/ui/sonner.tsx +45 -0
- package/src/components/ui/spinner.tsx +21 -0
- package/src/components/ui/switch.tsx +27 -0
- package/src/components/ui/table.tsx +95 -0
- package/src/components/ui/tabs.tsx +119 -0
- package/src/components/ui/textarea.tsx +23 -0
- package/src/components/ui/toggle-group.tsx +55 -0
- package/src/components/ui/toggle.tsx +40 -0
- package/src/components/ui/tooltip.tsx +30 -0
- package/src/hooks/use-mobile.ts +19 -0
- package/src/index.ts +414 -0
- package/src/lib/utils.ts +7 -0
- package/src/styles/tokens.css +360 -0
- package/tailwind.preset.js +235 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
3
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
4
|
+
|
|
5
|
+
import { cn } from '../../lib/utils';
|
|
6
|
+
import { Button } from './button';
|
|
7
|
+
|
|
8
|
+
const attachmentVariants = cva(
|
|
9
|
+
'group/attachment relative isolate flex w-fit max-w-full min-w-0 shrink-0 flex-wrap rounded-[var(--pt-radius)] border bg-card text-card-foreground transition-colors focus-within:ring-1 focus-within:ring-ring data-[state=error]:border-destructive/30 data-[state=idle]:border-dashed after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:bg-[rgb(var(--pt-interaction-hover))] after:opacity-0 after:transition-opacity has-[>a,>button]:hover:after:opacity-100 has-[>a,>button]:active:after:bg-[rgb(var(--pt-interaction-press))] has-[>a,>button]:active:after:opacity-100',
|
|
10
|
+
{
|
|
11
|
+
variants: {
|
|
12
|
+
size: {
|
|
13
|
+
default:
|
|
14
|
+
'gap-[8px] text-[14px] leading-[20px] has-[[data-slot=attachment-content]]:px-[10px] has-[[data-slot=attachment-content]]:py-[8px] has-[[data-slot=attachment-media]]:p-[8px]',
|
|
15
|
+
sm: 'gap-[10px] text-[13px] leading-[20px] has-[[data-slot=attachment-content]]:px-[8px] has-[[data-slot=attachment-content]]:py-[6px] has-[[data-slot=attachment-media]]:p-[6px]',
|
|
16
|
+
xs: 'gap-[6px] rounded-[var(--pt-radius-md)] text-[13px] leading-[20px] has-[[data-slot=attachment-content]]:px-[6px] has-[[data-slot=attachment-content]]:py-[4px] has-[[data-slot=attachment-media]]:p-[4px]'
|
|
17
|
+
},
|
|
18
|
+
orientation: {
|
|
19
|
+
horizontal: 'min-w-[160px] items-center',
|
|
20
|
+
vertical: 'w-[96px] flex-col has-[[data-slot=attachment-content]]:w-[7.5rem]'
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
function Attachment({
|
|
27
|
+
className,
|
|
28
|
+
state = 'done',
|
|
29
|
+
size = 'default',
|
|
30
|
+
orientation = 'horizontal',
|
|
31
|
+
...props
|
|
32
|
+
}: React.HTMLAttributes<HTMLDivElement> &
|
|
33
|
+
VariantProps<typeof attachmentVariants> & {
|
|
34
|
+
state?: 'idle' | 'uploading' | 'processing' | 'error' | 'done';
|
|
35
|
+
}) {
|
|
36
|
+
return (
|
|
37
|
+
<div
|
|
38
|
+
data-slot="attachment"
|
|
39
|
+
data-state={state}
|
|
40
|
+
data-size={size}
|
|
41
|
+
data-orientation={orientation}
|
|
42
|
+
className={cn(attachmentVariants({ size, orientation }), className)}
|
|
43
|
+
{...props}
|
|
44
|
+
/>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const attachmentMediaVariants = cva(
|
|
49
|
+
"relative flex aspect-square w-[40px] shrink-0 items-center justify-center overflow-hidden rounded-[var(--pt-radius-md)] bg-muted text-foreground group-data-[orientation=vertical]/attachment:w-full group-data-[size=sm]/attachment:w-[32px] group-data-[size=xs]/attachment:w-[28px] group-data-[size=xs]/attachment:rounded-[var(--pt-radius-sm)] group-data-[state=error]/attachment:bg-destructive/10 group-data-[state=error]/attachment:text-destructive group-data-[orientation=vertical]/attachment:[&>[data-slot=spinner]]:!size-[24px] [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-[16px] group-data-[orientation=vertical]/attachment:[&_svg:not([class*='size-'])]:size-[24px] group-data-[size=xs]/attachment:[&_svg:not([class*='size-'])]:size-[14px]",
|
|
50
|
+
{
|
|
51
|
+
variants: {
|
|
52
|
+
variant: {
|
|
53
|
+
icon: '',
|
|
54
|
+
image: 'opacity-60 group-data-[state=done]/attachment:opacity-100 group-data-[state=idle]/attachment:opacity-100 [&>img]:aspect-square [&>img]:w-full [&>img]:object-cover'
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
defaultVariants: {
|
|
58
|
+
variant: 'icon'
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
function AttachmentMedia({
|
|
64
|
+
className,
|
|
65
|
+
variant = 'icon',
|
|
66
|
+
...props
|
|
67
|
+
}: React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof attachmentMediaVariants>) {
|
|
68
|
+
return (
|
|
69
|
+
<div
|
|
70
|
+
data-slot="attachment-media"
|
|
71
|
+
data-variant={variant}
|
|
72
|
+
className={cn(attachmentMediaVariants({ variant }), className)}
|
|
73
|
+
{...props}
|
|
74
|
+
/>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function AttachmentContent({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
|
|
79
|
+
return (
|
|
80
|
+
<div
|
|
81
|
+
data-slot="attachment-content"
|
|
82
|
+
className={cn(
|
|
83
|
+
'max-w-full min-w-0 flex-1 leading-tight group-data-[orientation=vertical]/attachment:px-[4px]',
|
|
84
|
+
className
|
|
85
|
+
)}
|
|
86
|
+
{...props}
|
|
87
|
+
/>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function AttachmentTitle({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) {
|
|
92
|
+
return (
|
|
93
|
+
<span
|
|
94
|
+
data-slot="attachment-title"
|
|
95
|
+
className={cn(
|
|
96
|
+
'block max-w-full min-w-0 truncate font-medium group-data-[state=processing]/attachment:animate-pulse group-data-[state=uploading]/attachment:animate-pulse',
|
|
97
|
+
className
|
|
98
|
+
)}
|
|
99
|
+
{...props}
|
|
100
|
+
/>
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function AttachmentDescription({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) {
|
|
105
|
+
return (
|
|
106
|
+
<span
|
|
107
|
+
data-slot="attachment-description"
|
|
108
|
+
className={cn(
|
|
109
|
+
'mt-[2px] block max-w-full min-w-0 truncate text-[13px] leading-[20px] text-muted-foreground group-data-[state=error]/attachment:text-destructive/80',
|
|
110
|
+
className
|
|
111
|
+
)}
|
|
112
|
+
{...props}
|
|
113
|
+
/>
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function AttachmentActions({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
|
|
118
|
+
return (
|
|
119
|
+
<div
|
|
120
|
+
data-slot="attachment-actions"
|
|
121
|
+
className={cn(
|
|
122
|
+
'relative z-20 flex shrink-0 items-center group-data-[orientation=vertical]/attachment:absolute group-data-[orientation=vertical]/attachment:right-[12px] group-data-[orientation=vertical]/attachment:top-[12px] group-data-[orientation=vertical]/attachment:gap-[4px]',
|
|
123
|
+
className
|
|
124
|
+
)}
|
|
125
|
+
{...props}
|
|
126
|
+
/>
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function AttachmentAction({ className, variant, size, ...props }: React.ComponentProps<typeof Button>) {
|
|
131
|
+
return (
|
|
132
|
+
<Button
|
|
133
|
+
data-slot="attachment-action"
|
|
134
|
+
variant={variant ?? 'ghost'}
|
|
135
|
+
size={size ?? 'icon'}
|
|
136
|
+
className={cn('h-[24px] w-[24px] rounded-[var(--pt-radius-sm)] [&_svg]:size-[14px]', className)}
|
|
137
|
+
{...props}
|
|
138
|
+
/>
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function AttachmentTrigger({
|
|
143
|
+
className,
|
|
144
|
+
asChild = false,
|
|
145
|
+
type,
|
|
146
|
+
...props
|
|
147
|
+
}: React.ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
148
|
+
/** Render the child element as the root (e.g. an <a>), keeping the hit area. */
|
|
149
|
+
asChild?: boolean;
|
|
150
|
+
}) {
|
|
151
|
+
const Comp = asChild ? Slot : 'button';
|
|
152
|
+
|
|
153
|
+
return (
|
|
154
|
+
<Comp
|
|
155
|
+
data-slot="attachment-trigger"
|
|
156
|
+
type={asChild ? undefined : (type ?? 'button')}
|
|
157
|
+
className={cn('absolute inset-0 z-10 cursor-pointer outline-none', className)}
|
|
158
|
+
{...props}
|
|
159
|
+
/>
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function AttachmentGroup({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
|
|
164
|
+
return (
|
|
165
|
+
<div
|
|
166
|
+
data-slot="attachment-group"
|
|
167
|
+
className={cn(
|
|
168
|
+
'flex min-w-0 snap-x snap-mandatory scroll-px-[4px] gap-[12px] overflow-x-auto overscroll-x-contain py-[4px] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden [&>[data-slot=attachment]]:flex-none [&>[data-slot=attachment]]:snap-start',
|
|
169
|
+
className
|
|
170
|
+
)}
|
|
171
|
+
{...props}
|
|
172
|
+
/>
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export {
|
|
177
|
+
Attachment,
|
|
178
|
+
AttachmentGroup,
|
|
179
|
+
AttachmentMedia,
|
|
180
|
+
AttachmentContent,
|
|
181
|
+
AttachmentTitle,
|
|
182
|
+
AttachmentDescription,
|
|
183
|
+
AttachmentActions,
|
|
184
|
+
AttachmentAction,
|
|
185
|
+
AttachmentTrigger
|
|
186
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import * as AvatarPrimitive from '@radix-ui/react-avatar';
|
|
3
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
4
|
+
|
|
5
|
+
import { cn } from '../../lib/utils';
|
|
6
|
+
|
|
7
|
+
/* 头像三档:sm 24(字12)· md 32(字13)· lg 40(字14,默认)。字号作用于 Fallback 首字母 */
|
|
8
|
+
const avatarVariants = cva('relative flex shrink-0 overflow-hidden rounded-full', {
|
|
9
|
+
variants: {
|
|
10
|
+
size: {
|
|
11
|
+
sm: 'h-[24px] w-[24px] text-[12px] leading-[16px]',
|
|
12
|
+
md: 'h-[32px] w-[32px] text-[13px] leading-[20px]',
|
|
13
|
+
lg: 'h-[40px] w-[40px] text-[14px] leading-[20px]'
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
defaultVariants: {
|
|
17
|
+
size: 'lg'
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const Avatar = React.forwardRef<
|
|
22
|
+
React.ElementRef<typeof AvatarPrimitive.Root>,
|
|
23
|
+
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root> &
|
|
24
|
+
VariantProps<typeof avatarVariants>
|
|
25
|
+
>(({ className, size, ...props }, ref) => (
|
|
26
|
+
<AvatarPrimitive.Root ref={ref} className={cn(avatarVariants({ size }), className)} {...props} />
|
|
27
|
+
));
|
|
28
|
+
Avatar.displayName = AvatarPrimitive.Root.displayName;
|
|
29
|
+
|
|
30
|
+
const AvatarImage = React.forwardRef<
|
|
31
|
+
React.ElementRef<typeof AvatarPrimitive.Image>,
|
|
32
|
+
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
|
|
33
|
+
>(({ className, ...props }, ref) => (
|
|
34
|
+
<AvatarPrimitive.Image
|
|
35
|
+
ref={ref}
|
|
36
|
+
className={cn('aspect-square h-full w-full', className)}
|
|
37
|
+
{...props}
|
|
38
|
+
/>
|
|
39
|
+
));
|
|
40
|
+
AvatarImage.displayName = AvatarPrimitive.Image.displayName;
|
|
41
|
+
|
|
42
|
+
const AvatarFallback = React.forwardRef<
|
|
43
|
+
React.ElementRef<typeof AvatarPrimitive.Fallback>,
|
|
44
|
+
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
|
|
45
|
+
>(({ className, ...props }, ref) => (
|
|
46
|
+
<AvatarPrimitive.Fallback
|
|
47
|
+
ref={ref}
|
|
48
|
+
className={cn(
|
|
49
|
+
'flex h-full w-full items-center justify-center rounded-full bg-secondary text-foreground',
|
|
50
|
+
className
|
|
51
|
+
)}
|
|
52
|
+
{...props}
|
|
53
|
+
/>
|
|
54
|
+
));
|
|
55
|
+
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
|
|
56
|
+
|
|
57
|
+
export { Avatar, AvatarImage, AvatarFallback };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
3
|
+
|
|
4
|
+
import { cn } from '../../lib/utils';
|
|
5
|
+
|
|
6
|
+
const badgeVariants = cva(
|
|
7
|
+
'inline-flex items-center rounded-full border px-[10px] py-[2px] text-[13px] leading-[20px] font-semibold transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 [--pt-state-layer-border:1px] [&:is(a,button)]:cursor-pointer',
|
|
8
|
+
{
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
default:
|
|
12
|
+
'border-transparent bg-primary text-primary-foreground [&:is(a,button)]:state-layer-inverse',
|
|
13
|
+
secondary:
|
|
14
|
+
'border-transparent bg-neutral-subtler text-neutral [&:is(a,button)]:state-layer',
|
|
15
|
+
destructive:
|
|
16
|
+
'border-transparent bg-danger-subtler text-danger [&:is(a,button)]:state-layer',
|
|
17
|
+
success:
|
|
18
|
+
'border-transparent bg-positive-subtler text-success [&:is(a,button)]:state-layer',
|
|
19
|
+
warning:
|
|
20
|
+
'border-transparent bg-warning-subtler text-warning [&:is(a,button)]:state-layer',
|
|
21
|
+
information:
|
|
22
|
+
'border-transparent bg-information-subtler text-information [&:is(a,button)]:state-layer',
|
|
23
|
+
ai: 'border-transparent bg-ai-subtler text-ai [&:is(a,button)]:state-layer'
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
defaultVariants: {
|
|
27
|
+
variant: 'default'
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
export interface BadgeProps
|
|
33
|
+
extends React.HTMLAttributes<HTMLDivElement>,
|
|
34
|
+
VariantProps<typeof badgeVariants> {}
|
|
35
|
+
|
|
36
|
+
function Badge({ className, variant, ...props }: BadgeProps) {
|
|
37
|
+
return <div className={cn(badgeVariants({ variant }), className)} {...props} />;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export { Badge, badgeVariants };
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
3
|
+
import { ChevronRight, MoreHorizontal } from 'lucide-react';
|
|
4
|
+
|
|
5
|
+
import { cn } from '../../lib/utils';
|
|
6
|
+
|
|
7
|
+
const Breadcrumb = React.forwardRef<
|
|
8
|
+
HTMLElement,
|
|
9
|
+
React.ComponentPropsWithoutRef<'nav'> & { separator?: React.ReactNode }
|
|
10
|
+
>(({ ...props }, ref) => <nav ref={ref} aria-label="breadcrumb" {...props} />);
|
|
11
|
+
Breadcrumb.displayName = 'Breadcrumb';
|
|
12
|
+
|
|
13
|
+
const BreadcrumbList = React.forwardRef<HTMLOListElement, React.ComponentPropsWithoutRef<'ol'>>(
|
|
14
|
+
({ className, ...props }, ref) => (
|
|
15
|
+
<ol
|
|
16
|
+
ref={ref}
|
|
17
|
+
className={cn(
|
|
18
|
+
'flex flex-wrap items-center gap-[6px] break-words text-[14px] leading-[20px] text-muted-foreground sm:gap-[10px]',
|
|
19
|
+
className
|
|
20
|
+
)}
|
|
21
|
+
{...props}
|
|
22
|
+
/>
|
|
23
|
+
)
|
|
24
|
+
);
|
|
25
|
+
BreadcrumbList.displayName = 'BreadcrumbList';
|
|
26
|
+
|
|
27
|
+
const BreadcrumbItem = React.forwardRef<HTMLLIElement, React.ComponentPropsWithoutRef<'li'>>(
|
|
28
|
+
({ className, ...props }, ref) => (
|
|
29
|
+
<li ref={ref} className={cn('inline-flex items-center gap-[6px]', className)} {...props} />
|
|
30
|
+
)
|
|
31
|
+
);
|
|
32
|
+
BreadcrumbItem.displayName = 'BreadcrumbItem';
|
|
33
|
+
|
|
34
|
+
const BreadcrumbLink = React.forwardRef<
|
|
35
|
+
HTMLAnchorElement,
|
|
36
|
+
React.ComponentPropsWithoutRef<'a'> & { asChild?: boolean }
|
|
37
|
+
>(({ asChild, className, ...props }, ref) => {
|
|
38
|
+
const Comp = asChild ? Slot : 'a';
|
|
39
|
+
return (
|
|
40
|
+
<Comp
|
|
41
|
+
ref={ref}
|
|
42
|
+
className={cn('transition-colors hover:text-foreground', className)}
|
|
43
|
+
{...props}
|
|
44
|
+
/>
|
|
45
|
+
);
|
|
46
|
+
});
|
|
47
|
+
BreadcrumbLink.displayName = 'BreadcrumbLink';
|
|
48
|
+
|
|
49
|
+
const BreadcrumbPage = React.forwardRef<HTMLSpanElement, React.ComponentPropsWithoutRef<'span'>>(
|
|
50
|
+
({ className, ...props }, ref) => (
|
|
51
|
+
<span
|
|
52
|
+
ref={ref}
|
|
53
|
+
role="link"
|
|
54
|
+
aria-disabled="true"
|
|
55
|
+
aria-current="page"
|
|
56
|
+
className={cn('font-normal text-foreground', className)}
|
|
57
|
+
{...props}
|
|
58
|
+
/>
|
|
59
|
+
)
|
|
60
|
+
);
|
|
61
|
+
BreadcrumbPage.displayName = 'BreadcrumbPage';
|
|
62
|
+
|
|
63
|
+
const BreadcrumbSeparator = ({ children, className, ...props }: React.ComponentProps<'li'>) => (
|
|
64
|
+
<li
|
|
65
|
+
role="presentation"
|
|
66
|
+
aria-hidden="true"
|
|
67
|
+
className={cn('[&>svg]:size-[14px]', className)}
|
|
68
|
+
{...props}
|
|
69
|
+
>
|
|
70
|
+
{children ?? <ChevronRight />}
|
|
71
|
+
</li>
|
|
72
|
+
);
|
|
73
|
+
BreadcrumbSeparator.displayName = 'BreadcrumbSeparator';
|
|
74
|
+
|
|
75
|
+
/* label:读屏文案,库不做 i18n,消费方传译文(默认英文) */
|
|
76
|
+
const BreadcrumbEllipsis = ({
|
|
77
|
+
className,
|
|
78
|
+
label = 'More',
|
|
79
|
+
...props
|
|
80
|
+
}: React.ComponentProps<'span'> & { label?: string }) => (
|
|
81
|
+
<span
|
|
82
|
+
role="presentation"
|
|
83
|
+
aria-hidden="true"
|
|
84
|
+
className={cn('flex h-[32px] w-[36px] items-center justify-center', className)}
|
|
85
|
+
{...props}
|
|
86
|
+
>
|
|
87
|
+
<MoreHorizontal className="h-[16px] w-[16px]" />
|
|
88
|
+
<span className="sr-only">{label}</span>
|
|
89
|
+
</span>
|
|
90
|
+
);
|
|
91
|
+
BreadcrumbEllipsis.displayName = 'BreadcrumbEllipsis';
|
|
92
|
+
|
|
93
|
+
export {
|
|
94
|
+
Breadcrumb,
|
|
95
|
+
BreadcrumbList,
|
|
96
|
+
BreadcrumbItem,
|
|
97
|
+
BreadcrumbLink,
|
|
98
|
+
BreadcrumbPage,
|
|
99
|
+
BreadcrumbSeparator,
|
|
100
|
+
BreadcrumbEllipsis
|
|
101
|
+
};
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
3
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
4
|
+
|
|
5
|
+
import { cn } from '../../lib/utils';
|
|
6
|
+
|
|
7
|
+
function BubbleGroup({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
|
|
8
|
+
return (
|
|
9
|
+
<div
|
|
10
|
+
data-slot="bubble-group"
|
|
11
|
+
className={cn('flex min-w-0 flex-col gap-[8px]', className)}
|
|
12
|
+
{...props}
|
|
13
|
+
/>
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const bubbleVariants = cva(
|
|
18
|
+
'group/bubble relative flex w-fit max-w-[80%] min-w-0 flex-col gap-[4px] group-data-[align=end]/message:self-end data-[align=end]:self-end data-[variant=ghost]:max-w-full',
|
|
19
|
+
{
|
|
20
|
+
variants: {
|
|
21
|
+
variant: {
|
|
22
|
+
default:
|
|
23
|
+
'[&>[data-slot=bubble-content]]:bg-primary [&>[data-slot=bubble-content]]:text-primary-foreground [&>[data-slot=bubble-content]]:[--pt-interaction-hover:var(--pt-interaction-reversal-hover)] [&>[data-slot=bubble-content]]:[--pt-interaction-press:var(--pt-interaction-reversal-press)]',
|
|
24
|
+
secondary:
|
|
25
|
+
'[&>[data-slot=bubble-content]]:bg-secondary [&>[data-slot=bubble-content]]:text-secondary-foreground',
|
|
26
|
+
muted: '[&>[data-slot=bubble-content]]:bg-muted',
|
|
27
|
+
outline:
|
|
28
|
+
'[&>[data-slot=bubble-content]]:border-input [&>[data-slot=bubble-content]]:bg-background [&>[data-slot=bubble-content]]:[--pt-state-layer-border:1px]',
|
|
29
|
+
ghost: 'border-none [&>[data-slot=bubble-content]]:rounded-none [&>[data-slot=bubble-content]]:bg-transparent [&>[data-slot=bubble-content]]:p-0',
|
|
30
|
+
destructive:
|
|
31
|
+
'[&>[data-slot=bubble-content]]:bg-destructive/10 [&>[data-slot=bubble-content]]:text-destructive dark:[&>[data-slot=bubble-content]]:bg-destructive/20'
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
defaultVariants: {
|
|
35
|
+
variant: 'default'
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
function Bubble({
|
|
41
|
+
variant = 'default',
|
|
42
|
+
align = 'start',
|
|
43
|
+
className,
|
|
44
|
+
...props
|
|
45
|
+
}: React.HTMLAttributes<HTMLDivElement> &
|
|
46
|
+
VariantProps<typeof bubbleVariants> & {
|
|
47
|
+
align?: 'start' | 'end';
|
|
48
|
+
}) {
|
|
49
|
+
return (
|
|
50
|
+
<div
|
|
51
|
+
data-slot="bubble"
|
|
52
|
+
data-variant={variant}
|
|
53
|
+
data-align={align}
|
|
54
|
+
className={cn(bubbleVariants({ variant }), className)}
|
|
55
|
+
{...props}
|
|
56
|
+
/>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function BubbleContent({
|
|
61
|
+
asChild = false,
|
|
62
|
+
className,
|
|
63
|
+
...props
|
|
64
|
+
}: React.HTMLAttributes<HTMLDivElement> & {
|
|
65
|
+
/** Render the child element as the root (e.g. a <button>), keeping Bubble styles. */
|
|
66
|
+
asChild?: boolean;
|
|
67
|
+
}) {
|
|
68
|
+
const Comp = asChild ? Slot : 'div';
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<Comp
|
|
72
|
+
data-slot="bubble-content"
|
|
73
|
+
className={cn(
|
|
74
|
+
'w-fit max-w-full min-w-0 overflow-hidden break-words rounded-[var(--pt-radius)] border border-transparent px-[12px] py-[8px] text-[14px] leading-[20px] leading-relaxed group-data-[align=end]/bubble:self-end',
|
|
75
|
+
'[&:is(button,a)]:state-layer [&:is(button)]:text-left [&:is(button,a)]:cursor-pointer [&:is(button,a)]:focus-visible:outline-none [&:is(button,a)]:focus-visible:ring-1 [&:is(button,a)]:focus-visible:ring-ring',
|
|
76
|
+
className
|
|
77
|
+
)}
|
|
78
|
+
{...props}
|
|
79
|
+
/>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const bubbleReactionsVariants = cva(
|
|
84
|
+
'absolute z-10 flex w-fit shrink-0 items-center justify-center gap-[4px] rounded-full bg-muted px-[6px] py-[2px] text-[14px] leading-[20px] ring ring-card has-[button]:p-0',
|
|
85
|
+
{
|
|
86
|
+
variants: {
|
|
87
|
+
side: {
|
|
88
|
+
top: 'top-0 -translate-y-3/4',
|
|
89
|
+
bottom: 'bottom-0 translate-y-3/4'
|
|
90
|
+
},
|
|
91
|
+
align: {
|
|
92
|
+
start: 'left-[12px]',
|
|
93
|
+
end: 'right-[12px]'
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
defaultVariants: {
|
|
97
|
+
side: 'bottom',
|
|
98
|
+
align: 'end'
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
function BubbleReactions({
|
|
104
|
+
side = 'bottom',
|
|
105
|
+
align = 'end',
|
|
106
|
+
className,
|
|
107
|
+
...props
|
|
108
|
+
}: React.HTMLAttributes<HTMLDivElement> & {
|
|
109
|
+
align?: 'start' | 'end';
|
|
110
|
+
side?: 'top' | 'bottom';
|
|
111
|
+
}) {
|
|
112
|
+
return (
|
|
113
|
+
<div
|
|
114
|
+
data-slot="bubble-reactions"
|
|
115
|
+
data-align={align}
|
|
116
|
+
data-side={side}
|
|
117
|
+
className={cn(bubbleReactionsVariants({ side, align }), className)}
|
|
118
|
+
{...props}
|
|
119
|
+
/>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export { BubbleGroup, Bubble, BubbleContent, BubbleReactions };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
3
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
4
|
+
|
|
5
|
+
import { cn } from '../../lib/utils';
|
|
6
|
+
import { Separator } from './separator';
|
|
7
|
+
|
|
8
|
+
const buttonGroupVariants = cva(
|
|
9
|
+
"flex w-fit items-stretch has-[>[data-slot=button-group]]:gap-[8px] [&>*]:focus-visible:relative [&>*]:focus-visible:z-10 [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1",
|
|
10
|
+
{
|
|
11
|
+
variants: {
|
|
12
|
+
orientation: {
|
|
13
|
+
horizontal:
|
|
14
|
+
'[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none [&>*:not(:first-child)]:after:left-0',
|
|
15
|
+
vertical:
|
|
16
|
+
'flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none [&>*:not(:first-child)]:after:top-0'
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
defaultVariants: {
|
|
20
|
+
orientation: 'horizontal'
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
function ButtonGroup({
|
|
26
|
+
className,
|
|
27
|
+
orientation,
|
|
28
|
+
...props
|
|
29
|
+
}: React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof buttonGroupVariants>) {
|
|
30
|
+
return (
|
|
31
|
+
<div
|
|
32
|
+
role="group"
|
|
33
|
+
data-slot="button-group"
|
|
34
|
+
data-orientation={orientation}
|
|
35
|
+
className={cn(buttonGroupVariants({ orientation }), className)}
|
|
36
|
+
{...props}
|
|
37
|
+
/>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function ButtonGroupText({
|
|
42
|
+
className,
|
|
43
|
+
asChild = false,
|
|
44
|
+
...props
|
|
45
|
+
}: React.HTMLAttributes<HTMLDivElement> & { asChild?: boolean }) {
|
|
46
|
+
const Comp = asChild ? Slot : 'div';
|
|
47
|
+
return (
|
|
48
|
+
<Comp
|
|
49
|
+
data-slot="button-group-text"
|
|
50
|
+
className={cn(
|
|
51
|
+
"flex items-center gap-[8px] rounded-[var(--pt-radius-md)] border bg-muted px-[16px] text-[14px] leading-[20px] font-medium text-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-[16px]",
|
|
52
|
+
className
|
|
53
|
+
)}
|
|
54
|
+
{...props}
|
|
55
|
+
/>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function ButtonGroupSeparator({
|
|
60
|
+
className,
|
|
61
|
+
orientation = 'vertical',
|
|
62
|
+
...props
|
|
63
|
+
}: React.ComponentProps<typeof Separator>) {
|
|
64
|
+
return (
|
|
65
|
+
<Separator
|
|
66
|
+
data-slot="button-group-separator"
|
|
67
|
+
orientation={orientation}
|
|
68
|
+
className={cn('relative !m-0 self-stretch bg-input data-[orientation=vertical]:h-auto', className)}
|
|
69
|
+
{...props}
|
|
70
|
+
/>
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export { ButtonGroup, ButtonGroupSeparator, ButtonGroupText, buttonGroupVariants };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
3
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
4
|
+
|
|
5
|
+
import { cn } from '../../lib/utils';
|
|
6
|
+
|
|
7
|
+
const buttonVariants = cva(
|
|
8
|
+
'inline-flex items-center justify-center gap-[8px] whitespace-nowrap rounded-[var(--pt-radius-md)] text-[14px] leading-[20px] font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-[16px] [&_svg]:shrink-0',
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
default: 'state-layer-inverse bg-primary text-primary-foreground',
|
|
13
|
+
brand: 'state-layer bg-brand text-brand-foreground',
|
|
14
|
+
secondary:
|
|
15
|
+
'state-layer border border-input bg-background text-foreground [--pt-state-layer-border:1px]',
|
|
16
|
+
tertiary: 'state-layer bg-secondary text-secondary-foreground',
|
|
17
|
+
destructive: 'state-layer bg-destructive text-destructive-foreground',
|
|
18
|
+
ghost: 'state-layer text-foreground',
|
|
19
|
+
/* 静默警示钮:常态同 ghost/secondary,hover/按下 内容变 --pt-red(删除等场景) */
|
|
20
|
+
'ghost-destructive':
|
|
21
|
+
'state-layer text-foreground hover:text-[rgb(var(--pt-red))] active:text-[rgb(var(--pt-red))]',
|
|
22
|
+
'secondary-destructive':
|
|
23
|
+
'state-layer border border-input bg-background text-foreground [--pt-state-layer-border:1px] hover:text-[rgb(var(--pt-red))] active:text-[rgb(var(--pt-red))]',
|
|
24
|
+
link: 'text-primary underline-offset-4 hover:underline'
|
|
25
|
+
},
|
|
26
|
+
/* 控件三档刻度:sm 24(字12/图16)· default 32(字13/图16)· lg 40(字14/图20);语义图标 16/16/20 */
|
|
27
|
+
size: {
|
|
28
|
+
sm: 'h-[24px] gap-[4px] rounded-[var(--pt-radius-sm)] px-[8px] text-[12px] leading-[16px]',
|
|
29
|
+
default: 'h-[32px] rounded-[var(--pt-radius-md)] px-[12px] text-[13px] leading-[20px]',
|
|
30
|
+
lg: 'h-[40px] rounded-[var(--pt-radius-md)] px-[16px] text-[14px] leading-[20px] [&_svg]:size-[20px]',
|
|
31
|
+
'icon-sm': 'h-[24px] w-[24px] rounded-[var(--pt-radius-sm)]',
|
|
32
|
+
icon: 'h-[32px] w-[32px]',
|
|
33
|
+
'icon-lg': 'h-[40px] w-[40px] [&_svg]:size-[20px]'
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
defaultVariants: {
|
|
37
|
+
variant: 'default',
|
|
38
|
+
size: 'default'
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
export interface ButtonProps
|
|
44
|
+
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
45
|
+
VariantProps<typeof buttonVariants> {
|
|
46
|
+
/** Render the child element as the root (e.g. an <a>), keeping Button styles. */
|
|
47
|
+
asChild?: boolean;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
51
|
+
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
52
|
+
const Comp = asChild ? Slot : 'button';
|
|
53
|
+
return (
|
|
54
|
+
<Comp
|
|
55
|
+
className={cn(buttonVariants({ variant, size, className }))}
|
|
56
|
+
ref={ref}
|
|
57
|
+
{...props}
|
|
58
|
+
/>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
Button.displayName = 'Button';
|
|
63
|
+
|
|
64
|
+
export { Button, buttonVariants };
|