@authdog/react-elements 0.0.40 → 0.0.43
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/.eslintrc.js +1 -1
- package/.storybook/main.ts +21 -0
- package/.storybook/preview.ts +17 -0
- package/.storybook/vitest.setup.ts +7 -0
- package/.turbo/turbo-build.log +48 -44
- package/CHANGELOG.md +19 -0
- package/dist/components/ui/alert.js.map +1 -1
- package/dist/components/ui/alert.mjs.map +1 -1
- package/dist/components/ui/avatar.js.map +1 -1
- package/dist/components/ui/avatar.mjs.map +1 -1
- package/dist/components/ui/badge.js.map +1 -1
- package/dist/components/ui/badge.mjs.map +1 -1
- package/dist/components/ui/card.js.map +1 -1
- package/dist/components/ui/card.mjs.map +1 -1
- package/dist/components/ui/dropdown-menu.js +1 -1
- package/dist/components/ui/dropdown-menu.js.map +1 -1
- package/dist/components/ui/dropdown-menu.mjs +1 -1
- package/dist/components/ui/dropdown-menu.mjs.map +1 -1
- package/dist/components/ui/input.js.map +1 -1
- package/dist/components/ui/input.mjs.map +1 -1
- package/dist/components/ui/label.js.map +1 -1
- package/dist/components/ui/label.mjs.map +1 -1
- package/dist/components/ui/separator.js.map +1 -1
- package/dist/components/ui/separator.mjs.map +1 -1
- package/dist/components/ui/sheet.js.map +1 -1
- package/dist/components/ui/sheet.mjs.map +1 -1
- package/dist/components/ui/theme-toggle.js +3 -0
- package/dist/components/ui/theme-toggle.js.map +1 -0
- package/dist/components/ui/theme-toggle.mjs +3 -0
- package/dist/components/ui/theme-toggle.mjs.map +1 -0
- package/dist/index.d.mts +5 -2
- package/dist/index.d.ts +5 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +314 -20
- package/package.json +23 -12
- package/src/components/core/navbar.tsx +145 -112
- package/src/components/core/user-dropdown.tsx +22 -4
- package/src/components/icons.tsx +6 -12
- package/src/components/ui/alert.tsx +1 -1
- package/src/components/ui/avatar.tsx +1 -1
- package/src/components/ui/badge.tsx +1 -1
- package/src/components/ui/card.tsx +1 -1
- package/src/components/ui/dropdown-menu.tsx +198 -197
- package/src/components/ui/input.tsx +1 -1
- package/src/components/ui/label.tsx +1 -1
- package/src/components/ui/separator.tsx +1 -1
- package/src/components/ui/sheet.tsx +1 -1
- package/src/components/ui/theme-toggle.tsx +55 -0
- package/src/stories/core/Navbar.stories.tsx +45 -0
- package/src/stories/core/PlaceholderAlert.stories.tsx +23 -0
- package/src/stories/core/UserDropdown.stories.tsx +56 -0
- package/src/stories/core/UserProfile.stories.tsx +47 -0
- package/src/stories/flow/LoginForm.stories.tsx +20 -0
- package/src/stories/flow/TotpValidator.stories.tsx +23 -0
- package/src/stories/showcase/Landing.stories.tsx +376 -0
- package/src/stories/ui/Button.stories.tsx +45 -0
- package/vitest.config.ts +39 -0
- package/vitest.shims.d.ts +1 -0
- package/wrangler.prod.toml +4 -0
- package/ladle.config.mjs +0 -21
- package/src/main.tsx +0 -9
- package/src/preview.tsx +0 -7
- package/src/stories/Button._stories.tsx +0 -28
- package/src/stories/LoginForm.stories.tsx +0 -29
- package/src/stories/Navbar._stories.tsx +0 -66
- package/src/stories/PlaceholderAlert._stories.tsx +0 -13
- package/src/stories/TotpValidator.stories.tsx +0 -16
- package/src/stories/UserDropdown.stories.tsx +0 -34
- package/src/stories/UserProfile.stories.tsx +0 -46
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
} from "../../components/ui/dropdown-menu";
|
|
23
23
|
import { Sheet, SheetContent, SheetTrigger } from "../../components/ui/sheet";
|
|
24
24
|
import { IconWrapper } from "../icons";
|
|
25
|
+
import { ThemeToggle } from "../ui/theme-toggle";
|
|
25
26
|
|
|
26
27
|
interface NavItem {
|
|
27
28
|
title: string;
|
|
@@ -34,6 +35,7 @@ interface NavbarProps {
|
|
|
34
35
|
children?: React.ReactNode;
|
|
35
36
|
className?: string;
|
|
36
37
|
logoText?: string;
|
|
38
|
+
logoSrc?: string;
|
|
37
39
|
isLoading?: boolean;
|
|
38
40
|
user?: any;
|
|
39
41
|
onNavigateHome?: () => void;
|
|
@@ -52,6 +54,7 @@ export function Navbar({
|
|
|
52
54
|
children,
|
|
53
55
|
className,
|
|
54
56
|
logoText = "ACME Corp",
|
|
57
|
+
logoSrc,
|
|
55
58
|
user = {
|
|
56
59
|
name: "John Doe",
|
|
57
60
|
email: "john@example.com",
|
|
@@ -66,22 +69,54 @@ export function Navbar({
|
|
|
66
69
|
environmentId = "58be35b0-708f-49f6-84f0-6695d307d997",
|
|
67
70
|
}: NavbarProps) {
|
|
68
71
|
const [open, setOpen] = useState(false);
|
|
72
|
+
const [logoFailed, setLogoFailed] = useState(false);
|
|
69
73
|
const isAuthenticated =
|
|
70
74
|
user !== null &&
|
|
71
75
|
user !== undefined &&
|
|
72
76
|
user.id !== null &&
|
|
73
77
|
user.id !== undefined;
|
|
78
|
+
|
|
74
79
|
return (
|
|
75
|
-
<header
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
+
<header
|
|
81
|
+
className={cn(
|
|
82
|
+
"sticky top-0 z-40 w-full border-b bg-background/80 backdrop-blur supports-[backdrop-filter]:bg-background/60",
|
|
83
|
+
className,
|
|
84
|
+
)}
|
|
85
|
+
>
|
|
86
|
+
<div
|
|
87
|
+
className={cn(
|
|
88
|
+
"flex h-16 items-center justify-between px-4 md:px-6",
|
|
89
|
+
"w-full lg:max-w-[80vw] mx-auto",
|
|
90
|
+
)}
|
|
91
|
+
>
|
|
92
|
+
<div className="flex items-center gap-3 md:gap-4">
|
|
93
|
+
<button
|
|
94
|
+
type="button"
|
|
80
95
|
onClick={onNavigateHome}
|
|
96
|
+
className={cn(
|
|
97
|
+
"group inline-flex items-center gap-2 md:gap-3 rounded-md px-1 py-1 text-left",
|
|
98
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
99
|
+
)}
|
|
100
|
+
aria-label="Go to homepage"
|
|
81
101
|
>
|
|
82
|
-
{
|
|
83
|
-
|
|
84
|
-
|
|
102
|
+
{logoSrc && !logoFailed && (
|
|
103
|
+
<span className="inline-flex h-8 w-8 items-center justify-center overflow-hidden rounded-md bg-muted/80 ring-1 ring-border">
|
|
104
|
+
<img
|
|
105
|
+
src={logoSrc}
|
|
106
|
+
alt={logoText}
|
|
107
|
+
className="h-7 w-7 object-contain"
|
|
108
|
+
onError={() => setLogoFailed(true)}
|
|
109
|
+
/>
|
|
110
|
+
</span>
|
|
111
|
+
)}
|
|
112
|
+
<span className="text-base font-semibold tracking-tight md:text-lg group-hover:text-primary">
|
|
113
|
+
{logoText}
|
|
114
|
+
</span>
|
|
115
|
+
</button>
|
|
116
|
+
{children}
|
|
117
|
+
</div>
|
|
118
|
+
<div className="flex flex-1 items-center justify-end gap-6">
|
|
119
|
+
<nav className="hidden md:flex items-center gap-6">
|
|
85
120
|
{items?.map((item, index) => (
|
|
86
121
|
<span
|
|
87
122
|
key={index}
|
|
@@ -99,119 +134,117 @@ export function Navbar({
|
|
|
99
134
|
</span>
|
|
100
135
|
))}
|
|
101
136
|
</nav>
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
{isAuthenticated ? (
|
|
107
|
-
<DropdownMenu>
|
|
108
|
-
<DropdownMenuTrigger asChild>
|
|
137
|
+
<div className="flex items-center gap-3">
|
|
138
|
+
<Sheet open={open} onOpenChange={setOpen}>
|
|
139
|
+
<SheetTrigger asChild>
|
|
109
140
|
<Button
|
|
110
141
|
variant="ghost"
|
|
111
|
-
|
|
112
|
-
|
|
142
|
+
size="icon"
|
|
143
|
+
className="md:hidden"
|
|
144
|
+
aria-label="Open Menu"
|
|
113
145
|
>
|
|
114
|
-
<
|
|
115
|
-
{isLoading ? (
|
|
116
|
-
<div className="h-8 w-8 animate-pulse bg-muted rounded-full" />
|
|
117
|
-
) : (
|
|
118
|
-
<>
|
|
119
|
-
<AvatarImage
|
|
120
|
-
src={user.photos?.[0]?.value || "/placeholder.svg"}
|
|
121
|
-
alt={user.displayName}
|
|
122
|
-
/>
|
|
123
|
-
<AvatarFallback>
|
|
124
|
-
{user.displayName?.charAt(0)}
|
|
125
|
-
</AvatarFallback>
|
|
126
|
-
</>
|
|
127
|
-
)}
|
|
128
|
-
</Avatar>
|
|
146
|
+
<IconWrapper Icon={Menu} />
|
|
129
147
|
</Button>
|
|
130
|
-
</
|
|
131
|
-
<
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
<
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
148
|
+
</SheetTrigger>
|
|
149
|
+
<SheetContent side="left" className="pr-0">
|
|
150
|
+
<nav className="grid gap-2 py-6">
|
|
151
|
+
{items?.map((item, index) => (
|
|
152
|
+
<a
|
|
153
|
+
key={index}
|
|
154
|
+
href={item.href}
|
|
155
|
+
className={cn(
|
|
156
|
+
"flex w-full items-center rounded-md px-3 py-2 text-sm font-medium hover:bg-accent",
|
|
157
|
+
item.disabled && "cursor-not-allowed opacity-80",
|
|
158
|
+
)}
|
|
159
|
+
onClick={() => setOpen(false)}
|
|
160
|
+
>
|
|
161
|
+
{item.title}
|
|
162
|
+
</a>
|
|
163
|
+
))}
|
|
164
|
+
</nav>
|
|
165
|
+
</SheetContent>
|
|
166
|
+
</Sheet>
|
|
167
|
+
<ThemeToggle />
|
|
168
|
+
{isAuthenticated ? (
|
|
169
|
+
<DropdownMenu>
|
|
170
|
+
<DropdownMenuTrigger asChild>
|
|
171
|
+
<Button
|
|
172
|
+
variant="ghost"
|
|
173
|
+
className="relative h-8 w-8 rounded-full"
|
|
174
|
+
disabled={isLoading}
|
|
175
|
+
>
|
|
176
|
+
<Avatar className="h-8 w-8">
|
|
177
|
+
{isLoading ? (
|
|
178
|
+
<div className="h-8 w-8 animate-pulse bg-muted rounded-full" />
|
|
179
|
+
) : (
|
|
180
|
+
<>
|
|
181
|
+
<AvatarImage
|
|
182
|
+
src={user.photos?.[0]?.value || "/placeholder.svg"}
|
|
183
|
+
alt={user.displayName}
|
|
184
|
+
/>
|
|
185
|
+
<AvatarFallback>
|
|
186
|
+
{user.displayName?.charAt(0)}
|
|
187
|
+
</AvatarFallback>
|
|
188
|
+
</>
|
|
189
|
+
)}
|
|
190
|
+
</Avatar>
|
|
191
|
+
</Button>
|
|
192
|
+
</DropdownMenuTrigger>
|
|
193
|
+
<DropdownMenuContent className="w-56" align="end" forceMount>
|
|
194
|
+
{isLoading ? (
|
|
195
|
+
<div className="p-4">
|
|
196
|
+
<div className="h-4 w-3/4 animate-pulse bg-muted rounded mb-2" />
|
|
197
|
+
<div className="h-3 w-1/2 animate-pulse bg-muted rounded" />
|
|
198
|
+
</div>
|
|
199
|
+
) : (
|
|
200
|
+
<>
|
|
201
|
+
<DropdownMenuLabel className="font-normal">
|
|
202
|
+
<div className="flex flex-col space-y-1">
|
|
203
|
+
<p className="text-sm font-medium leading-none">
|
|
204
|
+
{user.displayName}
|
|
205
|
+
</p>
|
|
206
|
+
<p className="text-xs leading-none text-muted-foreground">
|
|
207
|
+
{user.emails?.[0]?.value}
|
|
208
|
+
</p>
|
|
209
|
+
</div>
|
|
210
|
+
</DropdownMenuLabel>
|
|
211
|
+
<DropdownMenuSeparator />
|
|
212
|
+
<DropdownMenuGroup>
|
|
213
|
+
<DropdownMenuItem onClick={onProfileSelected}>
|
|
214
|
+
<IconWrapper Icon={User} />
|
|
215
|
+
<span>Profile</span>
|
|
216
|
+
</DropdownMenuItem>
|
|
217
|
+
</DropdownMenuGroup>
|
|
218
|
+
<DropdownMenuSeparator />
|
|
219
|
+
<DropdownMenuItem onClick={onLogout}>
|
|
220
|
+
<IconWrapper Icon={LogOut} />
|
|
221
|
+
<span>Log out</span>
|
|
154
222
|
</DropdownMenuItem>
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
variant="default"
|
|
168
|
-
aria-label="Sign in"
|
|
169
|
-
onClick={() => {
|
|
170
|
-
if (!environmentId) {
|
|
171
|
-
throw new Error("Environment ID is required");
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
if (!identityHost) {
|
|
175
|
-
throw new Error("Identity Host is required");
|
|
176
|
-
}
|
|
223
|
+
</>
|
|
224
|
+
)}
|
|
225
|
+
</DropdownMenuContent>
|
|
226
|
+
</DropdownMenu>
|
|
227
|
+
) : (
|
|
228
|
+
<Button
|
|
229
|
+
variant="default"
|
|
230
|
+
aria-label="Sign in"
|
|
231
|
+
onClick={() => {
|
|
232
|
+
if (!environmentId) {
|
|
233
|
+
throw new Error("Environment ID is required");
|
|
234
|
+
}
|
|
177
235
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
>
|
|
182
|
-
Sign in
|
|
183
|
-
</Button>
|
|
184
|
-
)}
|
|
236
|
+
if (!identityHost) {
|
|
237
|
+
throw new Error("Identity Host is required");
|
|
238
|
+
}
|
|
185
239
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
variant="ghost"
|
|
190
|
-
size="icon"
|
|
191
|
-
className="md:hidden"
|
|
192
|
-
aria-label="Open Menu"
|
|
240
|
+
const signinUrl = `${identityHost}/signin/${environmentId}`;
|
|
241
|
+
window.open(signinUrl, "_blank");
|
|
242
|
+
}}
|
|
193
243
|
>
|
|
194
|
-
|
|
244
|
+
Sign in
|
|
195
245
|
</Button>
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
<nav className="grid gap-2 py-6">
|
|
199
|
-
{items?.map((item, index) => (
|
|
200
|
-
<a
|
|
201
|
-
key={index}
|
|
202
|
-
href={item.href}
|
|
203
|
-
className={cn(
|
|
204
|
-
"flex w-full items-center rounded-md px-3 py-2 text-sm font-medium hover:bg-accent",
|
|
205
|
-
item.disabled && "cursor-not-allowed opacity-80",
|
|
206
|
-
)}
|
|
207
|
-
onClick={() => setOpen(false)}
|
|
208
|
-
>
|
|
209
|
-
{item.title}
|
|
210
|
-
</a>
|
|
211
|
-
))}
|
|
212
|
-
</nav>
|
|
213
|
-
</SheetContent>
|
|
214
|
-
</Sheet>
|
|
246
|
+
)}
|
|
247
|
+
</div>
|
|
215
248
|
</div>
|
|
216
249
|
</div>
|
|
217
250
|
</header>
|
|
@@ -12,8 +12,9 @@ import {
|
|
|
12
12
|
AvatarFallback,
|
|
13
13
|
AvatarImage,
|
|
14
14
|
} from "../../components/ui/avatar";
|
|
15
|
-
import { cn } from "
|
|
15
|
+
import { cn } from "../../lib/utils";
|
|
16
16
|
import { LogOut, Settings, ExternalLink } from "lucide-react";
|
|
17
|
+
import type { ComponentType } from "react";
|
|
17
18
|
|
|
18
19
|
export type UserDropdownLink = {
|
|
19
20
|
label: string;
|
|
@@ -40,6 +41,8 @@ export interface UserDropdownProps {
|
|
|
40
41
|
align?: "start" | "center" | "end";
|
|
41
42
|
sideOffset?: number;
|
|
42
43
|
modal?: boolean;
|
|
44
|
+
triggerAsChild?: boolean;
|
|
45
|
+
triggerWrapperClassName?: string;
|
|
43
46
|
}
|
|
44
47
|
|
|
45
48
|
const getInitials = (name?: string) => {
|
|
@@ -63,6 +66,8 @@ export const UserDropdown = ({
|
|
|
63
66
|
align = "end",
|
|
64
67
|
sideOffset = 8,
|
|
65
68
|
modal = false,
|
|
69
|
+
triggerAsChild = false,
|
|
70
|
+
triggerWrapperClassName,
|
|
66
71
|
}: UserDropdownProps) => {
|
|
67
72
|
const primaryEmail = user?.emails?.[0]?.value || user?.email || "";
|
|
68
73
|
const displayName = user?.displayName || user?.name || "";
|
|
@@ -80,10 +85,23 @@ export const UserDropdown = ({
|
|
|
80
85
|
};
|
|
81
86
|
|
|
82
87
|
const IconExternal = ExternalLink as any;
|
|
88
|
+
const SettingsIcon = Settings as ComponentType<any>;
|
|
89
|
+
const LogOutIcon = LogOut as ComponentType<any>;
|
|
83
90
|
|
|
84
91
|
return (
|
|
85
92
|
<DropdownMenu modal={modal}>
|
|
86
|
-
|
|
93
|
+
{triggerAsChild ? (
|
|
94
|
+
<DropdownMenuTrigger asChild>{trigger}</DropdownMenuTrigger>
|
|
95
|
+
) : (
|
|
96
|
+
<DropdownMenuTrigger
|
|
97
|
+
className={cn(
|
|
98
|
+
"inline-flex items-center justify-center bg-transparent p-0 border-0 outline-none focus-visible:outline-none",
|
|
99
|
+
triggerWrapperClassName,
|
|
100
|
+
)}
|
|
101
|
+
>
|
|
102
|
+
{trigger}
|
|
103
|
+
</DropdownMenuTrigger>
|
|
104
|
+
)}
|
|
87
105
|
<DropdownMenuContent
|
|
88
106
|
align={align}
|
|
89
107
|
side={side}
|
|
@@ -112,7 +130,7 @@ export const UserDropdown = ({
|
|
|
112
130
|
className="cursor-pointer py-2"
|
|
113
131
|
onClick={() => onManageAccount?.()}
|
|
114
132
|
>
|
|
115
|
-
<
|
|
133
|
+
<SettingsIcon className="mr-2 h-4 w-4" />
|
|
116
134
|
<span>Manage account</span>
|
|
117
135
|
</DropdownMenuItem>
|
|
118
136
|
{links.map((item, idx) => {
|
|
@@ -133,7 +151,7 @@ export const UserDropdown = ({
|
|
|
133
151
|
className="cursor-pointer py-2 rounded-md font-semibold text-red-600 dark:text-red-300 hover:bg-red-50 hover:text-red-700 focus:bg-red-50 focus:text-red-700 dark:hover:bg-red-500/20 dark:focus:bg-red-500/25 dark:hover:text-red-100 dark:focus:text-red-100 border border-transparent dark:border-red-500/30 ring-0 focus-visible:ring-2 focus-visible:ring-red-400/40 dark:focus-visible:ring-red-400/40"
|
|
134
152
|
onClick={() => onSignout?.()}
|
|
135
153
|
>
|
|
136
|
-
<
|
|
154
|
+
<LogOutIcon className="mr-2 h-4 w-4 text-red-600 dark:text-red-300" />
|
|
137
155
|
<span>Sign out</span>
|
|
138
156
|
</DropdownMenuItem>
|
|
139
157
|
</DropdownMenuContent>
|
package/src/components/icons.tsx
CHANGED
|
@@ -6,26 +6,20 @@ const iconProps: LucideProps = {
|
|
|
6
6
|
"aria-hidden": "true",
|
|
7
7
|
};
|
|
8
8
|
|
|
9
|
-
export const
|
|
9
|
+
export const IconWrapper = ({ Icon }: { Icon: any }) => {
|
|
10
10
|
const [isMounted, setIsMounted] = useState(false);
|
|
11
11
|
|
|
12
12
|
useEffect(() => {
|
|
13
13
|
setIsMounted(true);
|
|
14
14
|
}, []);
|
|
15
15
|
|
|
16
|
-
if (!isMounted) {
|
|
17
|
-
return <span className="mr-2 h-4 w-4" aria-hidden="true" />;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return <Icon {...iconProps} />;
|
|
21
|
-
}) as React.FC<{
|
|
22
|
-
Icon: any;
|
|
23
|
-
}>;
|
|
24
|
-
|
|
25
|
-
export const IconWrapper = ({ Icon }: { Icon: any }) => {
|
|
26
16
|
return (
|
|
27
17
|
<span className="inline-flex items-center justify-center">
|
|
28
|
-
{
|
|
18
|
+
{!isMounted ? (
|
|
19
|
+
<span className="mr-2 h-4 w-4" aria-hidden="true" />
|
|
20
|
+
) : (
|
|
21
|
+
<Icon {...iconProps} />
|
|
22
|
+
)}
|
|
29
23
|
</span>
|
|
30
24
|
);
|
|
31
25
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
3
3
|
|
|
4
|
-
import { cn } from "
|
|
4
|
+
import { cn } from "../../lib/utils";
|
|
5
5
|
|
|
6
6
|
const alertVariants = cva(
|
|
7
7
|
"relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current",
|
|
@@ -2,7 +2,7 @@ import * as React from "react";
|
|
|
2
2
|
import { Slot } from "@radix-ui/react-slot";
|
|
3
3
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
4
4
|
|
|
5
|
-
import { cn } from "
|
|
5
|
+
import { cn } from "../../lib/utils";
|
|
6
6
|
|
|
7
7
|
const badgeVariants = cva(
|
|
8
8
|
"inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
|