@oussemasahbeni/keycloakify-login-shadcn 250004.0.8 → 250004.0.10
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 +317 -0
- package/keycloak-theme/components/ui/alert.tsx +69 -61
- package/keycloak-theme/components/ui/button.tsx +44 -38
- package/keycloak-theme/components/ui/card.tsx +60 -45
- package/keycloak-theme/components/ui/checkbox.tsx +24 -22
- package/keycloak-theme/components/ui/dropdown-menu.tsx +231 -176
- package/keycloak-theme/components/ui/field.tsx +51 -48
- package/keycloak-theme/components/ui/input-otp.tsx +56 -49
- package/keycloak-theme/components/ui/input.tsx +18 -21
- package/keycloak-theme/components/ui/label.tsx +19 -20
- package/keycloak-theme/components/ui/radio-group.tsx +27 -25
- package/keycloak-theme/components/ui/select.tsx +160 -121
- package/keycloak-theme/components/ui/separator.tsx +23 -23
- package/keycloak-theme/components/ui/tooltip.tsx +54 -24
- package/keycloak-theme/login/KcPage.tsx +0 -1
- package/keycloak-theme/login/components/Template/Template.tsx +2 -2
- package/keycloak-theme/login/components/Template/useInitializeTemplate.ts +3 -19
- package/keycloak-theme/login/index.css +3 -20
- package/keycloak-theme/login/pages/login/Form.tsx +49 -51
- package/keycloak-theme/login/pages/login/SocialProviders.tsx +9 -4
- package/keycloak-theme/login/pages/login/providers/github.svg +4 -3
- package/keycloak-theme/login/pages/login/providers/x.svg +4 -3
- package/keycloak-theme/login/pages/login/useProviderLogos.tsx +2 -3
- package/keycloak-theme/login/styleLevelCustomization.tsx +1 -0
- package/keycloak-theme/public/keycloak-theme/login/js/authChecker.js +95 -0
- package/keycloak-theme/public/keycloak-theme/login/js/passkeysConditionalAuth.js +86 -0
- package/keycloak-theme/public/keycloak-theme/login/js/rfc4648.js +185 -0
- package/keycloak-theme/public/keycloak-theme/login/js/webauthnAuthenticate.js +113 -0
- package/keycloak-theme/public/keycloak-theme/login/js/webauthnRegister.js +153 -0
- package/package.json +1 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { cva, type VariantProps } from "class-variance-authority"
|
|
2
|
-
import { useMemo } from "react"
|
|
1
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
2
|
+
import { useMemo } from "react"
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
4
|
+
import { Label } from "@/components/ui/label"
|
|
5
|
+
import { Separator } from "@/components/ui/separator"
|
|
6
|
+
import { cn } from '../lib/utils'
|
|
7
7
|
|
|
8
8
|
function FieldSet({ className, ...props }: React.ComponentProps<"fieldset">) {
|
|
9
9
|
return (
|
|
@@ -16,7 +16,7 @@ function FieldSet({ className, ...props }: React.ComponentProps<"fieldset">) {
|
|
|
16
16
|
)}
|
|
17
17
|
{...props}
|
|
18
18
|
/>
|
|
19
|
-
)
|
|
19
|
+
)
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
function FieldLegend({
|
|
@@ -36,7 +36,7 @@ function FieldLegend({
|
|
|
36
36
|
)}
|
|
37
37
|
{...props}
|
|
38
38
|
/>
|
|
39
|
-
)
|
|
39
|
+
)
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
function FieldGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
@@ -49,11 +49,11 @@ function FieldGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
|
49
49
|
)}
|
|
50
50
|
{...props}
|
|
51
51
|
/>
|
|
52
|
-
)
|
|
52
|
+
)
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
const fieldVariants = cva(
|
|
56
|
-
"group/field
|
|
56
|
+
"group/field flex w-full gap-2 ",
|
|
57
57
|
{
|
|
58
58
|
variants: {
|
|
59
59
|
orientation: {
|
|
@@ -61,20 +61,20 @@ const fieldVariants = cva(
|
|
|
61
61
|
horizontal: [
|
|
62
62
|
"flex-row items-center",
|
|
63
63
|
"[&>[data-slot=field-label]]:flex-auto",
|
|
64
|
-
"has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px
|
|
64
|
+
"has-[>[data-slot=field-content]]:items-start has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
|
|
65
65
|
],
|
|
66
66
|
responsive: [
|
|
67
|
-
"@md/field-group:flex-row @md/field-group:items-center @md/field-group:[&>*]:w-auto
|
|
67
|
+
"flex-col [&>*]:w-full [&>.sr-only]:w-auto @md/field-group:flex-row @md/field-group:items-center @md/field-group:[&>*]:w-auto",
|
|
68
68
|
"@md/field-group:[&>[data-slot=field-label]]:flex-auto",
|
|
69
|
-
"@md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px"
|
|
70
|
-
]
|
|
71
|
-
}
|
|
69
|
+
"@md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
|
|
70
|
+
],
|
|
71
|
+
},
|
|
72
72
|
},
|
|
73
73
|
defaultVariants: {
|
|
74
|
-
orientation: "vertical"
|
|
75
|
-
}
|
|
74
|
+
orientation: "vertical",
|
|
75
|
+
},
|
|
76
76
|
}
|
|
77
|
-
)
|
|
77
|
+
)
|
|
78
78
|
|
|
79
79
|
function Field({
|
|
80
80
|
className,
|
|
@@ -89,7 +89,7 @@ function Field({
|
|
|
89
89
|
className={cn(fieldVariants({ orientation }), className)}
|
|
90
90
|
{...props}
|
|
91
91
|
/>
|
|
92
|
-
)
|
|
92
|
+
)
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
function FieldContent({ className, ...props }: React.ComponentProps<"div">) {
|
|
@@ -102,10 +102,13 @@ function FieldContent({ className, ...props }: React.ComponentProps<"div">) {
|
|
|
102
102
|
)}
|
|
103
103
|
{...props}
|
|
104
104
|
/>
|
|
105
|
-
)
|
|
105
|
+
)
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
function FieldLabel({
|
|
108
|
+
function FieldLabel({
|
|
109
|
+
className,
|
|
110
|
+
...props
|
|
111
|
+
}: React.ComponentProps<typeof Label>) {
|
|
109
112
|
return (
|
|
110
113
|
<Label
|
|
111
114
|
data-slot="field-label"
|
|
@@ -117,7 +120,7 @@ function FieldLabel({ className, ...props }: React.ComponentProps<typeof Label>)
|
|
|
117
120
|
)}
|
|
118
121
|
{...props}
|
|
119
122
|
/>
|
|
120
|
-
)
|
|
123
|
+
)
|
|
121
124
|
}
|
|
122
125
|
|
|
123
126
|
function FieldTitle({ className, ...props }: React.ComponentProps<"div">) {
|
|
@@ -125,12 +128,12 @@ function FieldTitle({ className, ...props }: React.ComponentProps<"div">) {
|
|
|
125
128
|
<div
|
|
126
129
|
data-slot="field-label"
|
|
127
130
|
className={cn(
|
|
128
|
-
"flex w-fit items-center gap-2 text-sm font-medium
|
|
131
|
+
"flex w-fit items-center gap-2 text-sm leading-snug font-medium group-data-[disabled=true]/field:opacity-50",
|
|
129
132
|
className
|
|
130
133
|
)}
|
|
131
134
|
{...props}
|
|
132
135
|
/>
|
|
133
|
-
)
|
|
136
|
+
)
|
|
134
137
|
}
|
|
135
138
|
|
|
136
139
|
function FieldDescription({ className, ...props }: React.ComponentProps<"p">) {
|
|
@@ -138,14 +141,14 @@ function FieldDescription({ className, ...props }: React.ComponentProps<"p">) {
|
|
|
138
141
|
<p
|
|
139
142
|
data-slot="field-description"
|
|
140
143
|
className={cn(
|
|
141
|
-
"text-muted-foreground text-sm
|
|
142
|
-
"nth-last-2:-mt-1
|
|
144
|
+
"text-muted-foreground text-sm leading-normal font-normal group-has-data-[orientation=horizontal]/field:text-balance",
|
|
145
|
+
"last:mt-0 nth-last-2:-mt-1 [[data-variant=legend]+&]:-mt-1.5",
|
|
143
146
|
"[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4",
|
|
144
147
|
className
|
|
145
148
|
)}
|
|
146
149
|
{...props}
|
|
147
150
|
/>
|
|
148
|
-
)
|
|
151
|
+
)
|
|
149
152
|
}
|
|
150
153
|
|
|
151
154
|
function FieldSeparator({
|
|
@@ -153,7 +156,7 @@ function FieldSeparator({
|
|
|
153
156
|
className,
|
|
154
157
|
...props
|
|
155
158
|
}: React.ComponentProps<"div"> & {
|
|
156
|
-
children?: React.ReactNode
|
|
159
|
+
children?: React.ReactNode
|
|
157
160
|
}) {
|
|
158
161
|
return (
|
|
159
162
|
<div
|
|
@@ -175,7 +178,7 @@ function FieldSeparator({
|
|
|
175
178
|
</span>
|
|
176
179
|
)}
|
|
177
180
|
</div>
|
|
178
|
-
)
|
|
181
|
+
)
|
|
179
182
|
}
|
|
180
183
|
|
|
181
184
|
function FieldError({
|
|
@@ -184,33 +187,37 @@ function FieldError({
|
|
|
184
187
|
errors,
|
|
185
188
|
...props
|
|
186
189
|
}: React.ComponentProps<"div"> & {
|
|
187
|
-
errors?: Array<{ message?: string } | undefined
|
|
190
|
+
errors?: Array<{ message?: string } | undefined>
|
|
188
191
|
}) {
|
|
189
192
|
const content = useMemo(() => {
|
|
190
193
|
if (children) {
|
|
191
|
-
return children
|
|
194
|
+
return children
|
|
192
195
|
}
|
|
193
196
|
|
|
194
|
-
if (!errors) {
|
|
195
|
-
return null
|
|
197
|
+
if (!errors?.length) {
|
|
198
|
+
return null
|
|
196
199
|
}
|
|
197
200
|
|
|
198
|
-
|
|
199
|
-
|
|
201
|
+
const uniqueErrors = [
|
|
202
|
+
...new Map(errors.map((error) => [error?.message, error])).values(),
|
|
203
|
+
]
|
|
204
|
+
|
|
205
|
+
if (uniqueErrors?.length == 1) {
|
|
206
|
+
return uniqueErrors[0]?.message
|
|
200
207
|
}
|
|
201
208
|
|
|
202
209
|
return (
|
|
203
210
|
<ul className="ml-4 flex list-disc flex-col gap-1">
|
|
204
|
-
{
|
|
211
|
+
{uniqueErrors.map(
|
|
205
212
|
(error, index) =>
|
|
206
213
|
error?.message && <li key={index}>{error.message}</li>
|
|
207
214
|
)}
|
|
208
215
|
</ul>
|
|
209
|
-
)
|
|
210
|
-
}, [children, errors])
|
|
216
|
+
)
|
|
217
|
+
}, [children, errors])
|
|
211
218
|
|
|
212
219
|
if (!content) {
|
|
213
|
-
return null
|
|
220
|
+
return null
|
|
214
221
|
}
|
|
215
222
|
|
|
216
223
|
return (
|
|
@@ -222,18 +229,14 @@ function FieldError({
|
|
|
222
229
|
>
|
|
223
230
|
{content}
|
|
224
231
|
</div>
|
|
225
|
-
)
|
|
232
|
+
)
|
|
226
233
|
}
|
|
227
234
|
|
|
228
235
|
export {
|
|
229
|
-
Field,
|
|
230
|
-
FieldContent,
|
|
231
|
-
FieldDescription,
|
|
236
|
+
Field, FieldContent, FieldDescription,
|
|
232
237
|
FieldError,
|
|
233
|
-
FieldGroup,
|
|
234
|
-
FieldLabel,
|
|
235
|
-
FieldLegend,
|
|
238
|
+
FieldGroup, FieldLabel, FieldLegend,
|
|
236
239
|
FieldSeparator,
|
|
237
|
-
FieldSet,
|
|
238
|
-
|
|
239
|
-
|
|
240
|
+
FieldSet, FieldTitle
|
|
241
|
+
}
|
|
242
|
+
|
|
@@ -1,46 +1,55 @@
|
|
|
1
|
-
import { OTPInput, OTPInputContext } from "input-otp"
|
|
2
|
-
import {
|
|
3
|
-
import * as React from "react"
|
|
1
|
+
import { OTPInput, OTPInputContext } from "input-otp"
|
|
2
|
+
import { MinusIcon } from "lucide-react"
|
|
3
|
+
import * as React from "react"
|
|
4
4
|
|
|
5
|
-
import { cn } from
|
|
5
|
+
import { cn } from '../lib/utils'
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
)
|
|
21
|
-
|
|
7
|
+
function InputOTP({
|
|
8
|
+
className,
|
|
9
|
+
containerClassName,
|
|
10
|
+
...props
|
|
11
|
+
}: React.ComponentProps<typeof OTPInput> & {
|
|
12
|
+
containerClassName?: string
|
|
13
|
+
}) {
|
|
14
|
+
return (
|
|
15
|
+
<OTPInput
|
|
16
|
+
data-slot="input-otp"
|
|
17
|
+
containerClassName={cn(
|
|
18
|
+
"flex items-center gap-2 has-disabled:opacity-50",
|
|
19
|
+
containerClassName
|
|
20
|
+
)}
|
|
21
|
+
className={cn("disabled:cursor-not-allowed", className)}
|
|
22
|
+
{...props}
|
|
23
|
+
/>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
22
26
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
function InputOTPGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
28
|
+
return (
|
|
29
|
+
<div
|
|
30
|
+
data-slot="input-otp-group"
|
|
31
|
+
className={cn("flex items-center", className)}
|
|
32
|
+
{...props}
|
|
33
|
+
/>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
30
36
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
function InputOTPSlot({
|
|
38
|
+
index,
|
|
39
|
+
className,
|
|
40
|
+
...props
|
|
41
|
+
}: React.ComponentProps<"div"> & {
|
|
42
|
+
index: number
|
|
43
|
+
}) {
|
|
44
|
+
const inputOTPContext = React.useContext(OTPInputContext)
|
|
45
|
+
const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {}
|
|
37
46
|
|
|
38
47
|
return (
|
|
39
48
|
<div
|
|
40
|
-
|
|
49
|
+
data-slot="input-otp-slot"
|
|
50
|
+
data-active={isActive}
|
|
41
51
|
className={cn(
|
|
42
|
-
"relative flex h-9 w-9 items-center justify-center border-y border-r
|
|
43
|
-
isActive && "z-10 ring-1 ring-ring",
|
|
52
|
+
"data-[active=true]:border-ring data-[active=true]:ring-ring/50 data-[active=true]:aria-invalid:ring-destructive/20 dark:data-[active=true]:aria-invalid:ring-destructive/40 aria-invalid:border-destructive data-[active=true]:aria-invalid:border-destructive dark:bg-input/30 border-input relative flex h-9 w-9 items-center justify-center border-y border-r text-sm shadow-xs transition-all outline-none first:rounded-l-md first:border-l last:rounded-r-md data-[active=true]:z-10 data-[active=true]:ring-[3px]",
|
|
44
53
|
className
|
|
45
54
|
)}
|
|
46
55
|
{...props}
|
|
@@ -48,22 +57,20 @@ const InputOTPSlot = React.forwardRef<
|
|
|
48
57
|
{char}
|
|
49
58
|
{hasFakeCaret && (
|
|
50
59
|
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
|
|
51
|
-
<div className="
|
|
60
|
+
<div className="animate-caret-blink bg-foreground h-4 w-px duration-1000" />
|
|
52
61
|
</div>
|
|
53
62
|
)}
|
|
54
63
|
</div>
|
|
55
|
-
)
|
|
56
|
-
}
|
|
57
|
-
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function InputOTPSeparator({ ...props }: React.ComponentProps<"div">) {
|
|
68
|
+
return (
|
|
69
|
+
<div data-slot="input-otp-separator" role="separator" {...props}>
|
|
70
|
+
<MinusIcon />
|
|
71
|
+
</div>
|
|
72
|
+
)
|
|
73
|
+
}
|
|
58
74
|
|
|
59
|
-
|
|
60
|
-
React.ElementRef<"div">,
|
|
61
|
-
React.ComponentPropsWithoutRef<"div">
|
|
62
|
-
>(({ ...props }, ref) => (
|
|
63
|
-
<div ref={ref} role="separator" {...props}>
|
|
64
|
-
<Minus />
|
|
65
|
-
</div>
|
|
66
|
-
));
|
|
67
|
-
InputOTPSeparator.displayName = "InputOTPSeparator";
|
|
75
|
+
export { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot }
|
|
68
76
|
|
|
69
|
-
export { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot };
|
|
@@ -1,24 +1,21 @@
|
|
|
1
|
-
import * as React from "react"
|
|
1
|
+
import * as React from "react"
|
|
2
2
|
|
|
3
|
-
import { cn } from
|
|
3
|
+
import { cn } from '../lib/utils'
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
(
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
);
|
|
22
|
-
Input.displayName = "Input";
|
|
5
|
+
function Input({ className, type, ...props }: React.ComponentProps<"input">) {
|
|
6
|
+
return (
|
|
7
|
+
<input
|
|
8
|
+
type={type}
|
|
9
|
+
data-slot="input"
|
|
10
|
+
className={cn(
|
|
11
|
+
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
|
12
|
+
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
|
|
13
|
+
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
|
14
|
+
className
|
|
15
|
+
)}
|
|
16
|
+
{...props}
|
|
17
|
+
/>
|
|
18
|
+
)
|
|
19
|
+
}
|
|
23
20
|
|
|
24
|
-
export { Input }
|
|
21
|
+
export { Input }
|
|
@@ -1,24 +1,23 @@
|
|
|
1
|
-
import * as LabelPrimitive from "@radix-ui/react-label"
|
|
2
|
-
import
|
|
3
|
-
import * as React from "react";
|
|
1
|
+
import * as LabelPrimitive from "@radix-ui/react-label"
|
|
2
|
+
import * as React from "react"
|
|
4
3
|
|
|
5
|
-
import { cn } from
|
|
4
|
+
import { cn } from '../lib/utils'
|
|
6
5
|
|
|
7
|
-
const labelVariants = cva(
|
|
8
|
-
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
|
9
|
-
);
|
|
10
6
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
)
|
|
22
|
-
|
|
7
|
+
function Label({
|
|
8
|
+
className,
|
|
9
|
+
...props
|
|
10
|
+
}: React.ComponentProps<typeof LabelPrimitive.Root>) {
|
|
11
|
+
return (
|
|
12
|
+
<LabelPrimitive.Root
|
|
13
|
+
data-slot="label"
|
|
14
|
+
className={cn(
|
|
15
|
+
"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
|
|
16
|
+
className
|
|
17
|
+
)}
|
|
18
|
+
{...props}
|
|
19
|
+
/>
|
|
20
|
+
)
|
|
21
|
+
}
|
|
23
22
|
|
|
24
|
-
export { Label }
|
|
23
|
+
export { Label }
|
|
@@ -1,42 +1,44 @@
|
|
|
1
|
-
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group"
|
|
2
|
-
import {
|
|
3
|
-
import * as React from "react"
|
|
1
|
+
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group"
|
|
2
|
+
import { CircleIcon } from "lucide-react"
|
|
3
|
+
import * as React from "react"
|
|
4
4
|
|
|
5
|
-
import { cn } from
|
|
5
|
+
import { cn } from '../lib/utils'
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
|
|
8
|
+
function RadioGroup({
|
|
9
|
+
className,
|
|
10
|
+
...props
|
|
11
|
+
}: React.ComponentProps<typeof RadioGroupPrimitive.Root>) {
|
|
11
12
|
return (
|
|
12
13
|
<RadioGroupPrimitive.Root
|
|
13
|
-
|
|
14
|
+
data-slot="radio-group"
|
|
15
|
+
className={cn("grid gap-3", className)}
|
|
14
16
|
{...props}
|
|
15
|
-
ref={ref}
|
|
16
17
|
/>
|
|
17
|
-
)
|
|
18
|
-
}
|
|
19
|
-
RadioGroup.displayName = RadioGroupPrimitive.Root.displayName;
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
function RadioGroupItem({
|
|
22
|
+
className,
|
|
23
|
+
...props
|
|
24
|
+
}: React.ComponentProps<typeof RadioGroupPrimitive.Item>) {
|
|
25
25
|
return (
|
|
26
26
|
<RadioGroupPrimitive.Item
|
|
27
|
-
|
|
27
|
+
data-slot="radio-group-item"
|
|
28
28
|
className={cn(
|
|
29
|
-
"aspect-square
|
|
29
|
+
"border-input text-primary 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:bg-input/30 aspect-square size-4 shrink-0 rounded-full border shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
|
|
30
30
|
className
|
|
31
31
|
)}
|
|
32
32
|
{...props}
|
|
33
33
|
>
|
|
34
|
-
<RadioGroupPrimitive.Indicator
|
|
35
|
-
|
|
34
|
+
<RadioGroupPrimitive.Indicator
|
|
35
|
+
data-slot="radio-group-indicator"
|
|
36
|
+
className="relative flex items-center justify-center"
|
|
37
|
+
>
|
|
38
|
+
<CircleIcon className="fill-primary absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2" />
|
|
36
39
|
</RadioGroupPrimitive.Indicator>
|
|
37
40
|
</RadioGroupPrimitive.Item>
|
|
38
|
-
)
|
|
39
|
-
}
|
|
40
|
-
RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;
|
|
41
|
+
)
|
|
42
|
+
}
|
|
41
43
|
|
|
42
|
-
export { RadioGroup, RadioGroupItem }
|
|
44
|
+
export { RadioGroup, RadioGroupItem }
|