-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathradio-group.tsx
More file actions
114 lines (101 loc) · 3.11 KB
/
radio-group.tsx
File metadata and controls
114 lines (101 loc) · 3.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
'use client'
import * as React from 'react'
import { cn } from '@/lib/utils'
interface RadioGroupContextValue {
value: string
onChange: (value: string) => void
name: string
}
const RadioGroupContext = React.createContext<RadioGroupContextValue | null>(
null
)
function useRadioGroupContext() {
const context = React.useContext(RadioGroupContext)
if (!context) {
throw new Error('RadioGroupItem must be used within a RadioGroup')
}
return context
}
export interface RadioGroupProps extends React.HTMLAttributes<HTMLDivElement> {
value?: string
defaultValue?: string
onValueChange?: (value: string) => void
name?: string
}
export function RadioGroup({
value,
defaultValue = '',
onValueChange,
name = 'radio-group',
className,
children,
...props
}: RadioGroupProps) {
const [internalValue, setInternalValue] = React.useState(defaultValue)
const controlledValue = value ?? internalValue
const onChange = React.useCallback(
(newValue: string) => {
if (value === undefined) {
setInternalValue(newValue)
}
onValueChange?.(newValue)
},
[value, onValueChange]
)
return (
<RadioGroupContext.Provider
value={{ value: controlledValue, onChange, name }}
>
<div
className={cn('grid gap-2', className)}
role="radiogroup"
{...props}
>
{children}
</div>
</RadioGroupContext.Provider>
)
}
export interface RadioGroupItemProps extends Omit<
React.InputHTMLAttributes<HTMLInputElement>,
'type' | 'name' | 'checked' | 'onChange'
> {
value: string
}
export const RadioGroupItem = React.forwardRef<
HTMLInputElement,
RadioGroupItemProps
>(({ value, className, ...props }, ref) => {
const { value: groupValue, onChange, name } = useRadioGroupContext()
const isChecked = groupValue === value
return (
<label className="relative inline-flex cursor-pointer items-center">
<input
type="radio"
name={name}
value={value}
checked={isChecked}
onChange={() => onChange(value)}
className="peer sr-only"
ref={ref}
{...props}
/>
<div
className={cn(
'flex size-4 items-center justify-center rounded-full border border-primary ring-offset-background transition-colors',
'peer-focus-visible:ring-2 peer-focus-visible:ring-ring peer-focus-visible:ring-offset-2',
'peer-disabled:cursor-not-allowed peer-disabled:opacity-50',
className
)}
>
<div
className={cn(
'size-2.5 rounded-full bg-primary opacity-0 transition-opacity',
isChecked && 'opacity-100'
)}
/>
</div>
</label>
)
})
RadioGroupItem.displayName = 'RadioGroupItem'