@srcroot/ui 0.0.55 → 0.0.58

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.
Files changed (107) hide show
  1. package/README.md +151 -151
  2. package/dist/index.d.ts +0 -0
  3. package/dist/index.js +120 -93
  4. package/package.json +7 -2
  5. package/src/registry/analytics/google-analytics.tsx +36 -39
  6. package/src/registry/analytics/google-tag-manager.tsx +62 -65
  7. package/src/registry/analytics/meta-pixel.tsx +44 -47
  8. package/src/registry/analytics/microsoft-clarity.tsx +31 -34
  9. package/src/registry/analytics/tiktok-pixel.tsx +34 -37
  10. package/src/registry/lib/utils.ts +0 -0
  11. package/src/registry/themes/v3/blue.css +157 -157
  12. package/src/registry/themes/v3/glass.css +153 -153
  13. package/src/registry/themes/v3/gray.css +157 -157
  14. package/src/registry/themes/v3/green.css +157 -157
  15. package/src/registry/themes/v3/neutral.css +157 -157
  16. package/src/registry/themes/v3/orange.css +157 -157
  17. package/src/registry/themes/v3/rose.css +157 -157
  18. package/src/registry/themes/v3/slate.css +157 -157
  19. package/src/registry/themes/v3/stone.css +157 -157
  20. package/src/registry/themes/v3/violet.css +186 -186
  21. package/src/registry/themes/v3/zinc.css +157 -157
  22. package/src/registry/themes/v4/blue.css +184 -184
  23. package/src/registry/themes/v4/glass.css +180 -180
  24. package/src/registry/themes/v4/gray.css +184 -184
  25. package/src/registry/themes/v4/green.css +184 -184
  26. package/src/registry/themes/v4/neutral.css +184 -184
  27. package/src/registry/themes/v4/orange.css +184 -184
  28. package/src/registry/themes/v4/rose.css +184 -184
  29. package/src/registry/themes/v4/slate.css +184 -184
  30. package/src/registry/themes/v4/stone.css +184 -184
  31. package/src/registry/themes/v4/violet.css +184 -184
  32. package/src/registry/themes/v4/zinc.css +184 -184
  33. package/src/registry/ui/accordion.tsx +164 -165
  34. package/src/registry/ui/alert-dialog.tsx +213 -214
  35. package/src/registry/ui/alert.tsx +73 -76
  36. package/src/registry/ui/aspect-ratio.tsx +44 -47
  37. package/src/registry/ui/avatar.tsx +96 -97
  38. package/src/registry/ui/badge.tsx +52 -55
  39. package/src/registry/ui/breadcrumb.tsx +147 -150
  40. package/src/registry/ui/button-group.tsx +64 -67
  41. package/src/registry/ui/button.tsx +71 -72
  42. package/src/registry/ui/calendar.tsx +514 -515
  43. package/src/registry/ui/card.tsx +88 -91
  44. package/src/registry/ui/carousel.tsx +214 -214
  45. package/src/registry/ui/chart.tsx +373 -373
  46. package/src/registry/ui/chatbot.tsx +86 -13
  47. package/src/registry/ui/checkbox.tsx +93 -94
  48. package/src/registry/ui/collapsible.tsx +107 -108
  49. package/src/registry/ui/combobox.tsx +171 -171
  50. package/src/registry/ui/command.tsx +300 -300
  51. package/src/registry/ui/container.tsx +44 -47
  52. package/src/registry/ui/context-menu.tsx +221 -221
  53. package/src/registry/ui/date-picker.tsx +228 -228
  54. package/src/registry/ui/dialog.tsx +269 -270
  55. package/src/registry/ui/drawer.tsx +10 -4
  56. package/src/registry/ui/dropdown-menu.tsx +529 -530
  57. package/src/registry/ui/empty-state.tsx +0 -2
  58. package/src/registry/ui/file-upload.tsx +0 -0
  59. package/src/registry/ui/floating-dock.tsx +0 -0
  60. package/src/registry/ui/form-field.tsx +91 -94
  61. package/src/registry/ui/google-analytics.tsx +38 -0
  62. package/src/registry/ui/google-tag-manager.tsx +64 -0
  63. package/src/registry/ui/hover-card.tsx +223 -223
  64. package/src/registry/ui/image.tsx +144 -147
  65. package/src/registry/ui/input-group.tsx +82 -85
  66. package/src/registry/ui/input.tsx +125 -125
  67. package/src/registry/ui/kbd.tsx +60 -63
  68. package/src/registry/ui/label.tsx +36 -37
  69. package/src/registry/ui/loading-spinner.tsx +108 -111
  70. package/src/registry/ui/map.tsx +0 -0
  71. package/src/registry/ui/marquee.tsx +2 -0
  72. package/src/registry/ui/menubar.tsx +246 -246
  73. package/src/registry/ui/meta-pixel.tsx +46 -0
  74. package/src/registry/ui/microsoft-clarity.tsx +33 -0
  75. package/src/registry/ui/native-select.tsx +49 -52
  76. package/src/registry/ui/otp-input.tsx +163 -155
  77. package/src/registry/ui/pagination.tsx +149 -152
  78. package/src/registry/ui/patterns.tsx +28 -0
  79. package/src/registry/ui/popover.tsx +226 -227
  80. package/src/registry/ui/progress.tsx +51 -52
  81. package/src/registry/ui/radio.tsx +99 -102
  82. package/src/registry/ui/resizable.tsx +314 -314
  83. package/src/registry/ui/scroll-animation.tsx +45 -0
  84. package/src/registry/ui/scroll-area.tsx +121 -122
  85. package/src/registry/ui/scroll-to-top.tsx +0 -0
  86. package/src/registry/ui/search.tsx +162 -150
  87. package/src/registry/ui/select.tsx +292 -293
  88. package/src/registry/ui/separator.tsx +46 -47
  89. package/src/registry/ui/sheet.tsx +6 -3
  90. package/src/registry/ui/sidebar.tsx +628 -628
  91. package/src/registry/ui/skeleton.tsx +26 -29
  92. package/src/registry/ui/slider.tsx +196 -197
  93. package/src/registry/ui/slot.tsx +69 -72
  94. package/src/registry/ui/star-rating.tsx +146 -134
  95. package/src/registry/ui/switch.tsx +72 -73
  96. package/src/registry/ui/table-of-contents.tsx +96 -96
  97. package/src/registry/ui/table.tsx +138 -139
  98. package/src/registry/ui/tabs.tsx +124 -125
  99. package/src/registry/ui/text.tsx +61 -64
  100. package/src/registry/ui/textarea.tsx +41 -42
  101. package/src/registry/ui/theme-switcher.tsx +66 -66
  102. package/src/registry/ui/tiktok-pixel.tsx +36 -0
  103. package/src/registry/ui/toast.tsx +97 -98
  104. package/src/registry/ui/toggle-group.tsx +129 -129
  105. package/src/registry/ui/toggle.tsx +72 -72
  106. package/src/registry/ui/tooltip.tsx +143 -144
  107. package/src/registry/ui/whatsapp.tsx +0 -0
@@ -1,150 +1,147 @@
1
- "use client"
2
-
3
- import * as React from "react"
4
- import { cn } from "@/lib/utils"
5
- import { Slot } from "@/components/ui/slot"
6
-
7
- /**
8
- * Breadcrumb navigation component
9
- *
10
- * @example
11
- * <Breadcrumb>
12
- * <BreadcrumbList>
13
- * <BreadcrumbItem>
14
- * <BreadcrumbLink href="/">Home</BreadcrumbLink>
15
- * </BreadcrumbItem>
16
- * <BreadcrumbSeparator />
17
- * <BreadcrumbItem>
18
- * <BreadcrumbPage>Current Page</BreadcrumbPage>
19
- * </BreadcrumbItem>
20
- * </BreadcrumbList>
21
- * </Breadcrumb>
22
- */
23
-
24
- const Breadcrumb = React.forwardRef<
25
- HTMLElement,
26
- React.HTMLAttributes<HTMLElement>
27
- >(({ ...props }, ref) => (
28
- <nav ref={ref} aria-label="breadcrumb" {...props} />
29
- ))
30
- Breadcrumb.displayName = "Breadcrumb"
31
-
32
- const BreadcrumbList = React.forwardRef<
33
- HTMLOListElement,
34
- React.OlHTMLAttributes<HTMLOListElement>
35
- >(({ className, ...props }, ref) => (
36
- <ol
37
- ref={ref}
38
- className={cn(
39
- "flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground sm:gap-2.5",
40
- className
41
- )}
42
- {...props}
43
- />
44
- ))
45
- BreadcrumbList.displayName = "BreadcrumbList"
46
-
47
- const BreadcrumbItem = React.forwardRef<
48
- HTMLLIElement,
49
- React.LiHTMLAttributes<HTMLLIElement>
50
- >(({ className, ...props }, ref) => (
51
- <li
52
- ref={ref}
53
- className={cn("inline-flex items-center gap-1.5", className)}
54
- {...props}
55
- />
56
- ))
57
- BreadcrumbItem.displayName = "BreadcrumbItem"
58
-
59
- interface BreadcrumbLinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
60
- asChild?: boolean
61
- }
62
-
63
- const BreadcrumbLink = React.forwardRef<HTMLAnchorElement, BreadcrumbLinkProps>(
64
- ({ asChild, className, children, ...props }, ref) => {
65
- const Comp = asChild ? Slot : "a"
66
-
67
- return (
68
- <Comp
69
- ref={ref}
70
- className={cn("transition-colors hover:text-foreground", className)}
71
- {...props}
72
- >
73
- {children}
74
- </Comp>
75
- )
76
- }
77
- )
78
- BreadcrumbLink.displayName = "BreadcrumbLink"
79
-
80
- const BreadcrumbPage = React.forwardRef<
81
- HTMLSpanElement,
82
- React.HTMLAttributes<HTMLSpanElement>
83
- >(({ className, ...props }, ref) => (
84
- <span
85
- ref={ref}
86
- role="link"
87
- aria-disabled="true"
88
- aria-current="page"
89
- className={cn("font-normal text-foreground", className)}
90
- {...props}
91
- />
92
- ))
93
- BreadcrumbPage.displayName = "BreadcrumbPage"
94
-
95
- const BreadcrumbSeparator = ({
96
- children,
97
- className,
98
- ...props
99
- }: React.LiHTMLAttributes<HTMLLIElement>) => (
100
- <li
101
- role="presentation"
102
- aria-hidden="true"
103
- className={cn("[&>svg]:h-3.5 [&>svg]:w-3.5", className)}
104
- {...props}
105
- >
106
- {children || (
107
- <svg
108
- className="h-4 w-4"
109
- fill="none"
110
- viewBox="0 0 24 24"
111
- stroke="currentColor"
112
- strokeWidth={2}
113
- >
114
- <path strokeLinecap="round" strokeLinejoin="round" d="M9 5l7 7-7 7" />
115
- </svg>
116
- )}
117
- </li>
118
- )
119
- BreadcrumbSeparator.displayName = "BreadcrumbSeparator"
120
-
121
- const BreadcrumbEllipsis = ({
122
- className,
123
- ...props
124
- }: React.HTMLAttributes<HTMLSpanElement>) => (
125
- <span
126
- role="presentation"
127
- aria-hidden="true"
128
- className={cn("flex h-9 w-9 items-center justify-center", className)}
129
- {...props}
130
- >
131
- <svg className="h-4 w-4" fill="currentColor" viewBox="0 0 24 24">
132
- <circle cx="12" cy="12" r="1" />
133
- <circle cx="19" cy="12" r="1" />
134
- <circle cx="5" cy="12" r="1" />
135
- </svg>
136
- <span className="sr-only">More</span>
137
- </span>
138
- )
139
- BreadcrumbEllipsis.displayName = "BreadcrumbEllipsis"
140
-
141
- export {
142
- Breadcrumb,
143
- BreadcrumbList,
144
- BreadcrumbItem,
145
- BreadcrumbLink,
146
- BreadcrumbPage,
147
- BreadcrumbSeparator,
148
- BreadcrumbEllipsis,
149
- }
150
-
1
+ import * as React from "react"
2
+ import { cn } from "@/lib/utils"
3
+ import { Slot } from "@/components/ui/slot"
4
+
5
+ /**
6
+ * Breadcrumb navigation component
7
+ *
8
+ * @example
9
+ * <Breadcrumb>
10
+ * <BreadcrumbList>
11
+ * <BreadcrumbItem>
12
+ * <BreadcrumbLink href="/">Home</BreadcrumbLink>
13
+ * </BreadcrumbItem>
14
+ * <BreadcrumbSeparator />
15
+ * <BreadcrumbItem>
16
+ * <BreadcrumbPage>Current Page</BreadcrumbPage>
17
+ * </BreadcrumbItem>
18
+ * </BreadcrumbList>
19
+ * </Breadcrumb>
20
+ */
21
+
22
+ const Breadcrumb = React.forwardRef<
23
+ HTMLElement,
24
+ React.HTMLAttributes<HTMLElement>
25
+ >(({ ...props }, ref) => (
26
+ <nav ref={ref} aria-label="breadcrumb" {...props} />
27
+ ))
28
+ Breadcrumb.displayName = "Breadcrumb"
29
+
30
+ const BreadcrumbList = React.forwardRef<
31
+ HTMLOListElement,
32
+ React.OlHTMLAttributes<HTMLOListElement>
33
+ >(({ className, ...props }, ref) => (
34
+ <ol
35
+ ref={ref}
36
+ className={cn(
37
+ "flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground sm:gap-2.5",
38
+ className
39
+ )}
40
+ {...props}
41
+ />
42
+ ))
43
+ BreadcrumbList.displayName = "BreadcrumbList"
44
+
45
+ const BreadcrumbItem = React.forwardRef<
46
+ HTMLLIElement,
47
+ React.LiHTMLAttributes<HTMLLIElement>
48
+ >(({ className, ...props }, ref) => (
49
+ <li
50
+ ref={ref}
51
+ className={cn("inline-flex items-center gap-1.5", className)}
52
+ {...props}
53
+ />
54
+ ))
55
+ BreadcrumbItem.displayName = "BreadcrumbItem"
56
+
57
+ interface BreadcrumbLinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
58
+ asChild?: boolean
59
+ }
60
+
61
+ const BreadcrumbLink = React.forwardRef<HTMLAnchorElement, BreadcrumbLinkProps>(
62
+ ({ asChild, className, children, ...props }, ref) => {
63
+ const Comp = asChild ? Slot : "a"
64
+
65
+ return (
66
+ <Comp
67
+ ref={ref}
68
+ className={cn("transition-colors hover:text-foreground", className)}
69
+ {...props}
70
+ >
71
+ {children}
72
+ </Comp>
73
+ )
74
+ }
75
+ )
76
+ BreadcrumbLink.displayName = "BreadcrumbLink"
77
+
78
+ const BreadcrumbPage = React.forwardRef<
79
+ HTMLSpanElement,
80
+ React.HTMLAttributes<HTMLSpanElement>
81
+ >(({ className, ...props }, ref) => (
82
+ <span
83
+ ref={ref}
84
+ role="link"
85
+ aria-disabled="true"
86
+ aria-current="page"
87
+ className={cn("font-normal text-foreground", className)}
88
+ {...props}
89
+ />
90
+ ))
91
+ BreadcrumbPage.displayName = "BreadcrumbPage"
92
+
93
+ const BreadcrumbSeparator = ({
94
+ children,
95
+ className,
96
+ ...props
97
+ }: React.LiHTMLAttributes<HTMLLIElement>) => (
98
+ <li
99
+ role="presentation"
100
+ aria-hidden="true"
101
+ className={cn("[&>svg]:h-3.5 [&>svg]:w-3.5", className)}
102
+ {...props}
103
+ >
104
+ {children || (
105
+ <svg
106
+ className="h-4 w-4"
107
+ fill="none"
108
+ viewBox="0 0 24 24"
109
+ stroke="currentColor"
110
+ strokeWidth={2}
111
+ >
112
+ <path strokeLinecap="round" strokeLinejoin="round" d="M9 5l7 7-7 7" />
113
+ </svg>
114
+ )}
115
+ </li>
116
+ )
117
+ BreadcrumbSeparator.displayName = "BreadcrumbSeparator"
118
+
119
+ const BreadcrumbEllipsis = ({
120
+ className,
121
+ ...props
122
+ }: React.HTMLAttributes<HTMLSpanElement>) => (
123
+ <span
124
+ role="presentation"
125
+ aria-hidden="true"
126
+ className={cn("flex h-9 w-9 items-center justify-center", className)}
127
+ {...props}
128
+ >
129
+ <svg className="h-4 w-4" fill="currentColor" viewBox="0 0 24 24">
130
+ <circle cx="12" cy="12" r="1" />
131
+ <circle cx="19" cy="12" r="1" />
132
+ <circle cx="5" cy="12" r="1" />
133
+ </svg>
134
+ <span className="sr-only">More</span>
135
+ </span>
136
+ )
137
+ BreadcrumbEllipsis.displayName = "BreadcrumbEllipsis"
138
+
139
+ export {
140
+ Breadcrumb,
141
+ BreadcrumbList,
142
+ BreadcrumbItem,
143
+ BreadcrumbLink,
144
+ BreadcrumbPage,
145
+ BreadcrumbSeparator,
146
+ BreadcrumbEllipsis,
147
+ }
@@ -1,67 +1,64 @@
1
- "use client"
2
-
3
- import * as React from "react"
4
- import { cva, type VariantProps } from "class-variance-authority"
5
- import { cn } from "@/lib/utils"
6
-
7
- const buttonGroupVariants = cva("inline-flex", {
8
- variants: {
9
- orientation: {
10
- horizontal: "flex-row",
11
- vertical: "flex-col",
12
- },
13
- attached: {
14
- true: "",
15
- false: "gap-2",
16
- },
17
- },
18
- compoundVariants: [
19
- {
20
- orientation: "horizontal",
21
- attached: true,
22
- className:
23
- "[&>*:not(:first-child):not(:last-child)]:rounded-none [&>*:first-child]:rounded-r-none [&>*:last-child]:rounded-l-none [&>*:not(:first-child)]:-ml-px",
24
- },
25
- {
26
- orientation: "vertical",
27
- attached: true,
28
- className:
29
- "[&>*:not(:first-child):not(:last-child)]:rounded-none [&>*:first-child]:rounded-b-none [&>*:last-child]:rounded-t-none [&>*:not(:first-child)]:-mt-px",
30
- },
31
- ],
32
- defaultVariants: {
33
- orientation: "horizontal",
34
- attached: true,
35
- },
36
- })
37
-
38
- interface ButtonGroupProps
39
- extends React.HTMLAttributes<HTMLDivElement>,
40
- VariantProps<typeof buttonGroupVariants> { }
41
-
42
- /**
43
- * ButtonGroup to group buttons together
44
- *
45
- * @example
46
- * <ButtonGroup>
47
- * <Button>Left</Button>
48
- * <Button>Center</Button>
49
- * <Button>Right</Button>
50
- * </ButtonGroup>
51
- */
52
- const ButtonGroup = React.forwardRef<HTMLDivElement, ButtonGroupProps>(
53
- ({ className, orientation, attached, ...props }, ref) => {
54
- return (
55
- <div
56
- ref={ref}
57
- role="group"
58
- className={cn(buttonGroupVariants({ orientation, attached }), className)}
59
- {...props}
60
- />
61
- )
62
- }
63
- )
64
- ButtonGroup.displayName = "ButtonGroup"
65
-
66
- export { ButtonGroup, buttonGroupVariants }
67
-
1
+ import * as React from "react"
2
+ import { cva, type VariantProps } from "class-variance-authority"
3
+ import { cn } from "@/lib/utils"
4
+
5
+ const buttonGroupVariants = cva("inline-flex", {
6
+ variants: {
7
+ orientation: {
8
+ horizontal: "flex-row",
9
+ vertical: "flex-col",
10
+ },
11
+ attached: {
12
+ true: "",
13
+ false: "gap-2",
14
+ },
15
+ },
16
+ compoundVariants: [
17
+ {
18
+ orientation: "horizontal",
19
+ attached: true,
20
+ className:
21
+ "[&>*:not(:first-child):not(:last-child)]:rounded-none [&>*:first-child]:rounded-r-none [&>*:last-child]:rounded-l-none [&>*:not(:first-child)]:-ml-px",
22
+ },
23
+ {
24
+ orientation: "vertical",
25
+ attached: true,
26
+ className:
27
+ "[&>*:not(:first-child):not(:last-child)]:rounded-none [&>*:first-child]:rounded-b-none [&>*:last-child]:rounded-t-none [&>*:not(:first-child)]:-mt-px",
28
+ },
29
+ ],
30
+ defaultVariants: {
31
+ orientation: "horizontal",
32
+ attached: true,
33
+ },
34
+ })
35
+
36
+ interface ButtonGroupProps
37
+ extends React.HTMLAttributes<HTMLDivElement>,
38
+ VariantProps<typeof buttonGroupVariants> { }
39
+
40
+ /**
41
+ * ButtonGroup to group buttons together
42
+ *
43
+ * @example
44
+ * <ButtonGroup>
45
+ * <Button>Left</Button>
46
+ * <Button>Center</Button>
47
+ * <Button>Right</Button>
48
+ * </ButtonGroup>
49
+ */
50
+ const ButtonGroup = React.forwardRef<HTMLDivElement, ButtonGroupProps>(
51
+ ({ className, orientation, attached, ...props }, ref) => {
52
+ return (
53
+ <div
54
+ ref={ref}
55
+ role="group"
56
+ className={cn(buttonGroupVariants({ orientation, attached }), className)}
57
+ {...props}
58
+ />
59
+ )
60
+ }
61
+ )
62
+ ButtonGroup.displayName = "ButtonGroup"
63
+
64
+ export { ButtonGroup, buttonGroupVariants }
@@ -1,72 +1,71 @@
1
- "use client"
2
-
3
- import * as React from "react"
4
- import { cva, type VariantProps } from "class-variance-authority"
5
- import { cn } from "@/lib/utils"
6
-
7
- const buttonVariants = cva(
8
- "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 cursor-pointer",
9
- {
10
- variants: {
11
- variant: {
12
- default:
13
- "bg-primary text-primary-foreground shadow hover:bg-primary/90",
14
- destructive:
15
- "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
16
- outline:
17
- "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
18
- secondary:
19
- "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
20
- ghost: "hover:bg-accent hover:text-accent-foreground",
21
- link: "text-primary underline-offset-4 hover:underline",
22
- },
23
- size: {
24
- default: "h-9 px-4 py-2",
25
- sm: "h-8 rounded-md px-3 text-xs",
26
- lg: "h-10 rounded-md px-8",
27
- icon: "h-9 w-9",
28
- },
29
- },
30
- defaultVariants: {
31
- variant: "default",
32
- size: "default",
33
- },
34
- }
35
- )
36
-
37
- interface ButtonProps
38
- extends React.ButtonHTMLAttributes<HTMLButtonElement>,
39
- VariantProps<typeof buttonVariants> {
40
- asChild?: boolean
41
- }
42
-
43
- /**
44
- * Button component
45
- *
46
- * @example
47
- * // Default button
48
- * <Button variant="outline">Click me</Button>
49
- *
50
- * // With loading state
51
- * <Button disabled>
52
- * <LoadingSpinner /> Processing...
53
- * </Button>
54
- */
55
- import { Slot } from "@/components/ui/slot"
56
-
57
- const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
58
- ({ className, variant, size, asChild = false, ...props }, ref) => {
59
- const Comp = asChild ? Slot : "button"
60
- return (
61
- <Comp
62
- className={cn(buttonVariants({ variant, size }), className)}
63
- ref={ref}
64
- {...props}
65
- />
66
- )
67
- }
68
- )
69
- Button.displayName = "Button"
70
-
71
- export { Button, buttonVariants }
72
-
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { cva, type VariantProps } from "class-variance-authority"
5
+ import { cn } from "@/lib/utils"
6
+
7
+ const buttonVariants = cva(
8
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 cursor-pointer",
9
+ {
10
+ variants: {
11
+ variant: {
12
+ default:
13
+ "bg-primary text-primary-foreground shadow hover:bg-primary/90",
14
+ destructive:
15
+ "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
16
+ outline:
17
+ "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
18
+ secondary:
19
+ "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
20
+ ghost: "hover:bg-accent hover:text-accent-foreground",
21
+ link: "text-primary underline-offset-4 hover:underline",
22
+ },
23
+ size: {
24
+ default: "h-9 px-4 py-2",
25
+ sm: "h-8 rounded-md px-3 text-xs",
26
+ lg: "h-10 rounded-md px-8",
27
+ icon: "h-9 w-9",
28
+ },
29
+ },
30
+ defaultVariants: {
31
+ variant: "default",
32
+ size: "default",
33
+ },
34
+ }
35
+ )
36
+
37
+ interface ButtonProps
38
+ extends React.ButtonHTMLAttributes<HTMLButtonElement>,
39
+ VariantProps<typeof buttonVariants> {
40
+ asChild?: boolean
41
+ }
42
+
43
+ /**
44
+ * Button component
45
+ *
46
+ * @example
47
+ * // Default button
48
+ * <Button variant="outline">Click me</Button>
49
+ *
50
+ * // With loading state
51
+ * <Button disabled>
52
+ * <LoadingSpinner /> Processing...
53
+ * </Button>
54
+ */
55
+ import { Slot } from "@/components/ui/slot"
56
+
57
+ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
58
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
59
+ const Comp = asChild ? Slot : "button"
60
+ return (
61
+ <Comp
62
+ className={cn(buttonVariants({ variant, size }), className)}
63
+ ref={ref}
64
+ {...props}
65
+ />
66
+ )
67
+ }
68
+ )
69
+ Button.displayName = "Button"
70
+
71
+ export { Button, buttonVariants }