@tamagui/radio-group 1.4.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/dist/cjs/RadioGroup.js +382 -0
- package/dist/cjs/RadioGroup.js.map +7 -0
- package/dist/cjs/index.js +19 -0
- package/dist/cjs/index.js.map +7 -0
- package/dist/esm/RadioGroup.js +354 -0
- package/dist/esm/RadioGroup.js.map +7 -0
- package/dist/esm/RadioGroup.mjs +354 -0
- package/dist/esm/RadioGroup.mjs.map +7 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +7 -0
- package/dist/esm/index.mjs +2 -0
- package/dist/esm/index.mjs.map +7 -0
- package/dist/jsx/RadioGroup.js +330 -0
- package/dist/jsx/RadioGroup.js.map +7 -0
- package/dist/jsx/RadioGroup.mjs +330 -0
- package/dist/jsx/RadioGroup.mjs.map +7 -0
- package/dist/jsx/index.js +2 -0
- package/dist/jsx/index.js.map +7 -0
- package/dist/jsx/index.mjs +2 -0
- package/dist/jsx/index.mjs.map +7 -0
- package/package.json +48 -0
- package/src/RadioGroup.tsx +482 -0
- package/src/index.ts +1 -0
- package/types/RadioGroup.d.ts +264 -0
- package/types/RadioGroup.d.ts.map +1 -0
- package/types/index.d.ts +2 -0
- package/types/index.d.ts.map +1 -0
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
// forked from Radix UI
|
|
2
|
+
// https://github.com/radix-ui/primitives/blob/main/packages/react/radio-group/src/RadioGroup.tsx
|
|
3
|
+
|
|
4
|
+
import { usePrevious } from '@radix-ui/react-use-previous'
|
|
5
|
+
import {
|
|
6
|
+
GetProps,
|
|
7
|
+
composeEventHandlers,
|
|
8
|
+
getVariableValue,
|
|
9
|
+
isWeb,
|
|
10
|
+
styled,
|
|
11
|
+
useComposedRefs,
|
|
12
|
+
withStaticProperties,
|
|
13
|
+
} from '@tamagui/core'
|
|
14
|
+
import { Scope, createContextScope } from '@tamagui/create-context'
|
|
15
|
+
import { registerFocusable } from '@tamagui/focusable'
|
|
16
|
+
import { getSize, stepTokenUpOrDown } from '@tamagui/get-size'
|
|
17
|
+
import { useLabelContext } from '@tamagui/label'
|
|
18
|
+
import { ThemeableStack } from '@tamagui/stacks'
|
|
19
|
+
import { useControllableState } from '@tamagui/use-controllable-state'
|
|
20
|
+
import * as React from 'react'
|
|
21
|
+
import { View } from 'react-native'
|
|
22
|
+
|
|
23
|
+
const RADIO_GROUP_NAME = 'RadioGroup'
|
|
24
|
+
|
|
25
|
+
const ARROW_KEYS = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight']
|
|
26
|
+
|
|
27
|
+
const [createRadioGroupContext, createRadioGroupScope] =
|
|
28
|
+
createContextScope(RADIO_GROUP_NAME)
|
|
29
|
+
type RadioGroupContextValue = {
|
|
30
|
+
value?: string
|
|
31
|
+
disabled?: boolean
|
|
32
|
+
required?: boolean
|
|
33
|
+
onChange?: (value: string) => void
|
|
34
|
+
name?: string
|
|
35
|
+
native?: boolean
|
|
36
|
+
accentColor?: string
|
|
37
|
+
}
|
|
38
|
+
const [RadioGroupProvider, useRadioGroupContext] =
|
|
39
|
+
createRadioGroupContext<RadioGroupContextValue>(RADIO_GROUP_NAME)
|
|
40
|
+
|
|
41
|
+
const getState = (checked: boolean) => {
|
|
42
|
+
return checked ? 'checked' : 'unchecked'
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* -------------------------------------------------------------------------
|
|
46
|
+
* RadioIndicator
|
|
47
|
+
* ------------------------------------------------------------------------ */
|
|
48
|
+
|
|
49
|
+
const RADIO_GROUP_INDICATOR_NAME = 'RadioGroupIndicator'
|
|
50
|
+
|
|
51
|
+
const RadioIndicatorFrame = styled(ThemeableStack, {
|
|
52
|
+
name: RADIO_GROUP_INDICATOR_NAME,
|
|
53
|
+
pointerEvents: 'none',
|
|
54
|
+
|
|
55
|
+
variants: {
|
|
56
|
+
unstyled: {
|
|
57
|
+
false: {
|
|
58
|
+
w: '60%',
|
|
59
|
+
h: '60%',
|
|
60
|
+
br: 1000,
|
|
61
|
+
backgroundColor: '$color',
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
} as const,
|
|
65
|
+
|
|
66
|
+
defaultVariants: {
|
|
67
|
+
unstyled: false,
|
|
68
|
+
},
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
type RadioIndicatorProps = GetProps<typeof RadioIndicatorFrame> & {
|
|
72
|
+
forceMount?: boolean
|
|
73
|
+
unstyled?: boolean
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
type RadioIndicatorElement = TamaguiElement
|
|
77
|
+
|
|
78
|
+
const RadioIndicator = RadioIndicatorFrame.extractable(
|
|
79
|
+
React.forwardRef<RadioIndicatorElement, RadioIndicatorProps>(
|
|
80
|
+
(props: ScopedRadioGroupItemProps<RadioIndicatorProps>, forwardedRef) => {
|
|
81
|
+
const { __scopeRadioGroupItem, forceMount, disabled, ...indicatorProps } = props
|
|
82
|
+
const { checked } = useRadioGroupItemContext(
|
|
83
|
+
RADIO_GROUP_INDICATOR_NAME,
|
|
84
|
+
__scopeRadioGroupItem
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
if (forceMount || checked) {
|
|
88
|
+
return (
|
|
89
|
+
<RadioIndicatorFrame
|
|
90
|
+
theme="active"
|
|
91
|
+
data-state={getState(checked)}
|
|
92
|
+
data-disabled={disabled ? '' : undefined}
|
|
93
|
+
{...indicatorProps}
|
|
94
|
+
ref={forwardedRef}
|
|
95
|
+
/>
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return null
|
|
100
|
+
}
|
|
101
|
+
)
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
RadioIndicator.displayName = RADIO_GROUP_INDICATOR_NAME
|
|
105
|
+
|
|
106
|
+
/* -------------------------------------------------------------------------
|
|
107
|
+
* RadioGroupItem
|
|
108
|
+
* ------------------------------------------------------------------------ */
|
|
109
|
+
|
|
110
|
+
const RADIO_GROUP_ITEM_NAME = 'RadioGroupItem'
|
|
111
|
+
|
|
112
|
+
type RadioGroupItemContextValue = {
|
|
113
|
+
checked: boolean
|
|
114
|
+
disabled?: boolean
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const [RadioGroupItemProvider, useRadioGroupItemContext] =
|
|
118
|
+
createRadioGroupContext<RadioGroupItemContextValue>(RADIO_GROUP_NAME)
|
|
119
|
+
|
|
120
|
+
const RadioGroupItemFrame = styled(ThemeableStack, {
|
|
121
|
+
name: RADIO_GROUP_ITEM_NAME,
|
|
122
|
+
tag: 'button',
|
|
123
|
+
debug: 'verbose',
|
|
124
|
+
|
|
125
|
+
variants: {
|
|
126
|
+
unstyled: {
|
|
127
|
+
false: {
|
|
128
|
+
borderRadius: 9999,
|
|
129
|
+
backgroundColor: '$background',
|
|
130
|
+
alignItems: 'center',
|
|
131
|
+
justifyContent: 'center',
|
|
132
|
+
borderWidth: 2,
|
|
133
|
+
borderColor: 'transparent',
|
|
134
|
+
|
|
135
|
+
focusStyle: {
|
|
136
|
+
borderColor: '$borderColorFocus',
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
size: {
|
|
142
|
+
'...size': (value, { props }) => {
|
|
143
|
+
const size = Math.floor(
|
|
144
|
+
getVariableValue(getSize(value)) * (props['scaleSize'] ?? 0.5)
|
|
145
|
+
)
|
|
146
|
+
return {
|
|
147
|
+
width: size,
|
|
148
|
+
height: size,
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
} as const,
|
|
153
|
+
|
|
154
|
+
defaultVariants: {
|
|
155
|
+
size: '$true',
|
|
156
|
+
unstyled: false,
|
|
157
|
+
},
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
type RadioGroupItemProps = GetProps<typeof RadioGroupItemFrame> & {
|
|
161
|
+
value: string
|
|
162
|
+
id?: string
|
|
163
|
+
labelledBy?: string
|
|
164
|
+
disabled?: boolean
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
type RadioGroupItemElement = HTMLButtonElement
|
|
168
|
+
|
|
169
|
+
type ScopedRadioGroupItemProps<P> = P & {
|
|
170
|
+
__scopeRadioGroupItem?: Scope
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const RadioGroupItem = RadioGroupItemFrame.extractable(
|
|
174
|
+
React.forwardRef<RadioGroupItemElement, RadioGroupItemProps>(
|
|
175
|
+
(props: ScopedProps<RadioGroupItemProps>, forwardedRef) => {
|
|
176
|
+
const {
|
|
177
|
+
__scopeRadioGroup,
|
|
178
|
+
value,
|
|
179
|
+
labelledBy: ariaLabelledby,
|
|
180
|
+
disabled: itemDisabled,
|
|
181
|
+
...itemProps
|
|
182
|
+
} = props
|
|
183
|
+
const {
|
|
184
|
+
value: groupValue,
|
|
185
|
+
disabled,
|
|
186
|
+
required,
|
|
187
|
+
onChange,
|
|
188
|
+
name,
|
|
189
|
+
native,
|
|
190
|
+
accentColor,
|
|
191
|
+
} = useRadioGroupContext(RADIO_GROUP_ITEM_NAME, __scopeRadioGroup)
|
|
192
|
+
const [button, setButton] = React.useState<HTMLButtonElement | null>(null)
|
|
193
|
+
const hasConsumerStoppedPropagationRef = React.useRef(false)
|
|
194
|
+
const ref = React.useRef<HTMLButtonElement>(null)
|
|
195
|
+
const composedRefs = useComposedRefs(forwardedRef, (node) => setButton(node), ref)
|
|
196
|
+
const isArrowKeyPressedRef = React.useRef(false)
|
|
197
|
+
|
|
198
|
+
const isFormControl = isWeb
|
|
199
|
+
? button
|
|
200
|
+
? Boolean(button.closest('form'))
|
|
201
|
+
: true
|
|
202
|
+
: false
|
|
203
|
+
|
|
204
|
+
const checked = groupValue === value
|
|
205
|
+
|
|
206
|
+
const labelId = useLabelContext(button)
|
|
207
|
+
const labelledBy = ariaLabelledby || labelId
|
|
208
|
+
|
|
209
|
+
React.useEffect(() => {
|
|
210
|
+
if (isWeb) {
|
|
211
|
+
const handleKeyDown = (event: KeyboardEvent) => {
|
|
212
|
+
if (ARROW_KEYS.includes(event.key)) {
|
|
213
|
+
isArrowKeyPressedRef.current = true
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
const handleKeyUp = () => (isArrowKeyPressedRef.current = false)
|
|
217
|
+
document.addEventListener('keydown', handleKeyDown)
|
|
218
|
+
document.addEventListener('keyup', handleKeyUp)
|
|
219
|
+
return () => {
|
|
220
|
+
document.removeEventListener('keydown', handleKeyDown)
|
|
221
|
+
document.removeEventListener('keyup', handleKeyUp)
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}, [])
|
|
225
|
+
|
|
226
|
+
if (process.env.TAMAGUI_TARGET === 'native') {
|
|
227
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
228
|
+
React.useEffect(() => {
|
|
229
|
+
if (!props.id) return
|
|
230
|
+
return registerFocusable(props.id, {
|
|
231
|
+
focusAndSelect: () => {
|
|
232
|
+
onChange?.(value)
|
|
233
|
+
},
|
|
234
|
+
focus: () => {},
|
|
235
|
+
})
|
|
236
|
+
}, [props.id, value])
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const isDisabled = disabled || itemDisabled
|
|
240
|
+
|
|
241
|
+
return (
|
|
242
|
+
<RadioGroupItemProvider checked={checked} scope={__scopeRadioGroup}>
|
|
243
|
+
{isWeb && native ? (
|
|
244
|
+
<BubbleInput
|
|
245
|
+
control={button}
|
|
246
|
+
bubbles={!hasConsumerStoppedPropagationRef.current}
|
|
247
|
+
name={name}
|
|
248
|
+
value={value}
|
|
249
|
+
checked={checked}
|
|
250
|
+
required={required}
|
|
251
|
+
disabled={isDisabled}
|
|
252
|
+
id={props.id}
|
|
253
|
+
accentColor={accentColor}
|
|
254
|
+
/>
|
|
255
|
+
) : (
|
|
256
|
+
<>
|
|
257
|
+
<RadioGroupItemFrame
|
|
258
|
+
// theme={checked ? 'active' : undefined}
|
|
259
|
+
data-state={getState(checked)}
|
|
260
|
+
data-disabled={isDisabled ? '' : undefined}
|
|
261
|
+
role="radio"
|
|
262
|
+
aria-labelledby={labelledBy}
|
|
263
|
+
aria-checked={checked}
|
|
264
|
+
aria-required={required}
|
|
265
|
+
disabled={isDisabled}
|
|
266
|
+
ref={composedRefs}
|
|
267
|
+
{...(isWeb && {
|
|
268
|
+
type: 'button',
|
|
269
|
+
value: value,
|
|
270
|
+
})}
|
|
271
|
+
// allow them to override all but the handlers that already compose:
|
|
272
|
+
{...itemProps}
|
|
273
|
+
onPress={composeEventHandlers(props.onPress as any, (event) => {
|
|
274
|
+
if (!checked) {
|
|
275
|
+
onChange?.(value)
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (isFormControl) {
|
|
279
|
+
hasConsumerStoppedPropagationRef.current =
|
|
280
|
+
event.isPropagationStopped()
|
|
281
|
+
// if radio is in a form, stop propagation from the button so that we only propagate
|
|
282
|
+
// one click event (from the input). We propagate changes from an input so that native
|
|
283
|
+
// form validation works and form events reflect radio updates.
|
|
284
|
+
if (!hasConsumerStoppedPropagationRef.current) event.stopPropagation()
|
|
285
|
+
}
|
|
286
|
+
})}
|
|
287
|
+
{...(isWeb && {
|
|
288
|
+
onKeyDown: composeEventHandlers(
|
|
289
|
+
(props as React.HTMLProps<HTMLButtonElement>).onKeyDown,
|
|
290
|
+
(event) => {
|
|
291
|
+
// According to WAI ARIA, Checkboxes don't activate on enter keypress
|
|
292
|
+
if (event.key === 'Enter') event.preventDefault()
|
|
293
|
+
}
|
|
294
|
+
),
|
|
295
|
+
onFocus: composeEventHandlers(itemProps.onFocus, () => {
|
|
296
|
+
/**
|
|
297
|
+
* Our `RovingFocusGroup` will focus the radio when navigating with arrow keys
|
|
298
|
+
* and we need to "check" it in that case. We click it to "check" it (instead
|
|
299
|
+
* of updating `context.value`) so that the radio change event fires.
|
|
300
|
+
*/
|
|
301
|
+
if (isArrowKeyPressedRef.current)
|
|
302
|
+
(ref.current as HTMLButtonElement)?.click()
|
|
303
|
+
}),
|
|
304
|
+
})}
|
|
305
|
+
/>
|
|
306
|
+
{isFormControl && (
|
|
307
|
+
<BubbleInput
|
|
308
|
+
isHidden
|
|
309
|
+
control={button}
|
|
310
|
+
bubbles={!hasConsumerStoppedPropagationRef.current}
|
|
311
|
+
name={name}
|
|
312
|
+
value={value}
|
|
313
|
+
checked={checked}
|
|
314
|
+
required={required}
|
|
315
|
+
disabled={isDisabled}
|
|
316
|
+
/>
|
|
317
|
+
)}
|
|
318
|
+
</>
|
|
319
|
+
)}
|
|
320
|
+
</RadioGroupItemProvider>
|
|
321
|
+
)
|
|
322
|
+
}
|
|
323
|
+
)
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
/* -------------------------------------------------------------------------
|
|
327
|
+
* BubbleInput
|
|
328
|
+
* ------------------------------------------------------------------------ */
|
|
329
|
+
|
|
330
|
+
interface BubbleInputProps extends Omit<React.HTMLProps<HTMLInputElement>, 'checked'> {
|
|
331
|
+
checked: boolean
|
|
332
|
+
control: HTMLElement | null
|
|
333
|
+
bubbles: boolean
|
|
334
|
+
isHidden?: boolean
|
|
335
|
+
accentColor?: string
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const BubbleInput = (props: BubbleInputProps) => {
|
|
339
|
+
const { checked, bubbles = true, control, isHidden, accentColor, ...inputProps } = props
|
|
340
|
+
const ref = React.useRef<HTMLInputElement>(null)
|
|
341
|
+
const prevChecked = usePrevious(checked)
|
|
342
|
+
|
|
343
|
+
// Bubble checked change to parents (e.g form change event)
|
|
344
|
+
React.useEffect(() => {
|
|
345
|
+
const input = ref.current!
|
|
346
|
+
const inputProto = window.HTMLInputElement.prototype
|
|
347
|
+
const descriptor = Object.getOwnPropertyDescriptor(
|
|
348
|
+
inputProto,
|
|
349
|
+
'checked'
|
|
350
|
+
) as PropertyDescriptor
|
|
351
|
+
const setChecked = descriptor.set
|
|
352
|
+
if (prevChecked !== checked && setChecked) {
|
|
353
|
+
const event = new Event('click', { bubbles })
|
|
354
|
+
setChecked.call(input, checked)
|
|
355
|
+
input.dispatchEvent(event)
|
|
356
|
+
}
|
|
357
|
+
}, [prevChecked, checked, bubbles])
|
|
358
|
+
|
|
359
|
+
return (
|
|
360
|
+
<input
|
|
361
|
+
type="radio"
|
|
362
|
+
defaultChecked={checked}
|
|
363
|
+
{...inputProps}
|
|
364
|
+
tabIndex={-1}
|
|
365
|
+
ref={ref}
|
|
366
|
+
aria-hidden={isHidden}
|
|
367
|
+
style={{
|
|
368
|
+
...(isHidden
|
|
369
|
+
? {
|
|
370
|
+
// ...controlSize,
|
|
371
|
+
position: 'absolute',
|
|
372
|
+
pointerEvents: 'none',
|
|
373
|
+
opacity: 0,
|
|
374
|
+
margin: 0,
|
|
375
|
+
}
|
|
376
|
+
: {
|
|
377
|
+
appearance: 'auto',
|
|
378
|
+
accentColor,
|
|
379
|
+
}),
|
|
380
|
+
|
|
381
|
+
...props.style,
|
|
382
|
+
}}
|
|
383
|
+
/>
|
|
384
|
+
)
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/* -------------------------------------------------------------------------
|
|
388
|
+
* RadioGroup
|
|
389
|
+
* ----------------------------------------------------------------------- */
|
|
390
|
+
|
|
391
|
+
type ScopedProps<P> = P & { __scopeRadioGroup?: Scope }
|
|
392
|
+
|
|
393
|
+
type TamaguiElement = HTMLElement | View
|
|
394
|
+
|
|
395
|
+
type RadioGroupElement = TamaguiElement
|
|
396
|
+
|
|
397
|
+
const RadioGroupFrame = styled(ThemeableStack, {
|
|
398
|
+
name: RADIO_GROUP_NAME,
|
|
399
|
+
|
|
400
|
+
variants: {
|
|
401
|
+
orientation: {
|
|
402
|
+
horizontal: {
|
|
403
|
+
flexDirection: 'row',
|
|
404
|
+
spaceDirection: 'horizontal',
|
|
405
|
+
},
|
|
406
|
+
vertical: {
|
|
407
|
+
flexDirection: 'column',
|
|
408
|
+
spaceDirection: 'vertical',
|
|
409
|
+
},
|
|
410
|
+
},
|
|
411
|
+
} as const,
|
|
412
|
+
})
|
|
413
|
+
|
|
414
|
+
type RadioGroupProps = GetProps<typeof RadioGroupFrame> & {
|
|
415
|
+
value?: string
|
|
416
|
+
defaultValue?: string
|
|
417
|
+
onValueChange?: (value: string) => void
|
|
418
|
+
required?: boolean
|
|
419
|
+
disabled?: boolean
|
|
420
|
+
name?: string
|
|
421
|
+
native?: boolean
|
|
422
|
+
accentColor?: string
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
const RadioGroup = withStaticProperties(
|
|
426
|
+
RadioGroupFrame.extractable(
|
|
427
|
+
React.forwardRef<RadioGroupElement, RadioGroupProps>(
|
|
428
|
+
(props: ScopedProps<RadioGroupProps>, forwardedRef) => {
|
|
429
|
+
const {
|
|
430
|
+
__scopeRadioGroup,
|
|
431
|
+
value: valueProp,
|
|
432
|
+
defaultValue,
|
|
433
|
+
onValueChange,
|
|
434
|
+
disabled = false,
|
|
435
|
+
required = false,
|
|
436
|
+
name,
|
|
437
|
+
orientation,
|
|
438
|
+
native,
|
|
439
|
+
accentColor,
|
|
440
|
+
...radioGroupProps
|
|
441
|
+
} = props
|
|
442
|
+
const [value, setValue] = useControllableState({
|
|
443
|
+
prop: valueProp,
|
|
444
|
+
defaultProp: defaultValue!,
|
|
445
|
+
onChange: onValueChange,
|
|
446
|
+
})
|
|
447
|
+
|
|
448
|
+
return (
|
|
449
|
+
<RadioGroupProvider
|
|
450
|
+
scope={__scopeRadioGroup}
|
|
451
|
+
value={value}
|
|
452
|
+
required={required}
|
|
453
|
+
onChange={setValue}
|
|
454
|
+
disabled={disabled}
|
|
455
|
+
name={name}
|
|
456
|
+
native={native}
|
|
457
|
+
accentColor={accentColor}
|
|
458
|
+
>
|
|
459
|
+
<RadioGroupFrame
|
|
460
|
+
aria-valuetext={value}
|
|
461
|
+
role="radiogroup"
|
|
462
|
+
aria-orientation={orientation}
|
|
463
|
+
ref={forwardedRef}
|
|
464
|
+
orientation={orientation}
|
|
465
|
+
data-disabled={disabled ? '' : undefined}
|
|
466
|
+
{...radioGroupProps}
|
|
467
|
+
/>
|
|
468
|
+
</RadioGroupProvider>
|
|
469
|
+
)
|
|
470
|
+
}
|
|
471
|
+
)
|
|
472
|
+
),
|
|
473
|
+
{
|
|
474
|
+
Indicator: RadioIndicator,
|
|
475
|
+
Item: RadioGroupItem,
|
|
476
|
+
}
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
RadioGroup.displayName = RADIO_GROUP_NAME
|
|
480
|
+
|
|
481
|
+
export { createRadioGroupScope, RadioGroup }
|
|
482
|
+
export type { RadioGroupProps }
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './RadioGroup'
|