@react-native-reusables/cli 0.0.8 → 0.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.
Files changed (136) hide show
  1. package/dist/generated/components/primitives/accordion/accordion.tsx +216 -0
  2. package/dist/generated/components/primitives/accordion/accordion.web.tsx +295 -0
  3. package/dist/generated/components/primitives/accordion/index.ts +1 -0
  4. package/dist/generated/components/primitives/accordion/types.ts +45 -0
  5. package/dist/generated/components/primitives/alert-dialog/alert-dialog.tsx +237 -0
  6. package/dist/generated/components/primitives/alert-dialog/alert-dialog.web.tsx +256 -0
  7. package/dist/generated/components/primitives/alert-dialog/index.ts +1 -0
  8. package/dist/generated/components/primitives/alert-dialog/types.ts +48 -0
  9. package/dist/generated/components/primitives/aspect-ratio.tsx +23 -0
  10. package/dist/generated/components/primitives/avatar/ types.ts +10 -0
  11. package/dist/generated/components/primitives/avatar/index.tsx +95 -0
  12. package/dist/generated/components/primitives/checkbox/checkbox.tsx +101 -0
  13. package/dist/generated/components/primitives/checkbox/checkbox.web.tsx +114 -0
  14. package/dist/generated/components/primitives/checkbox/index.ts +1 -0
  15. package/dist/generated/components/primitives/checkbox/types.ts +11 -0
  16. package/dist/generated/components/primitives/collapsible/collapsible.tsx +119 -0
  17. package/dist/generated/components/primitives/collapsible/collapsible.web.tsx +157 -0
  18. package/dist/generated/components/primitives/collapsible/index.ts +1 -0
  19. package/dist/generated/components/primitives/collapsible/types.ts +18 -0
  20. package/dist/generated/components/primitives/context-menu/context-menu.tsx +626 -0
  21. package/dist/generated/components/primitives/context-menu/context-menu.web.tsx +504 -0
  22. package/dist/generated/components/primitives/context-menu/index.ts +1 -0
  23. package/dist/generated/components/primitives/context-menu/types.ts +82 -0
  24. package/dist/generated/components/primitives/dialog/dialog.tsx +211 -0
  25. package/dist/generated/components/primitives/dialog/dialog.web.tsx +197 -0
  26. package/dist/generated/components/primitives/dialog/index.ts +1 -0
  27. package/dist/generated/components/primitives/dialog/types.ts +60 -0
  28. package/dist/generated/components/primitives/dropdown-menu/dropdown-menu.tsx +584 -0
  29. package/dist/generated/components/primitives/dropdown-menu/dropdown-menu.web.tsx +521 -0
  30. package/dist/generated/components/primitives/dropdown-menu/index.ts +1 -0
  31. package/dist/generated/components/primitives/dropdown-menu/types.ts +71 -0
  32. package/dist/generated/components/primitives/hooks/index.ts +3 -0
  33. package/dist/generated/components/primitives/hooks/useAugmentedRef.tsx +29 -0
  34. package/dist/generated/components/primitives/hooks/useControllableState.tsx +75 -0
  35. package/dist/generated/components/primitives/hooks/useRelativePosition.tsx +227 -0
  36. package/dist/generated/components/primitives/hover-card/hover-card.tsx +271 -0
  37. package/dist/generated/components/primitives/hover-card/hover-card.web.tsx +145 -0
  38. package/dist/generated/components/primitives/hover-card/index.ts +1 -0
  39. package/dist/generated/components/primitives/hover-card/types.ts +42 -0
  40. package/dist/generated/components/primitives/label/index.ts +1 -0
  41. package/dist/generated/components/primitives/label/label.tsx +31 -0
  42. package/dist/generated/components/primitives/label/label.web.tsx +36 -0
  43. package/dist/generated/components/primitives/label/types.ts +15 -0
  44. package/dist/generated/components/primitives/menubar/index.ts +1 -0
  45. package/dist/generated/components/primitives/menubar/menubar.tsx +624 -0
  46. package/dist/generated/components/primitives/menubar/menubar.web.tsx +543 -0
  47. package/dist/generated/components/primitives/menubar/types.ts +76 -0
  48. package/dist/generated/components/primitives/navigation-menu/index.ts +1 -0
  49. package/dist/generated/components/primitives/navigation-menu/navigation-menu.tsx +315 -0
  50. package/dist/generated/components/primitives/navigation-menu/navigation-menu.web.tsx +264 -0
  51. package/dist/generated/components/primitives/navigation-menu/types.ts +49 -0
  52. package/dist/generated/components/primitives/popover/index.ts +1 -0
  53. package/dist/generated/components/primitives/popover/popover.tsx +286 -0
  54. package/dist/generated/components/primitives/popover/popover.web.tsx +179 -0
  55. package/dist/generated/components/primitives/popover/types.ts +30 -0
  56. package/dist/generated/components/primitives/portal.tsx +67 -0
  57. package/dist/generated/components/primitives/progress/index.ts +1 -0
  58. package/dist/generated/components/primitives/progress/progress.tsx +59 -0
  59. package/dist/generated/components/primitives/progress/progress.web.tsx +36 -0
  60. package/dist/generated/components/primitives/progress/types.ts +7 -0
  61. package/dist/generated/components/primitives/radio-group/index.ts +1 -0
  62. package/dist/generated/components/primitives/radio-group/radio-group.tsx +116 -0
  63. package/dist/generated/components/primitives/radio-group/radio-group.web.tsx +78 -0
  64. package/dist/generated/components/primitives/radio-group/types.ts +15 -0
  65. package/dist/generated/components/primitives/select/index.ts +1 -0
  66. package/dist/generated/components/primitives/select/select.tsx +455 -0
  67. package/dist/generated/components/primitives/select/select.web.tsx +319 -0
  68. package/dist/generated/components/primitives/select/types.ts +87 -0
  69. package/dist/generated/components/primitives/separator/ types.ts +6 -0
  70. package/dist/generated/components/primitives/separator/index.tsx +23 -0
  71. package/dist/generated/components/primitives/slider/index.ts +1 -0
  72. package/dist/generated/components/primitives/slider/slider.tsx +89 -0
  73. package/dist/generated/components/primitives/slider/slider.web.tsx +67 -0
  74. package/dist/generated/components/primitives/slider/types.ts +24 -0
  75. package/dist/generated/components/primitives/slot.tsx +187 -0
  76. package/dist/generated/components/primitives/switch/index.ts +1 -0
  77. package/dist/generated/components/primitives/switch/switch.tsx +65 -0
  78. package/dist/generated/components/primitives/switch/switch.web.tsx +67 -0
  79. package/dist/generated/components/primitives/switch/types.ts +11 -0
  80. package/dist/generated/components/primitives/table.tsx +55 -0
  81. package/dist/generated/components/primitives/tabs/index.ts +1 -0
  82. package/dist/generated/components/primitives/tabs/tabs.tsx +133 -0
  83. package/dist/generated/components/primitives/tabs/tabs.web.tsx +97 -0
  84. package/dist/generated/components/primitives/tabs/types.ts +24 -0
  85. package/dist/generated/components/primitives/toast/ types.ts +7 -0
  86. package/dist/generated/components/primitives/toast/index.tsx +128 -0
  87. package/dist/generated/components/primitives/toggle/index.ts +1 -0
  88. package/dist/generated/components/primitives/toggle/toggle.tsx +37 -0
  89. package/dist/generated/components/primitives/toggle/toggle.web.tsx +26 -0
  90. package/dist/generated/components/primitives/toggle/types.ts +7 -0
  91. package/dist/generated/components/primitives/toggle-group/index.ts +1 -0
  92. package/dist/generated/components/primitives/toggle-group/toggle-group.tsx +125 -0
  93. package/dist/generated/components/primitives/toggle-group/toggle-group.web.tsx +124 -0
  94. package/dist/generated/components/primitives/toggle-group/types.ts +37 -0
  95. package/dist/generated/components/primitives/toolbar/index.ts +1 -0
  96. package/dist/generated/components/primitives/toolbar/toolbar.tsx +125 -0
  97. package/dist/generated/components/primitives/toolbar/toolbar.web.tsx +129 -0
  98. package/dist/generated/components/primitives/toolbar/types.ts +39 -0
  99. package/dist/generated/components/primitives/tooltip/index.ts +1 -0
  100. package/dist/generated/components/primitives/tooltip/tooltip.tsx +271 -0
  101. package/dist/generated/components/primitives/tooltip/tooltip.web.tsx +167 -0
  102. package/dist/generated/components/primitives/tooltip/types.ts +44 -0
  103. package/dist/generated/components/primitives/types.ts +105 -0
  104. package/dist/generated/components/primitives/utils.ts +61 -0
  105. package/dist/generated/components/ui/accordion.tsx +127 -0
  106. package/dist/generated/components/ui/alert-dialog.tsx +167 -0
  107. package/dist/generated/components/ui/aspect-ratio.tsx +5 -0
  108. package/dist/generated/components/ui/avatar.tsx +44 -0
  109. package/dist/generated/components/ui/badge.tsx +51 -0
  110. package/dist/generated/components/ui/button.tsx +88 -0
  111. package/dist/generated/components/ui/card.tsx +67 -0
  112. package/dist/generated/components/ui/checkbox.tsx +34 -0
  113. package/dist/generated/components/ui/collapsible.tsx +9 -0
  114. package/dist/generated/components/ui/context-menu.tsx +244 -0
  115. package/dist/generated/components/ui/dialog.tsx +150 -0
  116. package/dist/generated/components/ui/dropdown-menu.tsx +244 -0
  117. package/dist/generated/components/ui/hover-card.tsx +45 -0
  118. package/dist/generated/components/ui/input.tsx +26 -0
  119. package/dist/generated/components/ui/label.tsx +28 -0
  120. package/dist/generated/components/ui/menubar.tsx +260 -0
  121. package/dist/generated/components/ui/navigation-menu.tsx +177 -0
  122. package/dist/generated/components/ui/popover.tsx +39 -0
  123. package/dist/generated/components/ui/radio-group.tsx +38 -0
  124. package/dist/generated/components/ui/select.tsx +181 -0
  125. package/dist/generated/components/ui/separator.tsx +23 -0
  126. package/dist/generated/components/ui/skeleton.tsx +39 -0
  127. package/dist/generated/components/ui/switch.tsx +97 -0
  128. package/dist/generated/components/ui/table.tsx +99 -0
  129. package/dist/generated/components/ui/tabs.tsx +65 -0
  130. package/dist/generated/components/ui/text.tsx +24 -0
  131. package/dist/generated/components/ui/textarea.tsx +28 -0
  132. package/dist/generated/components/ui/toggle-group.tsx +86 -0
  133. package/dist/generated/components/ui/toggle.tsx +85 -0
  134. package/dist/generated/components/ui/tooltip.tsx +36 -0
  135. package/dist/generated/components/ui/typography.tsx +204 -0
  136. package/package.json +8 -8
@@ -0,0 +1,626 @@
1
+ import * as React from 'react';
2
+ import {
3
+ BackHandler,
4
+ Pressable,
5
+ Text,
6
+ View,
7
+ type AccessibilityActionEvent,
8
+ type GestureResponderEvent,
9
+ type LayoutChangeEvent,
10
+ type LayoutRectangle,
11
+ } from 'react-native';
12
+ import { useRelativePosition, type LayoutPosition } from '@rnr/hooks';
13
+ import { Portal as RNPPortal } from '@rnr/portal';
14
+ import * as Slot from '@rnr/slot';
15
+ import type {
16
+ ForceMountable,
17
+ PositionedContentProps,
18
+ PressableRef,
19
+ SlottablePressableProps,
20
+ SlottableTextProps,
21
+ SlottableViewProps,
22
+ TextRef,
23
+ ViewRef,
24
+ } from '@rnr/types';
25
+ import type {
26
+ ContextMenuCheckboxItemProps,
27
+ ContextMenuItemProps,
28
+ ContextMenuOverlayProps,
29
+ ContextMenuPortalProps,
30
+ ContextMenuRadioGroupProps,
31
+ ContextMenuRadioItemProps,
32
+ ContextMenuRootProps,
33
+ ContextMenuSeparatorProps,
34
+ ContextMenuSubProps,
35
+ ContextMenuSubTriggerProps,
36
+ } from './types';
37
+
38
+ interface IRootContext extends ContextMenuRootProps {
39
+ pressPosition: LayoutPosition | null;
40
+ setPressPosition: (pressPosition: LayoutPosition | null) => void;
41
+ contentLayout: LayoutRectangle | null;
42
+ setContentLayout: (contentLayout: LayoutRectangle | null) => void;
43
+ nativeID: string;
44
+ }
45
+
46
+ const RootContext = React.createContext<IRootContext | null>(null);
47
+
48
+ const Root = React.forwardRef<ViewRef, SlottableViewProps & ContextMenuRootProps>(
49
+ ({ asChild, open, onOpenChange, relativeTo = 'longPress', ...viewProps }, ref) => {
50
+ const nativeID = React.useId();
51
+ const [pressPosition, setPressPosition] = React.useState<LayoutPosition | null>(null);
52
+ const [contentLayout, setContentLayout] = React.useState<LayoutRectangle | null>(null);
53
+
54
+ const Component = asChild ? Slot.View : View;
55
+ return (
56
+ <RootContext.Provider
57
+ value={{
58
+ open,
59
+ onOpenChange,
60
+ relativeTo,
61
+ contentLayout,
62
+ nativeID,
63
+ pressPosition,
64
+ setContentLayout,
65
+ setPressPosition,
66
+ }}
67
+ >
68
+ <Component ref={ref} {...viewProps} />
69
+ </RootContext.Provider>
70
+ );
71
+ }
72
+ );
73
+
74
+ Root.displayName = 'RootNativeContextMenu';
75
+
76
+ function useRootContext() {
77
+ const context = React.useContext(RootContext);
78
+ if (!context) {
79
+ throw new Error(
80
+ 'ContextMenu compound components cannot be rendered outside the ContextMenu component'
81
+ );
82
+ }
83
+ return context;
84
+ }
85
+
86
+ const accessibilityActions = [{ name: 'longpress' }];
87
+
88
+ const Trigger = React.forwardRef<PressableRef, SlottablePressableProps>(
89
+ (
90
+ {
91
+ asChild,
92
+ onLongPress: onLongPressProp,
93
+ disabled = false,
94
+ onAccessibilityAction: onAccessibilityActionProp,
95
+ ...props
96
+ },
97
+ ref
98
+ ) => {
99
+ const triggerRef = React.useRef<View>(null);
100
+ const { open, onOpenChange, relativeTo, setPressPosition } = useRootContext();
101
+
102
+ React.useImperativeHandle(
103
+ ref,
104
+ () => {
105
+ if (!triggerRef.current) {
106
+ return new View({});
107
+ }
108
+ return triggerRef.current;
109
+ },
110
+ [triggerRef.current]
111
+ );
112
+
113
+ function onLongPress(ev: GestureResponderEvent) {
114
+ if (disabled) return;
115
+ if (relativeTo === 'longPress') {
116
+ setPressPosition({
117
+ width: 0,
118
+ pageX: ev.nativeEvent.pageX,
119
+ pageY: ev.nativeEvent.pageY,
120
+ height: 0,
121
+ });
122
+ }
123
+ if (relativeTo === 'trigger') {
124
+ triggerRef.current?.measure((_x, _y, width, height, pageX, pageY) => {
125
+ setPressPosition({ width, pageX, pageY: pageY, height });
126
+ });
127
+ }
128
+ onOpenChange(!open);
129
+ onLongPressProp?.(ev);
130
+ }
131
+
132
+ function onAccessibilityAction(event: AccessibilityActionEvent) {
133
+ if (disabled) return;
134
+ if (event.nativeEvent.actionName === 'longpress') {
135
+ setPressPosition({
136
+ width: 0,
137
+ pageX: 0,
138
+ pageY: 0,
139
+ height: 0,
140
+ });
141
+ const newValue = !open;
142
+ onOpenChange(newValue);
143
+ }
144
+ onAccessibilityActionProp?.(event);
145
+ }
146
+
147
+ const Component = asChild ? Slot.Pressable : Pressable;
148
+ return (
149
+ <Component
150
+ ref={triggerRef}
151
+ aria-disabled={disabled ?? undefined}
152
+ role='button'
153
+ onLongPress={onLongPress}
154
+ disabled={disabled ?? undefined}
155
+ aria-expanded={open}
156
+ accessibilityActions={accessibilityActions}
157
+ onAccessibilityAction={onAccessibilityAction}
158
+ {...props}
159
+ />
160
+ );
161
+ }
162
+ );
163
+
164
+ Trigger.displayName = 'TriggerNativeContextMenu';
165
+
166
+ /**
167
+ * @warning when using a custom `<PortalHost />`, you will have to adjust the Content's sideOffset to account for nav elements like headers.
168
+ */
169
+ function Portal({ forceMount, hostName, children }: ContextMenuPortalProps) {
170
+ const value = useRootContext();
171
+
172
+ if (!value.pressPosition) {
173
+ return null;
174
+ }
175
+
176
+ if (!forceMount) {
177
+ if (!value.open) {
178
+ return null;
179
+ }
180
+ }
181
+
182
+ return (
183
+ <RNPPortal hostName={hostName} name={`${value.nativeID}_portal`}>
184
+ <RootContext.Provider value={value}>{children}</RootContext.Provider>
185
+ </RNPPortal>
186
+ );
187
+ }
188
+
189
+ const Overlay = React.forwardRef<PressableRef, SlottablePressableProps & ContextMenuOverlayProps>(
190
+ ({ asChild, forceMount, onPress: OnPressProp, closeOnPress = true, ...props }, ref) => {
191
+ const { open, onOpenChange, setContentLayout, setPressPosition } = useRootContext();
192
+
193
+ function onPress(ev: GestureResponderEvent) {
194
+ if (closeOnPress) {
195
+ setPressPosition(null);
196
+ setContentLayout(null);
197
+ onOpenChange(false);
198
+ }
199
+ OnPressProp?.(ev);
200
+ }
201
+
202
+ if (!forceMount) {
203
+ if (!open) {
204
+ return null;
205
+ }
206
+ }
207
+
208
+ const Component = asChild ? Slot.Pressable : Pressable;
209
+ return <Component ref={ref} onPress={onPress} {...props} />;
210
+ }
211
+ );
212
+
213
+ Overlay.displayName = 'OverlayNativeContextMenu';
214
+
215
+ const Content = React.forwardRef<ViewRef, SlottableViewProps & PositionedContentProps>(
216
+ (
217
+ {
218
+ asChild = false,
219
+ forceMount,
220
+ align = 'start',
221
+ side = 'bottom',
222
+ sideOffset = 0,
223
+ alignOffset = 0,
224
+ avoidCollisions = true,
225
+ onLayout: onLayoutProp,
226
+ insets,
227
+ style,
228
+ disablePositioningStyle,
229
+ ...props
230
+ },
231
+ ref
232
+ ) => {
233
+ const {
234
+ open,
235
+ onOpenChange,
236
+ contentLayout,
237
+ nativeID,
238
+ pressPosition,
239
+ setContentLayout,
240
+ setPressPosition,
241
+ } = useRootContext();
242
+
243
+ React.useEffect(() => {
244
+ const backHandler = BackHandler.addEventListener('hardwareBackPress', () => {
245
+ setPressPosition(null);
246
+ setContentLayout(null);
247
+ onOpenChange(false);
248
+ return true;
249
+ });
250
+
251
+ return () => {
252
+ setContentLayout(null);
253
+ backHandler.remove();
254
+ };
255
+ }, []);
256
+
257
+ const positionStyle = useRelativePosition({
258
+ align,
259
+ avoidCollisions,
260
+ triggerPosition: pressPosition,
261
+ contentLayout,
262
+ alignOffset,
263
+ insets,
264
+ sideOffset,
265
+ side,
266
+ disablePositioningStyle,
267
+ });
268
+
269
+ function onLayout(event: LayoutChangeEvent) {
270
+ setContentLayout(event.nativeEvent.layout);
271
+ onLayoutProp?.(event);
272
+ }
273
+
274
+ if (!forceMount) {
275
+ if (!open) {
276
+ return null;
277
+ }
278
+ }
279
+
280
+ const Component = asChild ? Slot.View : View;
281
+ return (
282
+ <Component
283
+ ref={ref}
284
+ role='menu'
285
+ nativeID={nativeID}
286
+ aria-modal={true}
287
+ style={[positionStyle, style]}
288
+ onLayout={onLayout}
289
+ onStartShouldSetResponder={onStartShouldSetResponder}
290
+ {...props}
291
+ />
292
+ );
293
+ }
294
+ );
295
+
296
+ Content.displayName = 'ContentNativeContextMenu';
297
+
298
+ const Item = React.forwardRef<PressableRef, SlottablePressableProps & ContextMenuItemProps>(
299
+ (
300
+ { asChild, textValue, onPress: onPressProp, disabled = false, closeOnPress = true, ...props },
301
+ ref
302
+ ) => {
303
+ const { onOpenChange, setContentLayout, setPressPosition } = useRootContext();
304
+
305
+ function onPress(ev: GestureResponderEvent) {
306
+ if (closeOnPress) {
307
+ setPressPosition(null);
308
+ setContentLayout(null);
309
+ onOpenChange(false);
310
+ }
311
+ onPressProp?.(ev);
312
+ }
313
+
314
+ const Component = asChild ? Slot.Pressable : Pressable;
315
+ return (
316
+ <Component
317
+ ref={ref}
318
+ role='menuitem'
319
+ onPress={onPress}
320
+ disabled={disabled}
321
+ aria-valuetext={textValue}
322
+ aria-disabled={!!disabled}
323
+ accessibilityState={{ disabled: !!disabled }}
324
+ {...props}
325
+ />
326
+ );
327
+ }
328
+ );
329
+
330
+ Item.displayName = 'ItemNativeContextMenu';
331
+
332
+ const Group = React.forwardRef<ViewRef, SlottableViewProps>(({ asChild, ...props }, ref) => {
333
+ const Component = asChild ? Slot.View : View;
334
+ return <Component ref={ref} role='group' {...props} />;
335
+ });
336
+
337
+ Group.displayName = 'GroupNativeContextMenu';
338
+
339
+ const Label = React.forwardRef<TextRef, SlottableTextProps>(({ asChild, ...props }, ref) => {
340
+ const Component = asChild ? Slot.Text : Text;
341
+ return <Component ref={ref} {...props} />;
342
+ });
343
+
344
+ Label.displayName = 'LabelNativeContextMenu';
345
+
346
+ type FormItemContext =
347
+ | { checked: boolean }
348
+ | {
349
+ value: string | undefined;
350
+ onValueChange: (value: string) => void;
351
+ };
352
+
353
+ const FormItemContext = React.createContext<FormItemContext | null>(null);
354
+
355
+ const CheckboxItem = React.forwardRef<
356
+ PressableRef,
357
+ SlottablePressableProps & ContextMenuCheckboxItemProps
358
+ >(
359
+ (
360
+ {
361
+ asChild,
362
+ checked,
363
+ onCheckedChange,
364
+ textValue,
365
+ onPress: onPressProp,
366
+ closeOnPress = true,
367
+ disabled = false,
368
+ ...props
369
+ },
370
+ ref
371
+ ) => {
372
+ const { onOpenChange, setContentLayout, setPressPosition, nativeID } = useRootContext();
373
+
374
+ function onPress(ev: GestureResponderEvent) {
375
+ onCheckedChange(!checked);
376
+ if (closeOnPress) {
377
+ setPressPosition(null);
378
+ setContentLayout(null);
379
+ onOpenChange(false);
380
+ }
381
+ onPressProp?.(ev);
382
+ }
383
+
384
+ const Component = asChild ? Slot.Pressable : Pressable;
385
+ return (
386
+ <FormItemContext.Provider value={{ checked }}>
387
+ <Component
388
+ ref={ref}
389
+ key={`checkbox-${nativeID}-${checked}`}
390
+ role='checkbox'
391
+ aria-checked={checked}
392
+ onPress={onPress}
393
+ disabled={disabled}
394
+ aria-disabled={!!disabled}
395
+ aria-valuetext={textValue}
396
+ accessibilityState={{ disabled: !!disabled }}
397
+ {...props}
398
+ />
399
+ </FormItemContext.Provider>
400
+ );
401
+ }
402
+ );
403
+
404
+ CheckboxItem.displayName = 'CheckboxItemNativeContextMenu';
405
+
406
+ function useFormItemContext() {
407
+ const context = React.useContext(FormItemContext);
408
+ if (!context) {
409
+ throw new Error(
410
+ 'CheckboxItem or RadioItem compound components cannot be rendered outside of a CheckboxItem or RadioItem component'
411
+ );
412
+ }
413
+ return context;
414
+ }
415
+
416
+ const RadioGroup = React.forwardRef<ViewRef, SlottableViewProps & ContextMenuRadioGroupProps>(
417
+ ({ asChild, value, onValueChange, ...props }, ref) => {
418
+ const Component = asChild ? Slot.View : View;
419
+ return (
420
+ <FormItemContext.Provider value={{ value, onValueChange }}>
421
+ <Component ref={ref} role='radiogroup' {...props} />
422
+ </FormItemContext.Provider>
423
+ );
424
+ }
425
+ );
426
+
427
+ RadioGroup.displayName = 'RadioGroupNativeContextMenu';
428
+
429
+ type BothFormItemContext = Exclude<FormItemContext, { checked: boolean }> & {
430
+ checked: boolean;
431
+ };
432
+
433
+ const RadioItemContext = React.createContext({} as { itemValue: string });
434
+
435
+ const RadioItem = React.forwardRef<
436
+ PressableRef,
437
+ SlottablePressableProps & ContextMenuRadioItemProps
438
+ >(
439
+ (
440
+ {
441
+ asChild,
442
+ value: itemValue,
443
+ textValue,
444
+ onPress: onPressProp,
445
+ disabled = false,
446
+ closeOnPress = true,
447
+ ...props
448
+ },
449
+ ref
450
+ ) => {
451
+ const { onOpenChange, setContentLayout, setPressPosition } = useRootContext();
452
+
453
+ const { value, onValueChange } = useFormItemContext() as BothFormItemContext;
454
+ function onPress(ev: GestureResponderEvent) {
455
+ onValueChange(itemValue);
456
+ if (closeOnPress) {
457
+ setPressPosition(null);
458
+ setContentLayout(null);
459
+ onOpenChange(false);
460
+ }
461
+ onPressProp?.(ev);
462
+ }
463
+
464
+ const Component = asChild ? Slot.Pressable : Pressable;
465
+ return (
466
+ <RadioItemContext.Provider value={{ itemValue }}>
467
+ <Component
468
+ ref={ref}
469
+ onPress={onPress}
470
+ role='radio'
471
+ aria-checked={value === itemValue}
472
+ disabled={disabled ?? false}
473
+ accessibilityState={{
474
+ disabled: disabled ?? false,
475
+ checked: value === itemValue,
476
+ }}
477
+ aria-valuetext={textValue}
478
+ {...props}
479
+ />
480
+ </RadioItemContext.Provider>
481
+ );
482
+ }
483
+ );
484
+
485
+ RadioItem.displayName = 'RadioItemNativeContextMenu';
486
+
487
+ function useItemIndicatorContext() {
488
+ return React.useContext(RadioItemContext);
489
+ }
490
+
491
+ const ItemIndicator = React.forwardRef<ViewRef, SlottableViewProps & ForceMountable>(
492
+ ({ asChild, forceMount, ...props }, ref) => {
493
+ const { itemValue } = useItemIndicatorContext();
494
+ const { checked, value } = useFormItemContext() as BothFormItemContext;
495
+
496
+ if (!forceMount) {
497
+ if (itemValue == null && !checked) {
498
+ return null;
499
+ }
500
+ if (value !== itemValue) {
501
+ return null;
502
+ }
503
+ }
504
+ const Component = asChild ? Slot.View : View;
505
+ return <Component ref={ref} role='presentation' {...props} />;
506
+ }
507
+ );
508
+
509
+ ItemIndicator.displayName = 'ItemIndicatorNativeContextMenu';
510
+
511
+ const Separator = React.forwardRef<ViewRef, SlottableViewProps & ContextMenuSeparatorProps>(
512
+ ({ asChild, decorative, ...props }, ref) => {
513
+ const Component = asChild ? Slot.View : View;
514
+ return <Component role={decorative ? 'presentation' : 'separator'} ref={ref} {...props} />;
515
+ }
516
+ );
517
+
518
+ Separator.displayName = 'SeparatorNativeContextMenu';
519
+
520
+ const SubContext = React.createContext<{
521
+ nativeID: string;
522
+ open: boolean;
523
+ onOpenChange: (value: boolean) => void;
524
+ } | null>(null);
525
+
526
+ const Sub = React.forwardRef<ViewRef, SlottableViewProps & ContextMenuSubProps>(
527
+ ({ asChild, open, onOpenChange, ...props }, ref) => {
528
+ const nativeID = React.useId();
529
+
530
+ const Component = asChild ? Slot.View : View;
531
+ return (
532
+ <SubContext.Provider
533
+ value={{
534
+ nativeID,
535
+ open,
536
+ onOpenChange,
537
+ }}
538
+ >
539
+ <Component ref={ref} {...props} />
540
+ </SubContext.Provider>
541
+ );
542
+ }
543
+ );
544
+
545
+ Sub.displayName = 'SubNativeContextMenu';
546
+
547
+ function useSubContext() {
548
+ const context = React.useContext(SubContext);
549
+ if (!context) {
550
+ throw new Error('Sub compound components cannot be rendered outside of a Sub component');
551
+ }
552
+ return context;
553
+ }
554
+
555
+ const SubTrigger = React.forwardRef<
556
+ PressableRef,
557
+ SlottablePressableProps & ContextMenuSubTriggerProps
558
+ >(({ asChild, textValue, onPress: onPressProp, disabled = false, ...props }, ref) => {
559
+ const { nativeID, open, onOpenChange } = useSubContext();
560
+
561
+ function onPress(ev: GestureResponderEvent) {
562
+ onOpenChange(!open);
563
+ onPressProp?.(ev);
564
+ }
565
+
566
+ const Component = asChild ? Slot.Pressable : Pressable;
567
+ return (
568
+ <Component
569
+ ref={ref}
570
+ key={`sub-trigger-${nativeID}-${open}`}
571
+ aria-valuetext={textValue}
572
+ role='menuitem'
573
+ aria-expanded={open}
574
+ accessibilityState={{ expanded: open, disabled: !!disabled }}
575
+ nativeID={nativeID}
576
+ onPress={onPress}
577
+ disabled={disabled}
578
+ aria-disabled={!!disabled}
579
+ {...props}
580
+ />
581
+ );
582
+ });
583
+
584
+ SubTrigger.displayName = 'SubTriggerNativeContextMenu';
585
+
586
+ const SubContent = React.forwardRef<PressableRef, SlottablePressableProps & ForceMountable>(
587
+ ({ asChild = false, forceMount, ...props }, ref) => {
588
+ const { open, nativeID } = useSubContext();
589
+
590
+ if (!forceMount) {
591
+ if (!open) {
592
+ return null;
593
+ }
594
+ }
595
+
596
+ const Component = asChild ? Slot.Pressable : Pressable;
597
+ return <Component ref={ref} role='group' aria-labelledby={nativeID} {...props} />;
598
+ }
599
+ );
600
+
601
+ Content.displayName = 'ContentNativeContextMenu';
602
+
603
+ export {
604
+ CheckboxItem,
605
+ Content,
606
+ Group,
607
+ Item,
608
+ ItemIndicator,
609
+ Label,
610
+ Overlay,
611
+ Portal,
612
+ RadioGroup,
613
+ RadioItem,
614
+ Root,
615
+ Separator,
616
+ Sub,
617
+ SubContent,
618
+ SubTrigger,
619
+ Trigger,
620
+ useRootContext,
621
+ useSubContext,
622
+ };
623
+
624
+ function onStartShouldSetResponder() {
625
+ return true;
626
+ }