@react-native-reusables/cli 0.0.9 → 0.0.11

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