@octanejs/radix 0.1.2

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 (62) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +100 -0
  3. package/package.json +45 -0
  4. package/src/AccessibleIcon.ts +26 -0
  5. package/src/Accordion.ts +282 -0
  6. package/src/AlertDialog.ts +110 -0
  7. package/src/Arrow.ts +21 -0
  8. package/src/AspectRatio.ts +34 -0
  9. package/src/Avatar.ts +152 -0
  10. package/src/Checkbox.ts +325 -0
  11. package/src/Collapsible.ts +170 -0
  12. package/src/ContextMenu.ts +303 -0
  13. package/src/Dialog.ts +308 -0
  14. package/src/DismissableLayer.ts +413 -0
  15. package/src/DropdownMenu.ts +275 -0
  16. package/src/FocusScope.ts +266 -0
  17. package/src/Form.ts +621 -0
  18. package/src/HoverCard.ts +318 -0
  19. package/src/Label.ts +25 -0
  20. package/src/Menu.ts +1057 -0
  21. package/src/Menubar.ts +572 -0
  22. package/src/NavigationMenu.ts +1236 -0
  23. package/src/OneTimePasswordField.ts +977 -0
  24. package/src/PasswordToggleField.ts +495 -0
  25. package/src/Popover.ts +354 -0
  26. package/src/Popper.ts +401 -0
  27. package/src/Portal.ts +19 -0
  28. package/src/Presence.ts +225 -0
  29. package/src/Primitive.ts +53 -0
  30. package/src/Progress.ts +92 -0
  31. package/src/Radio.ts +262 -0
  32. package/src/RadioGroup.ts +212 -0
  33. package/src/RovingFocusGroup.ts +259 -0
  34. package/src/ScrollArea.ts +966 -0
  35. package/src/Select.ts +1901 -0
  36. package/src/Separator.ts +36 -0
  37. package/src/Slider.ts +745 -0
  38. package/src/Slot.ts +105 -0
  39. package/src/Switch.ts +278 -0
  40. package/src/Tabs.ts +177 -0
  41. package/src/Toast.ts +923 -0
  42. package/src/Toggle.ts +31 -0
  43. package/src/ToggleGroup.ts +157 -0
  44. package/src/Toolbar.ts +130 -0
  45. package/src/Tooltip.ts +669 -0
  46. package/src/VisuallyHidden.ts +29 -0
  47. package/src/collection.ts +97 -0
  48. package/src/compose-event-handlers.ts +15 -0
  49. package/src/compose-refs.ts +53 -0
  50. package/src/context.ts +109 -0
  51. package/src/direction.ts +19 -0
  52. package/src/focus-guards.ts +56 -0
  53. package/src/index.ts +54 -0
  54. package/src/internal.ts +42 -0
  55. package/src/scroll-lock.ts +57 -0
  56. package/src/use-callback-ref.ts +28 -0
  57. package/src/use-effect-event.ts +36 -0
  58. package/src/use-is-hydrated.ts +23 -0
  59. package/src/use-previous.ts +28 -0
  60. package/src/use-size.ts +57 -0
  61. package/src/useControllableState.ts +78 -0
  62. package/src/useId.ts +15 -0
@@ -0,0 +1,92 @@
1
+ // Ported from @radix-ui/react-progress (source:
2
+ // .radix-primitives/packages/react/progress/src/progress.tsx). A `role=progressbar` with
3
+ // value/max ARIA + `data-state` (indeterminate/loading/complete); Indicator mirrors the
4
+ // state for styling.
5
+ import { createElement } from 'octane';
6
+
7
+ import { createContextScope } from './context';
8
+ import { Primitive } from './Primitive';
9
+
10
+ const DEFAULT_MAX = 100;
11
+
12
+ const [createProgressContext, createProgressScope] = createContextScope('Progress');
13
+ export { createProgressScope };
14
+ const [ProgressProvider, useProgressContext] = createProgressContext<{
15
+ value: number | null;
16
+ max: number;
17
+ }>('Progress');
18
+
19
+ export function Root(props: any): any {
20
+ const {
21
+ __scopeProgress,
22
+ value: valueProp = null,
23
+ max: maxProp,
24
+ getValueLabel = defaultGetValueLabel,
25
+ ...progressProps
26
+ } = props ?? {};
27
+ if ((maxProp || maxProp === 0) && !isValidMaxNumber(maxProp)) {
28
+ console.error(getInvalidMaxError(`${maxProp}`, 'Progress'));
29
+ }
30
+ const max = isValidMaxNumber(maxProp) ? maxProp : DEFAULT_MAX;
31
+ if (valueProp !== null && !isValidValueNumber(valueProp, max)) {
32
+ console.error(getInvalidValueError(`${valueProp}`, 'Progress'));
33
+ }
34
+ const value = isValidValueNumber(valueProp, max) ? valueProp : null;
35
+ const valueLabel = isNumber(value) ? getValueLabel(value, max) : undefined;
36
+ return createElement(ProgressProvider, {
37
+ scope: __scopeProgress,
38
+ value,
39
+ max,
40
+ children: createElement(Primitive.div, {
41
+ 'aria-valuemax': max,
42
+ 'aria-valuemin': 0,
43
+ 'aria-valuenow': isNumber(value) ? value : undefined,
44
+ 'aria-valuetext': valueLabel,
45
+ role: 'progressbar',
46
+ 'data-state': getProgressState(value, max),
47
+ 'data-value': value ?? undefined,
48
+ 'data-max': max,
49
+ ...progressProps,
50
+ }),
51
+ });
52
+ }
53
+
54
+ export function Indicator(props: any): any {
55
+ const { __scopeProgress, ...indicatorProps } = props ?? {};
56
+ const context = useProgressContext('ProgressIndicator', __scopeProgress);
57
+ return createElement(Primitive.div, {
58
+ 'data-state': getProgressState(context.value, context.max),
59
+ 'data-value': context.value ?? undefined,
60
+ 'data-max': context.max,
61
+ ...indicatorProps,
62
+ });
63
+ }
64
+
65
+ function getProgressState(value: number | null | undefined, maxValue: number): string {
66
+ return value == null ? 'indeterminate' : value === maxValue ? 'complete' : 'loading';
67
+ }
68
+ function defaultGetValueLabel(value: number, max: number): string {
69
+ return `${Math.round((value / max) * 100)}%`;
70
+ }
71
+ function isNumber(value: any): value is number {
72
+ return typeof value === 'number';
73
+ }
74
+ function isValidMaxNumber(max: any): max is number {
75
+ return isNumber(max) && !isNaN(max) && max > 0;
76
+ }
77
+ function isValidValueNumber(value: any, max: number): value is number {
78
+ return isNumber(value) && !isNaN(value) && value <= max && value >= 0;
79
+ }
80
+ function getInvalidMaxError(propValue: string, componentName: string): string {
81
+ return `Invalid prop \`max\` of value \`${propValue}\` supplied to \`${componentName}\`. Only numbers greater than 0 are valid max values. Defaulting to \`${DEFAULT_MAX}\`.`;
82
+ }
83
+ function getInvalidValueError(propValue: string, componentName: string): string {
84
+ return `Invalid prop \`value\` of value \`${propValue}\` supplied to \`${componentName}\`. The \`value\` prop must be:
85
+ - a positive number
86
+ - less than the value passed to \`max\` (or ${DEFAULT_MAX} if no \`max\` prop is set)
87
+ - \`null\` or \`undefined\` if the progress is indeterminate.
88
+
89
+ Defaulting to \`null\`.`;
90
+ }
91
+
92
+ export { Root as Progress, Indicator as ProgressIndicator };
package/src/Radio.ts ADDED
@@ -0,0 +1,262 @@
1
+ // Ported from @radix-ui/react-radio-group's internal radio (source:
2
+ // .radix-primitives/packages/react/radio-group/src/radio.tsx). The single-radio
3
+ // building block RadioGroup composes: a `role=radio` button + Presence indicator +
4
+ // the hidden native-radio "bubble input" (same machinery as Checkbox). Same octane
5
+ // adaptations as Checkbox.ts: `isPropagationStopped()` → `event.cancelBubble`;
6
+ // `defaultChecked` → the native `checked` attribute; a native `change` dispatched
7
+ // alongside the source's `click`.
8
+ import { createElement, useEffect, useRef, useState } from 'octane';
9
+
10
+ import { composeEventHandlers } from './compose-event-handlers';
11
+ import { useComposedRefs } from './compose-refs';
12
+ import { createContextScope } from './context';
13
+ import { S, subSlot } from './internal';
14
+ import { Presence } from './Presence';
15
+ import { Primitive } from './Primitive';
16
+ import { usePrevious } from './use-previous';
17
+ import { useSize } from './use-size';
18
+
19
+ const RADIO_NAME = 'Radio';
20
+
21
+ const [createRadioContext, createRadioScope] = createContextScope(RADIO_NAME);
22
+ export { createRadioScope };
23
+
24
+ interface RadioContextValue {
25
+ checked: boolean;
26
+ disabled: boolean | undefined;
27
+ required: boolean | undefined;
28
+ name: string | undefined;
29
+ form: string | undefined;
30
+ value: string | number;
31
+ control: HTMLElement | null;
32
+ setControl: (control: HTMLElement | null) => void;
33
+ hasConsumerStoppedPropagationRef: { current: boolean };
34
+ isFormControl: boolean;
35
+ bubbleInput: HTMLInputElement | null;
36
+ setBubbleInput: (input: HTMLInputElement | null) => void;
37
+ onCheck(): void;
38
+ }
39
+
40
+ const [RadioProviderImpl, useRadioContextImpl] = createRadioContext<RadioContextValue>(RADIO_NAME);
41
+ export const useRadioContext = useRadioContextImpl;
42
+
43
+ export function RadioProvider(props: any): any {
44
+ const slot = S('Radio.Provider');
45
+ const {
46
+ __scopeRadio,
47
+ checked = false,
48
+ children,
49
+ disabled,
50
+ form,
51
+ name,
52
+ onCheck,
53
+ required,
54
+ value = 'on',
55
+ internal_do_not_use_render,
56
+ } = props ?? {};
57
+
58
+ const [control, setControl] = useState<HTMLElement | null>(null, subSlot(slot, 'control'));
59
+ const [bubbleInput, setBubbleInput] = useState<HTMLInputElement | null>(
60
+ null,
61
+ subSlot(slot, 'input'),
62
+ );
63
+ const hasConsumerStoppedPropagationRef = useRef(false, subSlot(slot, 'stopped'));
64
+ const isFormControl = control
65
+ ? !!form || !!control.closest('form')
66
+ : // We set this to true by default so that events bubble to forms without JS (SSR)
67
+ true;
68
+
69
+ const context: RadioContextValue = {
70
+ checked,
71
+ disabled,
72
+ required,
73
+ name,
74
+ form,
75
+ value,
76
+ control,
77
+ setControl,
78
+ hasConsumerStoppedPropagationRef,
79
+ isFormControl,
80
+ bubbleInput,
81
+ setBubbleInput,
82
+ onCheck: () => onCheck?.(),
83
+ };
84
+
85
+ return createElement(RadioProviderImpl, {
86
+ scope: __scopeRadio,
87
+ ...context,
88
+ children: isFunction(internal_do_not_use_render)
89
+ ? internal_do_not_use_render(context)
90
+ : children,
91
+ });
92
+ }
93
+
94
+ export function RadioTrigger(props: any): any {
95
+ const slot = S('Radio.Trigger');
96
+ const { __scopeRadio, onClick, ref: forwardedRef, ...radioProps } = props ?? {};
97
+ const {
98
+ checked,
99
+ disabled,
100
+ value,
101
+ setControl,
102
+ onCheck,
103
+ hasConsumerStoppedPropagationRef,
104
+ isFormControl,
105
+ bubbleInput,
106
+ } = useRadioContext('RadioTrigger', __scopeRadio);
107
+ const composedRefs = useComposedRefs(forwardedRef, setControl, subSlot(slot, 'refs'));
108
+
109
+ return createElement(Primitive.button, {
110
+ type: 'button',
111
+ role: 'radio',
112
+ 'aria-checked': checked,
113
+ 'data-state': getState(checked),
114
+ 'data-disabled': disabled ? '' : undefined,
115
+ disabled,
116
+ value,
117
+ ...radioProps,
118
+ ref: composedRefs,
119
+ onClick: composeEventHandlers(onClick, (event: MouseEvent) => {
120
+ // radios cannot be unchecked so we only communicate a checked state
121
+ if (!checked) onCheck();
122
+ if (bubbleInput && isFormControl) {
123
+ hasConsumerStoppedPropagationRef.current = event.cancelBubble;
124
+ // if radio has a bubble input and is a form control, stop propagation
125
+ // from the button so that we only propagate one click event (from the
126
+ // input). We propagate changes from an input so that native form
127
+ // validation works and form events reflect radio updates.
128
+ if (!hasConsumerStoppedPropagationRef.current) event.stopPropagation();
129
+ }
130
+ }),
131
+ });
132
+ }
133
+
134
+ export function Radio(props: any): any {
135
+ const {
136
+ __scopeRadio,
137
+ name,
138
+ checked,
139
+ required,
140
+ disabled,
141
+ value,
142
+ onCheck,
143
+ form,
144
+ ref: forwardedRef,
145
+ ...radioProps
146
+ } = props ?? {};
147
+
148
+ return createElement(RadioProvider, {
149
+ __scopeRadio,
150
+ checked,
151
+ disabled,
152
+ required,
153
+ onCheck,
154
+ name,
155
+ form,
156
+ value,
157
+ internal_do_not_use_render: ({ isFormControl }: RadioContextValue) => [
158
+ createElement(RadioTrigger, {
159
+ key: 'trigger',
160
+ ...radioProps,
161
+ ref: forwardedRef,
162
+ __scopeRadio,
163
+ }),
164
+ isFormControl ? createElement(RadioBubbleInput, { key: 'bubble', __scopeRadio }) : null,
165
+ ],
166
+ });
167
+ }
168
+
169
+ export function RadioIndicator(props: any): any {
170
+ const { __scopeRadio, forceMount, ...indicatorProps } = props ?? {};
171
+ const context = useRadioContext('RadioIndicator', __scopeRadio);
172
+ return createElement(Presence, {
173
+ present: forceMount || context.checked,
174
+ children: createElement(Primitive.span, {
175
+ 'data-state': getState(context.checked),
176
+ 'data-disabled': context.disabled ? '' : undefined,
177
+ ...indicatorProps,
178
+ }),
179
+ });
180
+ }
181
+
182
+ export function RadioBubbleInput(props: any): any {
183
+ const slot = S('Radio.BubbleInput');
184
+ const { __scopeRadio, ref: forwardedRef, ...inputProps } = props ?? {};
185
+ const {
186
+ control,
187
+ checked,
188
+ required,
189
+ disabled,
190
+ name,
191
+ value,
192
+ form,
193
+ bubbleInput,
194
+ setBubbleInput,
195
+ hasConsumerStoppedPropagationRef,
196
+ } = useRadioContext('RadioBubbleInput', __scopeRadio);
197
+
198
+ const composedRefs = useComposedRefs(forwardedRef, setBubbleInput, subSlot(slot, 'refs'));
199
+ const prevChecked = usePrevious(checked, subSlot(slot, 'prev'));
200
+ const controlSize = useSize(control, subSlot(slot, 'size'));
201
+
202
+ // Bubble checked change to parents (e.g form change event)
203
+ useEffect(
204
+ () => {
205
+ const input = bubbleInput;
206
+ if (!input) return;
207
+
208
+ const inputProto = window.HTMLInputElement.prototype;
209
+ const descriptor = Object.getOwnPropertyDescriptor(
210
+ inputProto,
211
+ 'checked',
212
+ ) as PropertyDescriptor;
213
+ const setChecked = descriptor.set;
214
+
215
+ const bubbles = !hasConsumerStoppedPropagationRef.current;
216
+ if (prevChecked !== checked && setChecked) {
217
+ setChecked.call(input, checked);
218
+ input.dispatchEvent(new Event('click', { bubbles }));
219
+ // octane adaptation: also fire the native `change` (see Checkbox.ts header).
220
+ input.dispatchEvent(new Event('change', { bubbles }));
221
+ }
222
+ },
223
+ [bubbleInput, prevChecked, checked, hasConsumerStoppedPropagationRef],
224
+ subSlot(slot, 'e:bubble'),
225
+ );
226
+
227
+ const defaultCheckedRef = useRef(checked, subSlot(slot, 'default'));
228
+ return createElement(Primitive.input, {
229
+ type: 'radio',
230
+ 'aria-hidden': true,
231
+ // octane: native `checked` attribute = default-checked state (see Checkbox.ts).
232
+ checked: defaultCheckedRef.current || undefined,
233
+ required,
234
+ disabled,
235
+ name,
236
+ value,
237
+ form,
238
+ ...inputProps,
239
+ tabIndex: -1,
240
+ ref: composedRefs,
241
+ style: {
242
+ ...props?.style,
243
+ ...controlSize,
244
+ position: 'absolute',
245
+ pointerEvents: 'none',
246
+ opacity: 0,
247
+ margin: 0,
248
+ // We transform because the input is absolutely positioned but we have
249
+ // rendered it **after** the button. This pulls it back to sit on top
250
+ // of the button.
251
+ transform: 'translateX(-100%)',
252
+ },
253
+ });
254
+ }
255
+
256
+ function isFunction(value: unknown): value is (...args: any[]) => any {
257
+ return typeof value === 'function';
258
+ }
259
+
260
+ function getState(checked: boolean): string {
261
+ return checked ? 'checked' : 'unchecked';
262
+ }
@@ -0,0 +1,212 @@
1
+ // Ported from @radix-ui/react-radio-group (source:
2
+ // .radix-primitives/packages/react/radio-group/src/radio-group.tsx). A `role=radiogroup`
3
+ // on a RovingFocusGroup: arrow keys move focus between items and CHECK the focused item
4
+ // (via a real `.click()` so the radio change event fires); each item is the internal
5
+ // Radio (see Radio.ts) with its hidden native bubble input inside forms.
6
+ import { createElement, useEffect, useRef } from 'octane';
7
+
8
+ import { composeEventHandlers } from './compose-event-handlers';
9
+ import { useComposedRefs } from './compose-refs';
10
+ import { createContextScope } from './context';
11
+ import { useDirection } from './direction';
12
+ import { S, subSlot } from './internal';
13
+ import { Primitive } from './Primitive';
14
+ import {
15
+ createRadioScope,
16
+ RadioBubbleInput,
17
+ RadioIndicator,
18
+ RadioProvider,
19
+ RadioTrigger,
20
+ useRadioContext,
21
+ } from './Radio';
22
+ import * as RovingFocusGroup from './RovingFocusGroup';
23
+ import { createRovingFocusGroupScope } from './RovingFocusGroup';
24
+ import { useControllableState } from './useControllableState';
25
+
26
+ const ARROW_KEYS = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'];
27
+
28
+ const RADIO_GROUP_NAME = 'RadioGroup';
29
+
30
+ const [createRadioGroupContext, createRadioGroupScope] = createContextScope(RADIO_GROUP_NAME, [
31
+ createRovingFocusGroupScope,
32
+ createRadioScope,
33
+ ]);
34
+ export { createRadioGroupScope };
35
+ const useRovingFocusGroupScope = createRovingFocusGroupScope();
36
+ const useRadioScope = createRadioScope();
37
+
38
+ interface RadioGroupContextValue {
39
+ name?: string;
40
+ required: boolean;
41
+ disabled: boolean;
42
+ value: string | null;
43
+ onValueChange(value: string): void;
44
+ }
45
+
46
+ const [RadioGroupProvider, useRadioGroupContext] =
47
+ createRadioGroupContext<RadioGroupContextValue>(RADIO_GROUP_NAME);
48
+
49
+ export function Root(props: any): any {
50
+ const slot = S('RadioGroup.Root');
51
+ const {
52
+ __scopeRadioGroup,
53
+ name,
54
+ defaultValue,
55
+ value: valueProp,
56
+ required = false,
57
+ disabled = false,
58
+ orientation,
59
+ dir,
60
+ loop = true,
61
+ onValueChange,
62
+ ref: forwardedRef,
63
+ ...groupProps
64
+ } = props ?? {};
65
+ const rovingFocusGroupScope = useRovingFocusGroupScope(__scopeRadioGroup, subSlot(slot, 'rfs'));
66
+ const direction = useDirection(dir);
67
+ const [value, setValue] = useControllableState<string | null>(
68
+ { prop: valueProp, defaultProp: defaultValue ?? null, onChange: onValueChange },
69
+ subSlot(slot, 'value'),
70
+ );
71
+
72
+ return createElement(RadioGroupProvider, {
73
+ scope: __scopeRadioGroup,
74
+ name,
75
+ required,
76
+ disabled,
77
+ value,
78
+ onValueChange: setValue,
79
+ children: createElement(RovingFocusGroup.Root, {
80
+ asChild: true,
81
+ ...rovingFocusGroupScope,
82
+ orientation,
83
+ dir: direction,
84
+ loop,
85
+ children: createElement(Primitive.div, {
86
+ role: 'radiogroup',
87
+ 'aria-required': required,
88
+ 'aria-orientation': orientation,
89
+ 'data-disabled': disabled ? '' : undefined,
90
+ dir: direction,
91
+ ...groupProps,
92
+ ref: forwardedRef,
93
+ }),
94
+ }),
95
+ });
96
+ }
97
+
98
+ function ItemProvider(props: any): any {
99
+ const slot = S('RadioGroup.ItemProvider');
100
+ const { __scopeRadioGroup, value, disabled, children, internal_do_not_use_render } = props;
101
+ const context = useRadioGroupContext('RadioGroupItemProvider', __scopeRadioGroup);
102
+ const radioScope = useRadioScope(__scopeRadioGroup, subSlot(slot, 'radio'));
103
+ const isDisabled = context.disabled || disabled;
104
+
105
+ return createElement(RadioProvider, {
106
+ ...radioScope,
107
+ checked: context.value === value,
108
+ disabled: isDisabled,
109
+ required: context.required,
110
+ name: context.name,
111
+ value,
112
+ onCheck: () => context.onValueChange(value),
113
+ internal_do_not_use_render,
114
+ children,
115
+ });
116
+ }
117
+
118
+ function ItemTrigger(props: any): any {
119
+ const slot = S('RadioGroup.ItemTrigger');
120
+ const { __scopeRadioGroup, ref: forwardedRef, ...triggerProps } = props;
121
+ const rovingFocusGroupScope = useRovingFocusGroupScope(__scopeRadioGroup, subSlot(slot, 'rfs'));
122
+ const radioScope = useRadioScope(__scopeRadioGroup, subSlot(slot, 'radio'));
123
+ const { checked, disabled } = useRadioContext('RadioGroupItemTrigger', radioScope.__scopeRadio);
124
+ const ref = useRef<HTMLElement | null>(null, subSlot(slot, 'ref'));
125
+ const composedRefs = useComposedRefs(forwardedRef, ref, subSlot(slot, 'refs'));
126
+ const isArrowKeyPressedRef = useRef(false, subSlot(slot, 'arrow'));
127
+
128
+ useEffect(
129
+ () => {
130
+ const handleKeyDown = (event: KeyboardEvent): void => {
131
+ if (ARROW_KEYS.includes(event.key)) {
132
+ isArrowKeyPressedRef.current = true;
133
+ }
134
+ };
135
+ const handleKeyUp = (): boolean => (isArrowKeyPressedRef.current = false);
136
+ document.addEventListener('keydown', handleKeyDown);
137
+ document.addEventListener('keyup', handleKeyUp);
138
+ return () => {
139
+ document.removeEventListener('keydown', handleKeyDown);
140
+ document.removeEventListener('keyup', handleKeyUp);
141
+ };
142
+ },
143
+ [],
144
+ subSlot(slot, 'e:keys'),
145
+ );
146
+
147
+ return createElement(RovingFocusGroup.Item, {
148
+ asChild: true,
149
+ ...rovingFocusGroupScope,
150
+ focusable: !disabled,
151
+ active: checked,
152
+ children: createElement(RadioTrigger, {
153
+ ...radioScope,
154
+ ...triggerProps,
155
+ ref: composedRefs,
156
+ onKeyDown: composeEventHandlers(triggerProps.onKeyDown, (event: KeyboardEvent) => {
157
+ // According to WAI ARIA, radio groups don't activate items on enter keypress
158
+ if (event.key === 'Enter') event.preventDefault();
159
+ }),
160
+ onFocus: composeEventHandlers(triggerProps.onFocus, () => {
161
+ // Our `RovingFocusGroup` will focus the radio when navigating with arrow
162
+ // keys and we need to "check" it in that case. We click it to "check" it
163
+ // (instead of updating the group value) so that the radio change event fires.
164
+ if (isArrowKeyPressedRef.current) {
165
+ (ref.current as HTMLElement | null)?.click();
166
+ }
167
+ }),
168
+ }),
169
+ });
170
+ }
171
+
172
+ export function Item(props: any): any {
173
+ const { __scopeRadioGroup, value, disabled, ref: forwardedRef, ...itemProps } = props ?? {};
174
+
175
+ return createElement(ItemProvider, {
176
+ __scopeRadioGroup,
177
+ value,
178
+ disabled,
179
+ internal_do_not_use_render: ({ isFormControl }: { isFormControl: boolean }) => [
180
+ createElement(ItemTrigger, {
181
+ key: 'trigger',
182
+ ...itemProps,
183
+ ref: forwardedRef,
184
+ __scopeRadioGroup,
185
+ }),
186
+ isFormControl ? createElement(ItemBubbleInput, { key: 'bubble', __scopeRadioGroup }) : null,
187
+ ],
188
+ });
189
+ }
190
+
191
+ function ItemBubbleInput(props: any): any {
192
+ const slot = S('RadioGroup.ItemBubbleInput');
193
+ const { __scopeRadioGroup, ...bubbleProps } = props;
194
+ const radioScope = useRadioScope(__scopeRadioGroup, subSlot(slot, 'radio'));
195
+ return createElement(RadioBubbleInput, { ...radioScope, ...bubbleProps });
196
+ }
197
+
198
+ export function Indicator(props: any): any {
199
+ const slot = S('RadioGroup.Indicator');
200
+ const { __scopeRadioGroup, ...indicatorProps } = props ?? {};
201
+ const radioScope = useRadioScope(__scopeRadioGroup, subSlot(slot, 'radio'));
202
+ return createElement(RadioIndicator, { ...radioScope, ...indicatorProps });
203
+ }
204
+
205
+ export {
206
+ Root as RadioGroup,
207
+ Item as RadioGroupItem,
208
+ ItemProvider as RadioGroupItemProvider,
209
+ ItemTrigger as RadioGroupItemTrigger,
210
+ ItemBubbleInput as RadioGroupItemBubbleInput,
211
+ Indicator as RadioGroupIndicator,
212
+ };